diff --git a/application/dependency/dependency.go b/application/dependency/dependency.go index a4bab971..ebe5e478 100644 --- a/application/dependency/dependency.go +++ b/application/dependency/dependency.go @@ -88,6 +88,8 @@ type Dep interface { NodeClient() inventory.NodeClient // DavAccountClient Get a singleton inventory.DavAccountClient instance for access DB dav account store. DavAccountClient() inventory.DavAccountClient + // InvitationCodeClient Get a singleton inventory.InvitationCodeClient instance for access DB invitation code store. + InvitationCodeClient() inventory.InvitationCodeClient // DirectLinkClient Get a singleton inventory.DirectLinkClient instance for access DB direct link store. DirectLinkClient() inventory.DirectLinkClient // OAuthClientClient Get a singleton inventory.OAuthClientClient instance for access DB OAuth client store. @@ -167,6 +169,7 @@ type dependency struct { taskClient inventory.TaskClient nodeClient inventory.NodeClient davAccountClient inventory.DavAccountClient + invitationCodeClient inventory.InvitationCodeClient directLinkClient inventory.DirectLinkClient fsEventClient inventory.FsEventClient oAuthClient inventory.OAuthClientClient @@ -837,6 +840,15 @@ func (d *dependency) DavAccountClient() inventory.DavAccountClient { return d.davAccountClient } +func (d *dependency) InvitationCodeClient() inventory.InvitationCodeClient { + if d.invitationCodeClient != nil { + return d.invitationCodeClient + } + + d.invitationCodeClient = inventory.NewInvitationCodeClient(d.DBClient(), d.ConfigProvider().Database().Type, d.HashIDEncoder()) + return d.invitationCodeClient +} + func (d *dependency) DirectLinkClient() inventory.DirectLinkClient { if d.directLinkClient != nil { return d.directLinkClient diff --git a/ent/client.go b/ent/client.go index ab9d1c4b..58543f91 100644 --- a/ent/client.go +++ b/ent/client.go @@ -21,6 +21,7 @@ import ( "github.com/cloudreve/Cloudreve/v4/ent/file" "github.com/cloudreve/Cloudreve/v4/ent/fsevent" "github.com/cloudreve/Cloudreve/v4/ent/group" + "github.com/cloudreve/Cloudreve/v4/ent/invitationcode" "github.com/cloudreve/Cloudreve/v4/ent/metadata" "github.com/cloudreve/Cloudreve/v4/ent/node" "github.com/cloudreve/Cloudreve/v4/ent/oauthclient" @@ -52,6 +53,8 @@ type Client struct { FsEvent *FsEventClient // Group is the client for interacting with the Group builders. Group *GroupClient + // InvitationCode is the client for interacting with the InvitationCode builders. + InvitationCode *InvitationCodeClient // Metadata is the client for interacting with the Metadata builders. Metadata *MetadataClient // Node is the client for interacting with the Node builders. @@ -89,6 +92,7 @@ func (c *Client) init() { c.File = NewFileClient(c.config) c.FsEvent = NewFsEventClient(c.config) c.Group = NewGroupClient(c.config) + c.InvitationCode = NewInvitationCodeClient(c.config) c.Metadata = NewMetadataClient(c.config) c.Node = NewNodeClient(c.config) c.OAuthClient = NewOAuthClientClient(c.config) @@ -189,24 +193,25 @@ func (c *Client) Tx(ctx context.Context) (*Tx, error) { cfg := c.config cfg.driver = tx return &Tx{ - ctx: ctx, - config: cfg, - DavAccount: NewDavAccountClient(cfg), - DirectLink: NewDirectLinkClient(cfg), - Entity: NewEntityClient(cfg), - File: NewFileClient(cfg), - FsEvent: NewFsEventClient(cfg), - Group: NewGroupClient(cfg), - Metadata: NewMetadataClient(cfg), - Node: NewNodeClient(cfg), - OAuthClient: NewOAuthClientClient(cfg), - OAuthGrant: NewOAuthGrantClient(cfg), - Passkey: NewPasskeyClient(cfg), - Setting: NewSettingClient(cfg), - Share: NewShareClient(cfg), - StoragePolicy: NewStoragePolicyClient(cfg), - Task: NewTaskClient(cfg), - User: NewUserClient(cfg), + ctx: ctx, + config: cfg, + DavAccount: NewDavAccountClient(cfg), + DirectLink: NewDirectLinkClient(cfg), + Entity: NewEntityClient(cfg), + File: NewFileClient(cfg), + FsEvent: NewFsEventClient(cfg), + Group: NewGroupClient(cfg), + InvitationCode: NewInvitationCodeClient(cfg), + Metadata: NewMetadataClient(cfg), + Node: NewNodeClient(cfg), + OAuthClient: NewOAuthClientClient(cfg), + OAuthGrant: NewOAuthGrantClient(cfg), + Passkey: NewPasskeyClient(cfg), + Setting: NewSettingClient(cfg), + Share: NewShareClient(cfg), + StoragePolicy: NewStoragePolicyClient(cfg), + Task: NewTaskClient(cfg), + User: NewUserClient(cfg), }, nil } @@ -224,24 +229,25 @@ func (c *Client) BeginTx(ctx context.Context, opts *sql.TxOptions) (*Tx, error) cfg := c.config cfg.driver = &txDriver{tx: tx, drv: c.driver} return &Tx{ - ctx: ctx, - config: cfg, - DavAccount: NewDavAccountClient(cfg), - DirectLink: NewDirectLinkClient(cfg), - Entity: NewEntityClient(cfg), - File: NewFileClient(cfg), - FsEvent: NewFsEventClient(cfg), - Group: NewGroupClient(cfg), - Metadata: NewMetadataClient(cfg), - Node: NewNodeClient(cfg), - OAuthClient: NewOAuthClientClient(cfg), - OAuthGrant: NewOAuthGrantClient(cfg), - Passkey: NewPasskeyClient(cfg), - Setting: NewSettingClient(cfg), - Share: NewShareClient(cfg), - StoragePolicy: NewStoragePolicyClient(cfg), - Task: NewTaskClient(cfg), - User: NewUserClient(cfg), + ctx: ctx, + config: cfg, + DavAccount: NewDavAccountClient(cfg), + DirectLink: NewDirectLinkClient(cfg), + Entity: NewEntityClient(cfg), + File: NewFileClient(cfg), + FsEvent: NewFsEventClient(cfg), + Group: NewGroupClient(cfg), + InvitationCode: NewInvitationCodeClient(cfg), + Metadata: NewMetadataClient(cfg), + Node: NewNodeClient(cfg), + OAuthClient: NewOAuthClientClient(cfg), + OAuthGrant: NewOAuthGrantClient(cfg), + Passkey: NewPasskeyClient(cfg), + Setting: NewSettingClient(cfg), + Share: NewShareClient(cfg), + StoragePolicy: NewStoragePolicyClient(cfg), + Task: NewTaskClient(cfg), + User: NewUserClient(cfg), }, nil } @@ -271,9 +277,9 @@ func (c *Client) Close() error { // In order to add hooks to a specific client, call: `client.Node.Use(...)`. func (c *Client) Use(hooks ...Hook) { for _, n := range []interface{ Use(...Hook) }{ - c.DavAccount, c.DirectLink, c.Entity, c.File, c.FsEvent, c.Group, c.Metadata, - c.Node, c.OAuthClient, c.OAuthGrant, c.Passkey, c.Setting, c.Share, - c.StoragePolicy, c.Task, c.User, + c.DavAccount, c.DirectLink, c.Entity, c.File, c.FsEvent, c.Group, + c.InvitationCode, c.Metadata, c.Node, c.OAuthClient, c.OAuthGrant, c.Passkey, + c.Setting, c.Share, c.StoragePolicy, c.Task, c.User, } { n.Use(hooks...) } @@ -283,9 +289,9 @@ func (c *Client) Use(hooks ...Hook) { // In order to add interceptors to a specific client, call: `client.Node.Intercept(...)`. func (c *Client) Intercept(interceptors ...Interceptor) { for _, n := range []interface{ Intercept(...Interceptor) }{ - c.DavAccount, c.DirectLink, c.Entity, c.File, c.FsEvent, c.Group, c.Metadata, - c.Node, c.OAuthClient, c.OAuthGrant, c.Passkey, c.Setting, c.Share, - c.StoragePolicy, c.Task, c.User, + c.DavAccount, c.DirectLink, c.Entity, c.File, c.FsEvent, c.Group, + c.InvitationCode, c.Metadata, c.Node, c.OAuthClient, c.OAuthGrant, c.Passkey, + c.Setting, c.Share, c.StoragePolicy, c.Task, c.User, } { n.Intercept(interceptors...) } @@ -306,6 +312,8 @@ func (c *Client) Mutate(ctx context.Context, m Mutation) (Value, error) { return c.FsEvent.mutate(ctx, m) case *GroupMutation: return c.Group.mutate(ctx, m) + case *InvitationCodeMutation: + return c.InvitationCode.mutate(ctx, m) case *MetadataMutation: return c.Metadata.mutate(ctx, m) case *NodeMutation: @@ -1396,6 +1404,141 @@ func (c *GroupClient) mutate(ctx context.Context, m *GroupMutation) (Value, erro } } +// InvitationCodeClient is a client for the InvitationCode schema. +type InvitationCodeClient struct { + config +} + +// NewInvitationCodeClient returns a client for the InvitationCode from the given config. +func NewInvitationCodeClient(c config) *InvitationCodeClient { + return &InvitationCodeClient{config: c} +} + +// Use adds a list of mutation hooks to the hooks stack. +// A call to `Use(f, g, h)` equals to `invitationcode.Hooks(f(g(h())))`. +func (c *InvitationCodeClient) Use(hooks ...Hook) { + c.hooks.InvitationCode = append(c.hooks.InvitationCode, hooks...) +} + +// Intercept adds a list of query interceptors to the interceptors stack. +// A call to `Intercept(f, g, h)` equals to `invitationcode.Intercept(f(g(h())))`. +func (c *InvitationCodeClient) Intercept(interceptors ...Interceptor) { + c.inters.InvitationCode = append(c.inters.InvitationCode, interceptors...) +} + +// Create returns a builder for creating a InvitationCode entity. +func (c *InvitationCodeClient) Create() *InvitationCodeCreate { + mutation := newInvitationCodeMutation(c.config, OpCreate) + return &InvitationCodeCreate{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// CreateBulk returns a builder for creating a bulk of InvitationCode entities. +func (c *InvitationCodeClient) CreateBulk(builders ...*InvitationCodeCreate) *InvitationCodeCreateBulk { + return &InvitationCodeCreateBulk{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 *InvitationCodeClient) MapCreateBulk(slice any, setFunc func(*InvitationCodeCreate, int)) *InvitationCodeCreateBulk { + rv := reflect.ValueOf(slice) + if rv.Kind() != reflect.Slice { + return &InvitationCodeCreateBulk{err: fmt.Errorf("calling to InvitationCodeClient.MapCreateBulk with wrong type %T, need slice", slice)} + } + builders := make([]*InvitationCodeCreate, rv.Len()) + for i := 0; i < rv.Len(); i++ { + builders[i] = c.Create() + setFunc(builders[i], i) + } + return &InvitationCodeCreateBulk{config: c.config, builders: builders} +} + +// Update returns an update builder for InvitationCode. +func (c *InvitationCodeClient) Update() *InvitationCodeUpdate { + mutation := newInvitationCodeMutation(c.config, OpUpdate) + return &InvitationCodeUpdate{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// UpdateOne returns an update builder for the given entity. +func (c *InvitationCodeClient) UpdateOne(ic *InvitationCode) *InvitationCodeUpdateOne { + mutation := newInvitationCodeMutation(c.config, OpUpdateOne, withInvitationCode(ic)) + return &InvitationCodeUpdateOne{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// UpdateOneID returns an update builder for the given id. +func (c *InvitationCodeClient) UpdateOneID(id int) *InvitationCodeUpdateOne { + mutation := newInvitationCodeMutation(c.config, OpUpdateOne, withInvitationCodeID(id)) + return &InvitationCodeUpdateOne{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// Delete returns a delete builder for InvitationCode. +func (c *InvitationCodeClient) Delete() *InvitationCodeDelete { + mutation := newInvitationCodeMutation(c.config, OpDelete) + return &InvitationCodeDelete{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// DeleteOne returns a builder for deleting the given entity. +func (c *InvitationCodeClient) DeleteOne(ic *InvitationCode) *InvitationCodeDeleteOne { + return c.DeleteOneID(ic.ID) +} + +// DeleteOneID returns a builder for deleting the given entity by its id. +func (c *InvitationCodeClient) DeleteOneID(id int) *InvitationCodeDeleteOne { + builder := c.Delete().Where(invitationcode.ID(id)) + builder.mutation.id = &id + builder.mutation.op = OpDeleteOne + return &InvitationCodeDeleteOne{builder} +} + +// Query returns a query builder for InvitationCode. +func (c *InvitationCodeClient) Query() *InvitationCodeQuery { + return &InvitationCodeQuery{ + config: c.config, + ctx: &QueryContext{Type: TypeInvitationCode}, + inters: c.Interceptors(), + } +} + +// Get returns a InvitationCode entity by its id. +func (c *InvitationCodeClient) Get(ctx context.Context, id int) (*InvitationCode, error) { + return c.Query().Where(invitationcode.ID(id)).Only(ctx) +} + +// GetX is like Get, but panics if an error occurs. +func (c *InvitationCodeClient) GetX(ctx context.Context, id int) *InvitationCode { + obj, err := c.Get(ctx, id) + if err != nil { + panic(err) + } + return obj +} + +// Hooks returns the client hooks. +func (c *InvitationCodeClient) Hooks() []Hook { + hooks := c.hooks.InvitationCode + return append(hooks[:len(hooks):len(hooks)], invitationcode.Hooks[:]...) +} + +// Interceptors returns the client interceptors. +func (c *InvitationCodeClient) Interceptors() []Interceptor { + inters := c.inters.InvitationCode + return append(inters[:len(inters):len(inters)], invitationcode.Interceptors[:]...) +} + +func (c *InvitationCodeClient) mutate(ctx context.Context, m *InvitationCodeMutation) (Value, error) { + switch m.Op() { + case OpCreate: + return (&InvitationCodeCreate{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx) + case OpUpdate: + return (&InvitationCodeUpdate{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx) + case OpUpdateOne: + return (&InvitationCodeUpdateOne{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx) + case OpDelete, OpDeleteOne: + return (&InvitationCodeDelete{config: c.config, hooks: c.Hooks(), mutation: m}).Exec(ctx) + default: + return nil, fmt.Errorf("ent: unknown InvitationCode mutation op: %q", m.Op()) + } +} + // MetadataClient is a client for the Metadata schema. type MetadataClient struct { config @@ -3101,13 +3244,13 @@ func (c *UserClient) mutate(ctx context.Context, m *UserMutation) (Value, error) // hooks and interceptors per client, for fast access. type ( hooks struct { - DavAccount, DirectLink, Entity, File, FsEvent, Group, Metadata, Node, - OAuthClient, OAuthGrant, Passkey, Setting, Share, StoragePolicy, Task, + DavAccount, DirectLink, Entity, File, FsEvent, Group, InvitationCode, Metadata, + Node, OAuthClient, OAuthGrant, Passkey, Setting, Share, StoragePolicy, Task, User []ent.Hook } inters struct { - DavAccount, DirectLink, Entity, File, FsEvent, Group, Metadata, Node, - OAuthClient, OAuthGrant, Passkey, Setting, Share, StoragePolicy, Task, + DavAccount, DirectLink, Entity, File, FsEvent, Group, InvitationCode, Metadata, + Node, OAuthClient, OAuthGrant, Passkey, Setting, Share, StoragePolicy, Task, User []ent.Interceptor } ) diff --git a/ent/ent.go b/ent/ent.go index 3d92b48c..80840097 100644 --- a/ent/ent.go +++ b/ent/ent.go @@ -18,6 +18,7 @@ import ( "github.com/cloudreve/Cloudreve/v4/ent/file" "github.com/cloudreve/Cloudreve/v4/ent/fsevent" "github.com/cloudreve/Cloudreve/v4/ent/group" + "github.com/cloudreve/Cloudreve/v4/ent/invitationcode" "github.com/cloudreve/Cloudreve/v4/ent/metadata" "github.com/cloudreve/Cloudreve/v4/ent/node" "github.com/cloudreve/Cloudreve/v4/ent/oauthclient" @@ -88,22 +89,23 @@ var ( func checkColumn(table, column string) error { initCheck.Do(func() { columnCheck = sql.NewColumnCheck(map[string]func(string) bool{ - davaccount.Table: davaccount.ValidColumn, - directlink.Table: directlink.ValidColumn, - entity.Table: entity.ValidColumn, - file.Table: file.ValidColumn, - fsevent.Table: fsevent.ValidColumn, - group.Table: group.ValidColumn, - metadata.Table: metadata.ValidColumn, - node.Table: node.ValidColumn, - oauthclient.Table: oauthclient.ValidColumn, - oauthgrant.Table: oauthgrant.ValidColumn, - passkey.Table: passkey.ValidColumn, - setting.Table: setting.ValidColumn, - share.Table: share.ValidColumn, - storagepolicy.Table: storagepolicy.ValidColumn, - task.Table: task.ValidColumn, - user.Table: user.ValidColumn, + davaccount.Table: davaccount.ValidColumn, + directlink.Table: directlink.ValidColumn, + entity.Table: entity.ValidColumn, + file.Table: file.ValidColumn, + fsevent.Table: fsevent.ValidColumn, + group.Table: group.ValidColumn, + invitationcode.Table: invitationcode.ValidColumn, + metadata.Table: metadata.ValidColumn, + node.Table: node.ValidColumn, + oauthclient.Table: oauthclient.ValidColumn, + oauthgrant.Table: oauthgrant.ValidColumn, + passkey.Table: passkey.ValidColumn, + setting.Table: setting.ValidColumn, + share.Table: share.ValidColumn, + storagepolicy.Table: storagepolicy.ValidColumn, + task.Table: task.ValidColumn, + user.Table: user.ValidColumn, }) }) return columnCheck(table, column) diff --git a/ent/hook/hook.go b/ent/hook/hook.go index 2bf7e995..8e60de03 100644 --- a/ent/hook/hook.go +++ b/ent/hook/hook.go @@ -81,6 +81,18 @@ func (f GroupFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, error return nil, fmt.Errorf("unexpected mutation type %T. expect *ent.GroupMutation", m) } +// The InvitationCodeFunc type is an adapter to allow the use of ordinary +// function as InvitationCode mutator. +type InvitationCodeFunc func(context.Context, *ent.InvitationCodeMutation) (ent.Value, error) + +// Mutate calls f(ctx, m). +func (f InvitationCodeFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, error) { + if mv, ok := m.(*ent.InvitationCodeMutation); ok { + return f(ctx, mv) + } + return nil, fmt.Errorf("unexpected mutation type %T. expect *ent.InvitationCodeMutation", m) +} + // The MetadataFunc type is an adapter to allow the use of ordinary // function as Metadata mutator. type MetadataFunc func(context.Context, *ent.MetadataMutation) (ent.Value, error) diff --git a/ent/intercept/intercept.go b/ent/intercept/intercept.go index b2efc35b..6c1d9c86 100644 --- a/ent/intercept/intercept.go +++ b/ent/intercept/intercept.go @@ -14,6 +14,7 @@ import ( "github.com/cloudreve/Cloudreve/v4/ent/file" "github.com/cloudreve/Cloudreve/v4/ent/fsevent" "github.com/cloudreve/Cloudreve/v4/ent/group" + "github.com/cloudreve/Cloudreve/v4/ent/invitationcode" "github.com/cloudreve/Cloudreve/v4/ent/metadata" "github.com/cloudreve/Cloudreve/v4/ent/node" "github.com/cloudreve/Cloudreve/v4/ent/oauthclient" @@ -245,6 +246,33 @@ func (f TraverseGroup) Traverse(ctx context.Context, q ent.Query) error { return fmt.Errorf("unexpected query type %T. expect *ent.GroupQuery", q) } +// The InvitationCodeFunc type is an adapter to allow the use of ordinary function as a Querier. +type InvitationCodeFunc func(context.Context, *ent.InvitationCodeQuery) (ent.Value, error) + +// Query calls f(ctx, q). +func (f InvitationCodeFunc) Query(ctx context.Context, q ent.Query) (ent.Value, error) { + if q, ok := q.(*ent.InvitationCodeQuery); ok { + return f(ctx, q) + } + return nil, fmt.Errorf("unexpected query type %T. expect *ent.InvitationCodeQuery", q) +} + +// The TraverseInvitationCode type is an adapter to allow the use of ordinary function as Traverser. +type TraverseInvitationCode func(context.Context, *ent.InvitationCodeQuery) error + +// Intercept is a dummy implementation of Intercept that returns the next Querier in the pipeline. +func (f TraverseInvitationCode) Intercept(next ent.Querier) ent.Querier { + return next +} + +// Traverse calls f(ctx, q). +func (f TraverseInvitationCode) Traverse(ctx context.Context, q ent.Query) error { + if q, ok := q.(*ent.InvitationCodeQuery); ok { + return f(ctx, q) + } + return fmt.Errorf("unexpected query type %T. expect *ent.InvitationCodeQuery", q) +} + // The MetadataFunc type is an adapter to allow the use of ordinary function as a Querier. type MetadataFunc func(context.Context, *ent.MetadataQuery) (ent.Value, error) @@ -530,6 +558,8 @@ func NewQuery(q ent.Query) (Query, error) { return &query[*ent.FsEventQuery, predicate.FsEvent, fsevent.OrderOption]{typ: ent.TypeFsEvent, tq: q}, nil case *ent.GroupQuery: return &query[*ent.GroupQuery, predicate.Group, group.OrderOption]{typ: ent.TypeGroup, tq: q}, nil + case *ent.InvitationCodeQuery: + return &query[*ent.InvitationCodeQuery, predicate.InvitationCode, invitationcode.OrderOption]{typ: ent.TypeInvitationCode, tq: q}, nil case *ent.MetadataQuery: return &query[*ent.MetadataQuery, predicate.Metadata, metadata.OrderOption]{typ: ent.TypeMetadata, tq: q}, nil case *ent.NodeQuery: diff --git a/ent/internal/schema.go b/ent/internal/schema.go index 6d3f7940..e4a28cef 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\":\"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\":\"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\":\"Group\",\"config\":{\"Table\":\"\"},\"edges\":[{\"name\":\"users\",\"type\":\"User\"},{\"name\":\"storage_policies\",\"type\":\"StoragePolicy\",\"field\":\"storage_policy_id\",\"ref_name\":\"groups\",\"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\":\"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\":\"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\":\"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\"}],\"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\":\"two_factor_secret\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":8,\"MixedIn\":false,\"MixinIndex\":0},\"sensitive\":true},{\"name\":\"avatar\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":9,\"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\":10,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"group_users\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":11,\"MixedIn\":false,\"MixinIndex\":0}}],\"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\":\"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\":\"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\":\"Group\",\"config\":{\"Table\":\"\"},\"edges\":[{\"name\":\"users\",\"type\":\"User\"},{\"name\":\"storage_policies\",\"type\":\"StoragePolicy\",\"field\":\"storage_policy_id\",\"ref_name\":\"groups\",\"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\":\"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\":\"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\"}],\"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\":\"two_factor_secret\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":8,\"MixedIn\":false,\"MixinIndex\":0},\"sensitive\":true},{\"name\":\"avatar\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":9,\"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\":10,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"group_users\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":11,\"MixedIn\":false,\"MixinIndex\":0}}],\"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/invitationcode.go b/ent/invitationcode.go new file mode 100644 index 00000000..cc46d763 --- /dev/null +++ b/ent/invitationcode.go @@ -0,0 +1,189 @@ +// 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/invitationcode" +) + +// InvitationCode is the model entity for the InvitationCode schema. +type InvitationCode 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"` + // Code holds the value of the "code" field. + Code string `json:"code,omitempty"` + // GroupID holds the value of the "group_id" field. + GroupID int `json:"group_id,omitempty"` + // MaxUses holds the value of the "max_uses" field. + MaxUses int `json:"max_uses,omitempty"` + // UsedCount holds the value of the "used_count" field. + UsedCount int `json:"used_count,omitempty"` + // ExpiresAt holds the value of the "expires_at" field. + ExpiresAt *time.Time `json:"expires_at,omitempty"` + selectValues sql.SelectValues +} + +// scanValues returns the types for scanning values from sql.Rows. +func (*InvitationCode) scanValues(columns []string) ([]any, error) { + values := make([]any, len(columns)) + for i := range columns { + switch columns[i] { + case invitationcode.FieldID, invitationcode.FieldGroupID, invitationcode.FieldMaxUses, invitationcode.FieldUsedCount: + values[i] = new(sql.NullInt64) + case invitationcode.FieldCode: + values[i] = new(sql.NullString) + case invitationcode.FieldCreatedAt, invitationcode.FieldUpdatedAt, invitationcode.FieldDeletedAt, invitationcode.FieldExpiresAt: + 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 InvitationCode fields. +func (ic *InvitationCode) 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 invitationcode.FieldID: + value, ok := values[i].(*sql.NullInt64) + if !ok { + return fmt.Errorf("unexpected type %T for field id", value) + } + ic.ID = int(value.Int64) + case invitationcode.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 { + ic.CreatedAt = value.Time + } + case invitationcode.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 { + ic.UpdatedAt = value.Time + } + case invitationcode.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 { + ic.DeletedAt = new(time.Time) + *ic.DeletedAt = value.Time + } + case invitationcode.FieldCode: + if value, ok := values[i].(*sql.NullString); !ok { + return fmt.Errorf("unexpected type %T for field code", values[i]) + } else if value.Valid { + ic.Code = value.String + } + case invitationcode.FieldGroupID: + if value, ok := values[i].(*sql.NullInt64); !ok { + return fmt.Errorf("unexpected type %T for field group_id", values[i]) + } else if value.Valid { + ic.GroupID = int(value.Int64) + } + case invitationcode.FieldMaxUses: + if value, ok := values[i].(*sql.NullInt64); !ok { + return fmt.Errorf("unexpected type %T for field max_uses", values[i]) + } else if value.Valid { + ic.MaxUses = int(value.Int64) + } + case invitationcode.FieldUsedCount: + if value, ok := values[i].(*sql.NullInt64); !ok { + return fmt.Errorf("unexpected type %T for field used_count", values[i]) + } else if value.Valid { + ic.UsedCount = int(value.Int64) + } + case invitationcode.FieldExpiresAt: + if value, ok := values[i].(*sql.NullTime); !ok { + return fmt.Errorf("unexpected type %T for field expires_at", values[i]) + } else if value.Valid { + ic.ExpiresAt = new(time.Time) + *ic.ExpiresAt = value.Time + } + default: + ic.selectValues.Set(columns[i], values[i]) + } + } + return nil +} + +// Value returns the ent.Value that was dynamically selected and assigned to the InvitationCode. +// This includes values selected through modifiers, order, etc. +func (ic *InvitationCode) Value(name string) (ent.Value, error) { + return ic.selectValues.Get(name) +} + +// Update returns a builder for updating this InvitationCode. +// Note that you need to call InvitationCode.Unwrap() before calling this method if this InvitationCode +// was returned from a transaction, and the transaction was committed or rolled back. +func (ic *InvitationCode) Update() *InvitationCodeUpdateOne { + return NewInvitationCodeClient(ic.config).UpdateOne(ic) +} + +// Unwrap unwraps the InvitationCode 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 (ic *InvitationCode) Unwrap() *InvitationCode { + _tx, ok := ic.config.driver.(*txDriver) + if !ok { + panic("ent: InvitationCode is not a transactional entity") + } + ic.config.driver = _tx.drv + return ic +} + +// String implements the fmt.Stringer. +func (ic *InvitationCode) String() string { + var builder strings.Builder + builder.WriteString("InvitationCode(") + builder.WriteString(fmt.Sprintf("id=%v, ", ic.ID)) + builder.WriteString("created_at=") + builder.WriteString(ic.CreatedAt.Format(time.ANSIC)) + builder.WriteString(", ") + builder.WriteString("updated_at=") + builder.WriteString(ic.UpdatedAt.Format(time.ANSIC)) + builder.WriteString(", ") + if v := ic.DeletedAt; v != nil { + builder.WriteString("deleted_at=") + builder.WriteString(v.Format(time.ANSIC)) + } + builder.WriteString(", ") + builder.WriteString("code=") + builder.WriteString(ic.Code) + builder.WriteString(", ") + builder.WriteString("group_id=") + builder.WriteString(fmt.Sprintf("%v", ic.GroupID)) + builder.WriteString(", ") + builder.WriteString("max_uses=") + builder.WriteString(fmt.Sprintf("%v", ic.MaxUses)) + builder.WriteString(", ") + builder.WriteString("used_count=") + builder.WriteString(fmt.Sprintf("%v", ic.UsedCount)) + builder.WriteString(", ") + if v := ic.ExpiresAt; v != nil { + builder.WriteString("expires_at=") + builder.WriteString(v.Format(time.ANSIC)) + } + builder.WriteByte(')') + return builder.String() +} + +// InvitationCodes is a parsable slice of InvitationCode. +type InvitationCodes []*InvitationCode diff --git a/ent/invitationcode/invitationcode.go b/ent/invitationcode/invitationcode.go new file mode 100644 index 00000000..65b84f07 --- /dev/null +++ b/ent/invitationcode/invitationcode.go @@ -0,0 +1,130 @@ +// Code generated by ent, DO NOT EDIT. + +package invitationcode + +import ( + "time" + + "entgo.io/ent" + "entgo.io/ent/dialect/sql" +) + +const ( + // Label holds the string label denoting the invitationcode type in the database. + Label = "invitation_code" + // 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" + // FieldCode holds the string denoting the code field in the database. + FieldCode = "code" + // FieldGroupID holds the string denoting the group_id field in the database. + FieldGroupID = "group_id" + // FieldMaxUses holds the string denoting the max_uses field in the database. + FieldMaxUses = "max_uses" + // FieldUsedCount holds the string denoting the used_count field in the database. + FieldUsedCount = "used_count" + // FieldExpiresAt holds the string denoting the expires_at field in the database. + FieldExpiresAt = "expires_at" + // Table holds the table name of the invitationcode in the database. + Table = "invitation_codes" +) + +// Columns holds all SQL columns for invitationcode fields. +var Columns = []string{ + FieldID, + FieldCreatedAt, + FieldUpdatedAt, + FieldDeletedAt, + FieldCode, + FieldGroupID, + FieldMaxUses, + FieldUsedCount, + FieldExpiresAt, +} + +// 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 + // CodeValidator is a validator for the "code" field. It is called by the builders before save. + CodeValidator func(string) error + // DefaultGroupID holds the default value on creation for the "group_id" field. + DefaultGroupID int + // DefaultMaxUses holds the default value on creation for the "max_uses" field. + DefaultMaxUses int + // DefaultUsedCount holds the default value on creation for the "used_count" field. + DefaultUsedCount int +) + +// OrderOption defines the ordering options for the InvitationCode 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() +} + +// ByCode orders the results by the code field. +func ByCode(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldCode, opts...).ToFunc() +} + +// ByGroupID orders the results by the group_id field. +func ByGroupID(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldGroupID, opts...).ToFunc() +} + +// ByMaxUses orders the results by the max_uses field. +func ByMaxUses(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldMaxUses, opts...).ToFunc() +} + +// ByUsedCount orders the results by the used_count field. +func ByUsedCount(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldUsedCount, opts...).ToFunc() +} + +// ByExpiresAt orders the results by the expires_at field. +func ByExpiresAt(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldExpiresAt, opts...).ToFunc() +} diff --git a/ent/invitationcode/where.go b/ent/invitationcode/where.go new file mode 100644 index 00000000..2a0d2444 --- /dev/null +++ b/ent/invitationcode/where.go @@ -0,0 +1,475 @@ +// Code generated by ent, DO NOT EDIT. + +package invitationcode + +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.InvitationCode { + return predicate.InvitationCode(sql.FieldEQ(FieldID, id)) +} + +// IDEQ applies the EQ predicate on the ID field. +func IDEQ(id int) predicate.InvitationCode { + return predicate.InvitationCode(sql.FieldEQ(FieldID, id)) +} + +// IDNEQ applies the NEQ predicate on the ID field. +func IDNEQ(id int) predicate.InvitationCode { + return predicate.InvitationCode(sql.FieldNEQ(FieldID, id)) +} + +// IDIn applies the In predicate on the ID field. +func IDIn(ids ...int) predicate.InvitationCode { + return predicate.InvitationCode(sql.FieldIn(FieldID, ids...)) +} + +// IDNotIn applies the NotIn predicate on the ID field. +func IDNotIn(ids ...int) predicate.InvitationCode { + return predicate.InvitationCode(sql.FieldNotIn(FieldID, ids...)) +} + +// IDGT applies the GT predicate on the ID field. +func IDGT(id int) predicate.InvitationCode { + return predicate.InvitationCode(sql.FieldGT(FieldID, id)) +} + +// IDGTE applies the GTE predicate on the ID field. +func IDGTE(id int) predicate.InvitationCode { + return predicate.InvitationCode(sql.FieldGTE(FieldID, id)) +} + +// IDLT applies the LT predicate on the ID field. +func IDLT(id int) predicate.InvitationCode { + return predicate.InvitationCode(sql.FieldLT(FieldID, id)) +} + +// IDLTE applies the LTE predicate on the ID field. +func IDLTE(id int) predicate.InvitationCode { + return predicate.InvitationCode(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.InvitationCode { + return predicate.InvitationCode(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.InvitationCode { + return predicate.InvitationCode(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.InvitationCode { + return predicate.InvitationCode(sql.FieldEQ(FieldDeletedAt, v)) +} + +// Code applies equality check predicate on the "code" field. It's identical to CodeEQ. +func Code(v string) predicate.InvitationCode { + return predicate.InvitationCode(sql.FieldEQ(FieldCode, v)) +} + +// GroupID applies equality check predicate on the "group_id" field. It's identical to GroupIDEQ. +func GroupID(v int) predicate.InvitationCode { + return predicate.InvitationCode(sql.FieldEQ(FieldGroupID, v)) +} + +// MaxUses applies equality check predicate on the "max_uses" field. It's identical to MaxUsesEQ. +func MaxUses(v int) predicate.InvitationCode { + return predicate.InvitationCode(sql.FieldEQ(FieldMaxUses, v)) +} + +// UsedCount applies equality check predicate on the "used_count" field. It's identical to UsedCountEQ. +func UsedCount(v int) predicate.InvitationCode { + return predicate.InvitationCode(sql.FieldEQ(FieldUsedCount, v)) +} + +// ExpiresAt applies equality check predicate on the "expires_at" field. It's identical to ExpiresAtEQ. +func ExpiresAt(v time.Time) predicate.InvitationCode { + return predicate.InvitationCode(sql.FieldEQ(FieldExpiresAt, v)) +} + +// CreatedAtEQ applies the EQ predicate on the "created_at" field. +func CreatedAtEQ(v time.Time) predicate.InvitationCode { + return predicate.InvitationCode(sql.FieldEQ(FieldCreatedAt, v)) +} + +// CreatedAtNEQ applies the NEQ predicate on the "created_at" field. +func CreatedAtNEQ(v time.Time) predicate.InvitationCode { + return predicate.InvitationCode(sql.FieldNEQ(FieldCreatedAt, v)) +} + +// CreatedAtIn applies the In predicate on the "created_at" field. +func CreatedAtIn(vs ...time.Time) predicate.InvitationCode { + return predicate.InvitationCode(sql.FieldIn(FieldCreatedAt, vs...)) +} + +// CreatedAtNotIn applies the NotIn predicate on the "created_at" field. +func CreatedAtNotIn(vs ...time.Time) predicate.InvitationCode { + return predicate.InvitationCode(sql.FieldNotIn(FieldCreatedAt, vs...)) +} + +// CreatedAtGT applies the GT predicate on the "created_at" field. +func CreatedAtGT(v time.Time) predicate.InvitationCode { + return predicate.InvitationCode(sql.FieldGT(FieldCreatedAt, v)) +} + +// CreatedAtGTE applies the GTE predicate on the "created_at" field. +func CreatedAtGTE(v time.Time) predicate.InvitationCode { + return predicate.InvitationCode(sql.FieldGTE(FieldCreatedAt, v)) +} + +// CreatedAtLT applies the LT predicate on the "created_at" field. +func CreatedAtLT(v time.Time) predicate.InvitationCode { + return predicate.InvitationCode(sql.FieldLT(FieldCreatedAt, v)) +} + +// CreatedAtLTE applies the LTE predicate on the "created_at" field. +func CreatedAtLTE(v time.Time) predicate.InvitationCode { + return predicate.InvitationCode(sql.FieldLTE(FieldCreatedAt, v)) +} + +// UpdatedAtEQ applies the EQ predicate on the "updated_at" field. +func UpdatedAtEQ(v time.Time) predicate.InvitationCode { + return predicate.InvitationCode(sql.FieldEQ(FieldUpdatedAt, v)) +} + +// UpdatedAtNEQ applies the NEQ predicate on the "updated_at" field. +func UpdatedAtNEQ(v time.Time) predicate.InvitationCode { + return predicate.InvitationCode(sql.FieldNEQ(FieldUpdatedAt, v)) +} + +// UpdatedAtIn applies the In predicate on the "updated_at" field. +func UpdatedAtIn(vs ...time.Time) predicate.InvitationCode { + return predicate.InvitationCode(sql.FieldIn(FieldUpdatedAt, vs...)) +} + +// UpdatedAtNotIn applies the NotIn predicate on the "updated_at" field. +func UpdatedAtNotIn(vs ...time.Time) predicate.InvitationCode { + return predicate.InvitationCode(sql.FieldNotIn(FieldUpdatedAt, vs...)) +} + +// UpdatedAtGT applies the GT predicate on the "updated_at" field. +func UpdatedAtGT(v time.Time) predicate.InvitationCode { + return predicate.InvitationCode(sql.FieldGT(FieldUpdatedAt, v)) +} + +// UpdatedAtGTE applies the GTE predicate on the "updated_at" field. +func UpdatedAtGTE(v time.Time) predicate.InvitationCode { + return predicate.InvitationCode(sql.FieldGTE(FieldUpdatedAt, v)) +} + +// UpdatedAtLT applies the LT predicate on the "updated_at" field. +func UpdatedAtLT(v time.Time) predicate.InvitationCode { + return predicate.InvitationCode(sql.FieldLT(FieldUpdatedAt, v)) +} + +// UpdatedAtLTE applies the LTE predicate on the "updated_at" field. +func UpdatedAtLTE(v time.Time) predicate.InvitationCode { + return predicate.InvitationCode(sql.FieldLTE(FieldUpdatedAt, v)) +} + +// DeletedAtEQ applies the EQ predicate on the "deleted_at" field. +func DeletedAtEQ(v time.Time) predicate.InvitationCode { + return predicate.InvitationCode(sql.FieldEQ(FieldDeletedAt, v)) +} + +// DeletedAtNEQ applies the NEQ predicate on the "deleted_at" field. +func DeletedAtNEQ(v time.Time) predicate.InvitationCode { + return predicate.InvitationCode(sql.FieldNEQ(FieldDeletedAt, v)) +} + +// DeletedAtIn applies the In predicate on the "deleted_at" field. +func DeletedAtIn(vs ...time.Time) predicate.InvitationCode { + return predicate.InvitationCode(sql.FieldIn(FieldDeletedAt, vs...)) +} + +// DeletedAtNotIn applies the NotIn predicate on the "deleted_at" field. +func DeletedAtNotIn(vs ...time.Time) predicate.InvitationCode { + return predicate.InvitationCode(sql.FieldNotIn(FieldDeletedAt, vs...)) +} + +// DeletedAtGT applies the GT predicate on the "deleted_at" field. +func DeletedAtGT(v time.Time) predicate.InvitationCode { + return predicate.InvitationCode(sql.FieldGT(FieldDeletedAt, v)) +} + +// DeletedAtGTE applies the GTE predicate on the "deleted_at" field. +func DeletedAtGTE(v time.Time) predicate.InvitationCode { + return predicate.InvitationCode(sql.FieldGTE(FieldDeletedAt, v)) +} + +// DeletedAtLT applies the LT predicate on the "deleted_at" field. +func DeletedAtLT(v time.Time) predicate.InvitationCode { + return predicate.InvitationCode(sql.FieldLT(FieldDeletedAt, v)) +} + +// DeletedAtLTE applies the LTE predicate on the "deleted_at" field. +func DeletedAtLTE(v time.Time) predicate.InvitationCode { + return predicate.InvitationCode(sql.FieldLTE(FieldDeletedAt, v)) +} + +// DeletedAtIsNil applies the IsNil predicate on the "deleted_at" field. +func DeletedAtIsNil() predicate.InvitationCode { + return predicate.InvitationCode(sql.FieldIsNull(FieldDeletedAt)) +} + +// DeletedAtNotNil applies the NotNil predicate on the "deleted_at" field. +func DeletedAtNotNil() predicate.InvitationCode { + return predicate.InvitationCode(sql.FieldNotNull(FieldDeletedAt)) +} + +// CodeEQ applies the EQ predicate on the "code" field. +func CodeEQ(v string) predicate.InvitationCode { + return predicate.InvitationCode(sql.FieldEQ(FieldCode, v)) +} + +// CodeNEQ applies the NEQ predicate on the "code" field. +func CodeNEQ(v string) predicate.InvitationCode { + return predicate.InvitationCode(sql.FieldNEQ(FieldCode, v)) +} + +// CodeIn applies the In predicate on the "code" field. +func CodeIn(vs ...string) predicate.InvitationCode { + return predicate.InvitationCode(sql.FieldIn(FieldCode, vs...)) +} + +// CodeNotIn applies the NotIn predicate on the "code" field. +func CodeNotIn(vs ...string) predicate.InvitationCode { + return predicate.InvitationCode(sql.FieldNotIn(FieldCode, vs...)) +} + +// CodeGT applies the GT predicate on the "code" field. +func CodeGT(v string) predicate.InvitationCode { + return predicate.InvitationCode(sql.FieldGT(FieldCode, v)) +} + +// CodeGTE applies the GTE predicate on the "code" field. +func CodeGTE(v string) predicate.InvitationCode { + return predicate.InvitationCode(sql.FieldGTE(FieldCode, v)) +} + +// CodeLT applies the LT predicate on the "code" field. +func CodeLT(v string) predicate.InvitationCode { + return predicate.InvitationCode(sql.FieldLT(FieldCode, v)) +} + +// CodeLTE applies the LTE predicate on the "code" field. +func CodeLTE(v string) predicate.InvitationCode { + return predicate.InvitationCode(sql.FieldLTE(FieldCode, v)) +} + +// CodeContains applies the Contains predicate on the "code" field. +func CodeContains(v string) predicate.InvitationCode { + return predicate.InvitationCode(sql.FieldContains(FieldCode, v)) +} + +// CodeHasPrefix applies the HasPrefix predicate on the "code" field. +func CodeHasPrefix(v string) predicate.InvitationCode { + return predicate.InvitationCode(sql.FieldHasPrefix(FieldCode, v)) +} + +// CodeHasSuffix applies the HasSuffix predicate on the "code" field. +func CodeHasSuffix(v string) predicate.InvitationCode { + return predicate.InvitationCode(sql.FieldHasSuffix(FieldCode, v)) +} + +// CodeEqualFold applies the EqualFold predicate on the "code" field. +func CodeEqualFold(v string) predicate.InvitationCode { + return predicate.InvitationCode(sql.FieldEqualFold(FieldCode, v)) +} + +// CodeContainsFold applies the ContainsFold predicate on the "code" field. +func CodeContainsFold(v string) predicate.InvitationCode { + return predicate.InvitationCode(sql.FieldContainsFold(FieldCode, v)) +} + +// GroupIDEQ applies the EQ predicate on the "group_id" field. +func GroupIDEQ(v int) predicate.InvitationCode { + return predicate.InvitationCode(sql.FieldEQ(FieldGroupID, v)) +} + +// GroupIDNEQ applies the NEQ predicate on the "group_id" field. +func GroupIDNEQ(v int) predicate.InvitationCode { + return predicate.InvitationCode(sql.FieldNEQ(FieldGroupID, v)) +} + +// GroupIDIn applies the In predicate on the "group_id" field. +func GroupIDIn(vs ...int) predicate.InvitationCode { + return predicate.InvitationCode(sql.FieldIn(FieldGroupID, vs...)) +} + +// GroupIDNotIn applies the NotIn predicate on the "group_id" field. +func GroupIDNotIn(vs ...int) predicate.InvitationCode { + return predicate.InvitationCode(sql.FieldNotIn(FieldGroupID, vs...)) +} + +// GroupIDGT applies the GT predicate on the "group_id" field. +func GroupIDGT(v int) predicate.InvitationCode { + return predicate.InvitationCode(sql.FieldGT(FieldGroupID, v)) +} + +// GroupIDGTE applies the GTE predicate on the "group_id" field. +func GroupIDGTE(v int) predicate.InvitationCode { + return predicate.InvitationCode(sql.FieldGTE(FieldGroupID, v)) +} + +// GroupIDLT applies the LT predicate on the "group_id" field. +func GroupIDLT(v int) predicate.InvitationCode { + return predicate.InvitationCode(sql.FieldLT(FieldGroupID, v)) +} + +// GroupIDLTE applies the LTE predicate on the "group_id" field. +func GroupIDLTE(v int) predicate.InvitationCode { + return predicate.InvitationCode(sql.FieldLTE(FieldGroupID, v)) +} + +// MaxUsesEQ applies the EQ predicate on the "max_uses" field. +func MaxUsesEQ(v int) predicate.InvitationCode { + return predicate.InvitationCode(sql.FieldEQ(FieldMaxUses, v)) +} + +// MaxUsesNEQ applies the NEQ predicate on the "max_uses" field. +func MaxUsesNEQ(v int) predicate.InvitationCode { + return predicate.InvitationCode(sql.FieldNEQ(FieldMaxUses, v)) +} + +// MaxUsesIn applies the In predicate on the "max_uses" field. +func MaxUsesIn(vs ...int) predicate.InvitationCode { + return predicate.InvitationCode(sql.FieldIn(FieldMaxUses, vs...)) +} + +// MaxUsesNotIn applies the NotIn predicate on the "max_uses" field. +func MaxUsesNotIn(vs ...int) predicate.InvitationCode { + return predicate.InvitationCode(sql.FieldNotIn(FieldMaxUses, vs...)) +} + +// MaxUsesGT applies the GT predicate on the "max_uses" field. +func MaxUsesGT(v int) predicate.InvitationCode { + return predicate.InvitationCode(sql.FieldGT(FieldMaxUses, v)) +} + +// MaxUsesGTE applies the GTE predicate on the "max_uses" field. +func MaxUsesGTE(v int) predicate.InvitationCode { + return predicate.InvitationCode(sql.FieldGTE(FieldMaxUses, v)) +} + +// MaxUsesLT applies the LT predicate on the "max_uses" field. +func MaxUsesLT(v int) predicate.InvitationCode { + return predicate.InvitationCode(sql.FieldLT(FieldMaxUses, v)) +} + +// MaxUsesLTE applies the LTE predicate on the "max_uses" field. +func MaxUsesLTE(v int) predicate.InvitationCode { + return predicate.InvitationCode(sql.FieldLTE(FieldMaxUses, v)) +} + +// UsedCountEQ applies the EQ predicate on the "used_count" field. +func UsedCountEQ(v int) predicate.InvitationCode { + return predicate.InvitationCode(sql.FieldEQ(FieldUsedCount, v)) +} + +// UsedCountNEQ applies the NEQ predicate on the "used_count" field. +func UsedCountNEQ(v int) predicate.InvitationCode { + return predicate.InvitationCode(sql.FieldNEQ(FieldUsedCount, v)) +} + +// UsedCountIn applies the In predicate on the "used_count" field. +func UsedCountIn(vs ...int) predicate.InvitationCode { + return predicate.InvitationCode(sql.FieldIn(FieldUsedCount, vs...)) +} + +// UsedCountNotIn applies the NotIn predicate on the "used_count" field. +func UsedCountNotIn(vs ...int) predicate.InvitationCode { + return predicate.InvitationCode(sql.FieldNotIn(FieldUsedCount, vs...)) +} + +// UsedCountGT applies the GT predicate on the "used_count" field. +func UsedCountGT(v int) predicate.InvitationCode { + return predicate.InvitationCode(sql.FieldGT(FieldUsedCount, v)) +} + +// UsedCountGTE applies the GTE predicate on the "used_count" field. +func UsedCountGTE(v int) predicate.InvitationCode { + return predicate.InvitationCode(sql.FieldGTE(FieldUsedCount, v)) +} + +// UsedCountLT applies the LT predicate on the "used_count" field. +func UsedCountLT(v int) predicate.InvitationCode { + return predicate.InvitationCode(sql.FieldLT(FieldUsedCount, v)) +} + +// UsedCountLTE applies the LTE predicate on the "used_count" field. +func UsedCountLTE(v int) predicate.InvitationCode { + return predicate.InvitationCode(sql.FieldLTE(FieldUsedCount, v)) +} + +// ExpiresAtEQ applies the EQ predicate on the "expires_at" field. +func ExpiresAtEQ(v time.Time) predicate.InvitationCode { + return predicate.InvitationCode(sql.FieldEQ(FieldExpiresAt, v)) +} + +// ExpiresAtNEQ applies the NEQ predicate on the "expires_at" field. +func ExpiresAtNEQ(v time.Time) predicate.InvitationCode { + return predicate.InvitationCode(sql.FieldNEQ(FieldExpiresAt, v)) +} + +// ExpiresAtIn applies the In predicate on the "expires_at" field. +func ExpiresAtIn(vs ...time.Time) predicate.InvitationCode { + return predicate.InvitationCode(sql.FieldIn(FieldExpiresAt, vs...)) +} + +// ExpiresAtNotIn applies the NotIn predicate on the "expires_at" field. +func ExpiresAtNotIn(vs ...time.Time) predicate.InvitationCode { + return predicate.InvitationCode(sql.FieldNotIn(FieldExpiresAt, vs...)) +} + +// ExpiresAtGT applies the GT predicate on the "expires_at" field. +func ExpiresAtGT(v time.Time) predicate.InvitationCode { + return predicate.InvitationCode(sql.FieldGT(FieldExpiresAt, v)) +} + +// ExpiresAtGTE applies the GTE predicate on the "expires_at" field. +func ExpiresAtGTE(v time.Time) predicate.InvitationCode { + return predicate.InvitationCode(sql.FieldGTE(FieldExpiresAt, v)) +} + +// ExpiresAtLT applies the LT predicate on the "expires_at" field. +func ExpiresAtLT(v time.Time) predicate.InvitationCode { + return predicate.InvitationCode(sql.FieldLT(FieldExpiresAt, v)) +} + +// ExpiresAtLTE applies the LTE predicate on the "expires_at" field. +func ExpiresAtLTE(v time.Time) predicate.InvitationCode { + return predicate.InvitationCode(sql.FieldLTE(FieldExpiresAt, v)) +} + +// ExpiresAtIsNil applies the IsNil predicate on the "expires_at" field. +func ExpiresAtIsNil() predicate.InvitationCode { + return predicate.InvitationCode(sql.FieldIsNull(FieldExpiresAt)) +} + +// ExpiresAtNotNil applies the NotNil predicate on the "expires_at" field. +func ExpiresAtNotNil() predicate.InvitationCode { + return predicate.InvitationCode(sql.FieldNotNull(FieldExpiresAt)) +} + +// And groups predicates with the AND operator between them. +func And(predicates ...predicate.InvitationCode) predicate.InvitationCode { + return predicate.InvitationCode(sql.AndPredicates(predicates...)) +} + +// Or groups predicates with the OR operator between them. +func Or(predicates ...predicate.InvitationCode) predicate.InvitationCode { + return predicate.InvitationCode(sql.OrPredicates(predicates...)) +} + +// Not applies the not operator on the given predicate. +func Not(p predicate.InvitationCode) predicate.InvitationCode { + return predicate.InvitationCode(sql.NotPredicates(p)) +} diff --git a/ent/invitationcode_create.go b/ent/invitationcode_create.go new file mode 100644 index 00000000..0d7cb8d8 --- /dev/null +++ b/ent/invitationcode_create.go @@ -0,0 +1,1000 @@ +// 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/invitationcode" +) + +// InvitationCodeCreate is the builder for creating a InvitationCode entity. +type InvitationCodeCreate struct { + config + mutation *InvitationCodeMutation + hooks []Hook + conflict []sql.ConflictOption +} + +// SetCreatedAt sets the "created_at" field. +func (icc *InvitationCodeCreate) SetCreatedAt(t time.Time) *InvitationCodeCreate { + icc.mutation.SetCreatedAt(t) + return icc +} + +// SetNillableCreatedAt sets the "created_at" field if the given value is not nil. +func (icc *InvitationCodeCreate) SetNillableCreatedAt(t *time.Time) *InvitationCodeCreate { + if t != nil { + icc.SetCreatedAt(*t) + } + return icc +} + +// SetUpdatedAt sets the "updated_at" field. +func (icc *InvitationCodeCreate) SetUpdatedAt(t time.Time) *InvitationCodeCreate { + icc.mutation.SetUpdatedAt(t) + return icc +} + +// SetNillableUpdatedAt sets the "updated_at" field if the given value is not nil. +func (icc *InvitationCodeCreate) SetNillableUpdatedAt(t *time.Time) *InvitationCodeCreate { + if t != nil { + icc.SetUpdatedAt(*t) + } + return icc +} + +// SetDeletedAt sets the "deleted_at" field. +func (icc *InvitationCodeCreate) SetDeletedAt(t time.Time) *InvitationCodeCreate { + icc.mutation.SetDeletedAt(t) + return icc +} + +// SetNillableDeletedAt sets the "deleted_at" field if the given value is not nil. +func (icc *InvitationCodeCreate) SetNillableDeletedAt(t *time.Time) *InvitationCodeCreate { + if t != nil { + icc.SetDeletedAt(*t) + } + return icc +} + +// SetCode sets the "code" field. +func (icc *InvitationCodeCreate) SetCode(s string) *InvitationCodeCreate { + icc.mutation.SetCode(s) + return icc +} + +// SetGroupID sets the "group_id" field. +func (icc *InvitationCodeCreate) SetGroupID(i int) *InvitationCodeCreate { + icc.mutation.SetGroupID(i) + return icc +} + +// SetNillableGroupID sets the "group_id" field if the given value is not nil. +func (icc *InvitationCodeCreate) SetNillableGroupID(i *int) *InvitationCodeCreate { + if i != nil { + icc.SetGroupID(*i) + } + return icc +} + +// SetMaxUses sets the "max_uses" field. +func (icc *InvitationCodeCreate) SetMaxUses(i int) *InvitationCodeCreate { + icc.mutation.SetMaxUses(i) + return icc +} + +// SetNillableMaxUses sets the "max_uses" field if the given value is not nil. +func (icc *InvitationCodeCreate) SetNillableMaxUses(i *int) *InvitationCodeCreate { + if i != nil { + icc.SetMaxUses(*i) + } + return icc +} + +// SetUsedCount sets the "used_count" field. +func (icc *InvitationCodeCreate) SetUsedCount(i int) *InvitationCodeCreate { + icc.mutation.SetUsedCount(i) + return icc +} + +// SetNillableUsedCount sets the "used_count" field if the given value is not nil. +func (icc *InvitationCodeCreate) SetNillableUsedCount(i *int) *InvitationCodeCreate { + if i != nil { + icc.SetUsedCount(*i) + } + return icc +} + +// SetExpiresAt sets the "expires_at" field. +func (icc *InvitationCodeCreate) SetExpiresAt(t time.Time) *InvitationCodeCreate { + icc.mutation.SetExpiresAt(t) + return icc +} + +// SetNillableExpiresAt sets the "expires_at" field if the given value is not nil. +func (icc *InvitationCodeCreate) SetNillableExpiresAt(t *time.Time) *InvitationCodeCreate { + if t != nil { + icc.SetExpiresAt(*t) + } + return icc +} + +// Mutation returns the InvitationCodeMutation object of the builder. +func (icc *InvitationCodeCreate) Mutation() *InvitationCodeMutation { + return icc.mutation +} + +// Save creates the InvitationCode in the database. +func (icc *InvitationCodeCreate) Save(ctx context.Context) (*InvitationCode, error) { + if err := icc.defaults(); err != nil { + return nil, err + } + return withHooks(ctx, icc.sqlSave, icc.mutation, icc.hooks) +} + +// SaveX calls Save and panics if Save returns an error. +func (icc *InvitationCodeCreate) SaveX(ctx context.Context) *InvitationCode { + v, err := icc.Save(ctx) + if err != nil { + panic(err) + } + return v +} + +// Exec executes the query. +func (icc *InvitationCodeCreate) Exec(ctx context.Context) error { + _, err := icc.Save(ctx) + return err +} + +// ExecX is like Exec, but panics if an error occurs. +func (icc *InvitationCodeCreate) ExecX(ctx context.Context) { + if err := icc.Exec(ctx); err != nil { + panic(err) + } +} + +// defaults sets the default values of the builder before save. +func (icc *InvitationCodeCreate) defaults() error { + if _, ok := icc.mutation.CreatedAt(); !ok { + if invitationcode.DefaultCreatedAt == nil { + return fmt.Errorf("ent: uninitialized invitationcode.DefaultCreatedAt (forgotten import ent/runtime?)") + } + v := invitationcode.DefaultCreatedAt() + icc.mutation.SetCreatedAt(v) + } + if _, ok := icc.mutation.UpdatedAt(); !ok { + if invitationcode.DefaultUpdatedAt == nil { + return fmt.Errorf("ent: uninitialized invitationcode.DefaultUpdatedAt (forgotten import ent/runtime?)") + } + v := invitationcode.DefaultUpdatedAt() + icc.mutation.SetUpdatedAt(v) + } + if _, ok := icc.mutation.GroupID(); !ok { + v := invitationcode.DefaultGroupID + icc.mutation.SetGroupID(v) + } + if _, ok := icc.mutation.MaxUses(); !ok { + v := invitationcode.DefaultMaxUses + icc.mutation.SetMaxUses(v) + } + if _, ok := icc.mutation.UsedCount(); !ok { + v := invitationcode.DefaultUsedCount + icc.mutation.SetUsedCount(v) + } + return nil +} + +// check runs all checks and user-defined validators on the builder. +func (icc *InvitationCodeCreate) check() error { + if _, ok := icc.mutation.CreatedAt(); !ok { + return &ValidationError{Name: "created_at", err: errors.New(`ent: missing required field "InvitationCode.created_at"`)} + } + if _, ok := icc.mutation.UpdatedAt(); !ok { + return &ValidationError{Name: "updated_at", err: errors.New(`ent: missing required field "InvitationCode.updated_at"`)} + } + if _, ok := icc.mutation.Code(); !ok { + return &ValidationError{Name: "code", err: errors.New(`ent: missing required field "InvitationCode.code"`)} + } + if v, ok := icc.mutation.Code(); ok { + if err := invitationcode.CodeValidator(v); err != nil { + return &ValidationError{Name: "code", err: fmt.Errorf(`ent: validator failed for field "InvitationCode.code": %w`, err)} + } + } + if _, ok := icc.mutation.GroupID(); !ok { + return &ValidationError{Name: "group_id", err: errors.New(`ent: missing required field "InvitationCode.group_id"`)} + } + if _, ok := icc.mutation.MaxUses(); !ok { + return &ValidationError{Name: "max_uses", err: errors.New(`ent: missing required field "InvitationCode.max_uses"`)} + } + if _, ok := icc.mutation.UsedCount(); !ok { + return &ValidationError{Name: "used_count", err: errors.New(`ent: missing required field "InvitationCode.used_count"`)} + } + return nil +} + +func (icc *InvitationCodeCreate) sqlSave(ctx context.Context) (*InvitationCode, error) { + if err := icc.check(); err != nil { + return nil, err + } + _node, _spec := icc.createSpec() + if err := sqlgraph.CreateNode(ctx, icc.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) + icc.mutation.id = &_node.ID + icc.mutation.done = true + return _node, nil +} + +func (icc *InvitationCodeCreate) createSpec() (*InvitationCode, *sqlgraph.CreateSpec) { + var ( + _node = &InvitationCode{config: icc.config} + _spec = sqlgraph.NewCreateSpec(invitationcode.Table, sqlgraph.NewFieldSpec(invitationcode.FieldID, field.TypeInt)) + ) + + if id, ok := icc.mutation.ID(); ok { + _node.ID = id + id64 := int64(id) + _spec.ID.Value = id64 + } + + _spec.OnConflict = icc.conflict + if value, ok := icc.mutation.CreatedAt(); ok { + _spec.SetField(invitationcode.FieldCreatedAt, field.TypeTime, value) + _node.CreatedAt = value + } + if value, ok := icc.mutation.UpdatedAt(); ok { + _spec.SetField(invitationcode.FieldUpdatedAt, field.TypeTime, value) + _node.UpdatedAt = value + } + if value, ok := icc.mutation.DeletedAt(); ok { + _spec.SetField(invitationcode.FieldDeletedAt, field.TypeTime, value) + _node.DeletedAt = &value + } + if value, ok := icc.mutation.Code(); ok { + _spec.SetField(invitationcode.FieldCode, field.TypeString, value) + _node.Code = value + } + if value, ok := icc.mutation.GroupID(); ok { + _spec.SetField(invitationcode.FieldGroupID, field.TypeInt, value) + _node.GroupID = value + } + if value, ok := icc.mutation.MaxUses(); ok { + _spec.SetField(invitationcode.FieldMaxUses, field.TypeInt, value) + _node.MaxUses = value + } + if value, ok := icc.mutation.UsedCount(); ok { + _spec.SetField(invitationcode.FieldUsedCount, field.TypeInt, value) + _node.UsedCount = value + } + if value, ok := icc.mutation.ExpiresAt(); ok { + _spec.SetField(invitationcode.FieldExpiresAt, field.TypeTime, value) + _node.ExpiresAt = &value + } + return _node, _spec +} + +// OnConflict allows configuring the `ON CONFLICT` / `ON DUPLICATE KEY` clause +// of the `INSERT` statement. For example: +// +// client.InvitationCode.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.InvitationCodeUpsert) { +// SetCreatedAt(v+v). +// }). +// Exec(ctx) +func (icc *InvitationCodeCreate) OnConflict(opts ...sql.ConflictOption) *InvitationCodeUpsertOne { + icc.conflict = opts + return &InvitationCodeUpsertOne{ + create: icc, + } +} + +// OnConflictColumns calls `OnConflict` and configures the columns +// as conflict target. Using this option is equivalent to using: +// +// client.InvitationCode.Create(). +// OnConflict(sql.ConflictColumns(columns...)). +// Exec(ctx) +func (icc *InvitationCodeCreate) OnConflictColumns(columns ...string) *InvitationCodeUpsertOne { + icc.conflict = append(icc.conflict, sql.ConflictColumns(columns...)) + return &InvitationCodeUpsertOne{ + create: icc, + } +} + +type ( + // InvitationCodeUpsertOne is the builder for "upsert"-ing + // one InvitationCode node. + InvitationCodeUpsertOne struct { + create *InvitationCodeCreate + } + + // InvitationCodeUpsert is the "OnConflict" setter. + InvitationCodeUpsert struct { + *sql.UpdateSet + } +) + +// SetUpdatedAt sets the "updated_at" field. +func (u *InvitationCodeUpsert) SetUpdatedAt(v time.Time) *InvitationCodeUpsert { + u.Set(invitationcode.FieldUpdatedAt, v) + return u +} + +// UpdateUpdatedAt sets the "updated_at" field to the value that was provided on create. +func (u *InvitationCodeUpsert) UpdateUpdatedAt() *InvitationCodeUpsert { + u.SetExcluded(invitationcode.FieldUpdatedAt) + return u +} + +// SetDeletedAt sets the "deleted_at" field. +func (u *InvitationCodeUpsert) SetDeletedAt(v time.Time) *InvitationCodeUpsert { + u.Set(invitationcode.FieldDeletedAt, v) + return u +} + +// UpdateDeletedAt sets the "deleted_at" field to the value that was provided on create. +func (u *InvitationCodeUpsert) UpdateDeletedAt() *InvitationCodeUpsert { + u.SetExcluded(invitationcode.FieldDeletedAt) + return u +} + +// ClearDeletedAt clears the value of the "deleted_at" field. +func (u *InvitationCodeUpsert) ClearDeletedAt() *InvitationCodeUpsert { + u.SetNull(invitationcode.FieldDeletedAt) + return u +} + +// SetCode sets the "code" field. +func (u *InvitationCodeUpsert) SetCode(v string) *InvitationCodeUpsert { + u.Set(invitationcode.FieldCode, v) + return u +} + +// UpdateCode sets the "code" field to the value that was provided on create. +func (u *InvitationCodeUpsert) UpdateCode() *InvitationCodeUpsert { + u.SetExcluded(invitationcode.FieldCode) + return u +} + +// SetGroupID sets the "group_id" field. +func (u *InvitationCodeUpsert) SetGroupID(v int) *InvitationCodeUpsert { + u.Set(invitationcode.FieldGroupID, v) + return u +} + +// UpdateGroupID sets the "group_id" field to the value that was provided on create. +func (u *InvitationCodeUpsert) UpdateGroupID() *InvitationCodeUpsert { + u.SetExcluded(invitationcode.FieldGroupID) + return u +} + +// AddGroupID adds v to the "group_id" field. +func (u *InvitationCodeUpsert) AddGroupID(v int) *InvitationCodeUpsert { + u.Add(invitationcode.FieldGroupID, v) + return u +} + +// SetMaxUses sets the "max_uses" field. +func (u *InvitationCodeUpsert) SetMaxUses(v int) *InvitationCodeUpsert { + u.Set(invitationcode.FieldMaxUses, v) + return u +} + +// UpdateMaxUses sets the "max_uses" field to the value that was provided on create. +func (u *InvitationCodeUpsert) UpdateMaxUses() *InvitationCodeUpsert { + u.SetExcluded(invitationcode.FieldMaxUses) + return u +} + +// AddMaxUses adds v to the "max_uses" field. +func (u *InvitationCodeUpsert) AddMaxUses(v int) *InvitationCodeUpsert { + u.Add(invitationcode.FieldMaxUses, v) + return u +} + +// SetUsedCount sets the "used_count" field. +func (u *InvitationCodeUpsert) SetUsedCount(v int) *InvitationCodeUpsert { + u.Set(invitationcode.FieldUsedCount, v) + return u +} + +// UpdateUsedCount sets the "used_count" field to the value that was provided on create. +func (u *InvitationCodeUpsert) UpdateUsedCount() *InvitationCodeUpsert { + u.SetExcluded(invitationcode.FieldUsedCount) + return u +} + +// AddUsedCount adds v to the "used_count" field. +func (u *InvitationCodeUpsert) AddUsedCount(v int) *InvitationCodeUpsert { + u.Add(invitationcode.FieldUsedCount, v) + return u +} + +// SetExpiresAt sets the "expires_at" field. +func (u *InvitationCodeUpsert) SetExpiresAt(v time.Time) *InvitationCodeUpsert { + u.Set(invitationcode.FieldExpiresAt, v) + return u +} + +// UpdateExpiresAt sets the "expires_at" field to the value that was provided on create. +func (u *InvitationCodeUpsert) UpdateExpiresAt() *InvitationCodeUpsert { + u.SetExcluded(invitationcode.FieldExpiresAt) + return u +} + +// ClearExpiresAt clears the value of the "expires_at" field. +func (u *InvitationCodeUpsert) ClearExpiresAt() *InvitationCodeUpsert { + u.SetNull(invitationcode.FieldExpiresAt) + return u +} + +// UpdateNewValues updates the mutable fields using the new values that were set on create. +// Using this option is equivalent to using: +// +// client.InvitationCode.Create(). +// OnConflict( +// sql.ResolveWithNewValues(), +// ). +// Exec(ctx) +func (u *InvitationCodeUpsertOne) UpdateNewValues() *InvitationCodeUpsertOne { + 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(invitationcode.FieldCreatedAt) + } + })) + return u +} + +// Ignore sets each column to itself in case of conflict. +// Using this option is equivalent to using: +// +// client.InvitationCode.Create(). +// OnConflict(sql.ResolveWithIgnore()). +// Exec(ctx) +func (u *InvitationCodeUpsertOne) Ignore() *InvitationCodeUpsertOne { + 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 *InvitationCodeUpsertOne) DoNothing() *InvitationCodeUpsertOne { + u.create.conflict = append(u.create.conflict, sql.DoNothing()) + return u +} + +// Update allows overriding fields `UPDATE` values. See the InvitationCodeCreate.OnConflict +// documentation for more info. +func (u *InvitationCodeUpsertOne) Update(set func(*InvitationCodeUpsert)) *InvitationCodeUpsertOne { + u.create.conflict = append(u.create.conflict, sql.ResolveWith(func(update *sql.UpdateSet) { + set(&InvitationCodeUpsert{UpdateSet: update}) + })) + return u +} + +// SetUpdatedAt sets the "updated_at" field. +func (u *InvitationCodeUpsertOne) SetUpdatedAt(v time.Time) *InvitationCodeUpsertOne { + return u.Update(func(s *InvitationCodeUpsert) { + s.SetUpdatedAt(v) + }) +} + +// UpdateUpdatedAt sets the "updated_at" field to the value that was provided on create. +func (u *InvitationCodeUpsertOne) UpdateUpdatedAt() *InvitationCodeUpsertOne { + return u.Update(func(s *InvitationCodeUpsert) { + s.UpdateUpdatedAt() + }) +} + +// SetDeletedAt sets the "deleted_at" field. +func (u *InvitationCodeUpsertOne) SetDeletedAt(v time.Time) *InvitationCodeUpsertOne { + return u.Update(func(s *InvitationCodeUpsert) { + s.SetDeletedAt(v) + }) +} + +// UpdateDeletedAt sets the "deleted_at" field to the value that was provided on create. +func (u *InvitationCodeUpsertOne) UpdateDeletedAt() *InvitationCodeUpsertOne { + return u.Update(func(s *InvitationCodeUpsert) { + s.UpdateDeletedAt() + }) +} + +// ClearDeletedAt clears the value of the "deleted_at" field. +func (u *InvitationCodeUpsertOne) ClearDeletedAt() *InvitationCodeUpsertOne { + return u.Update(func(s *InvitationCodeUpsert) { + s.ClearDeletedAt() + }) +} + +// SetCode sets the "code" field. +func (u *InvitationCodeUpsertOne) SetCode(v string) *InvitationCodeUpsertOne { + return u.Update(func(s *InvitationCodeUpsert) { + s.SetCode(v) + }) +} + +// UpdateCode sets the "code" field to the value that was provided on create. +func (u *InvitationCodeUpsertOne) UpdateCode() *InvitationCodeUpsertOne { + return u.Update(func(s *InvitationCodeUpsert) { + s.UpdateCode() + }) +} + +// SetGroupID sets the "group_id" field. +func (u *InvitationCodeUpsertOne) SetGroupID(v int) *InvitationCodeUpsertOne { + return u.Update(func(s *InvitationCodeUpsert) { + s.SetGroupID(v) + }) +} + +// AddGroupID adds v to the "group_id" field. +func (u *InvitationCodeUpsertOne) AddGroupID(v int) *InvitationCodeUpsertOne { + return u.Update(func(s *InvitationCodeUpsert) { + s.AddGroupID(v) + }) +} + +// UpdateGroupID sets the "group_id" field to the value that was provided on create. +func (u *InvitationCodeUpsertOne) UpdateGroupID() *InvitationCodeUpsertOne { + return u.Update(func(s *InvitationCodeUpsert) { + s.UpdateGroupID() + }) +} + +// SetMaxUses sets the "max_uses" field. +func (u *InvitationCodeUpsertOne) SetMaxUses(v int) *InvitationCodeUpsertOne { + return u.Update(func(s *InvitationCodeUpsert) { + s.SetMaxUses(v) + }) +} + +// AddMaxUses adds v to the "max_uses" field. +func (u *InvitationCodeUpsertOne) AddMaxUses(v int) *InvitationCodeUpsertOne { + return u.Update(func(s *InvitationCodeUpsert) { + s.AddMaxUses(v) + }) +} + +// UpdateMaxUses sets the "max_uses" field to the value that was provided on create. +func (u *InvitationCodeUpsertOne) UpdateMaxUses() *InvitationCodeUpsertOne { + return u.Update(func(s *InvitationCodeUpsert) { + s.UpdateMaxUses() + }) +} + +// SetUsedCount sets the "used_count" field. +func (u *InvitationCodeUpsertOne) SetUsedCount(v int) *InvitationCodeUpsertOne { + return u.Update(func(s *InvitationCodeUpsert) { + s.SetUsedCount(v) + }) +} + +// AddUsedCount adds v to the "used_count" field. +func (u *InvitationCodeUpsertOne) AddUsedCount(v int) *InvitationCodeUpsertOne { + return u.Update(func(s *InvitationCodeUpsert) { + s.AddUsedCount(v) + }) +} + +// UpdateUsedCount sets the "used_count" field to the value that was provided on create. +func (u *InvitationCodeUpsertOne) UpdateUsedCount() *InvitationCodeUpsertOne { + return u.Update(func(s *InvitationCodeUpsert) { + s.UpdateUsedCount() + }) +} + +// SetExpiresAt sets the "expires_at" field. +func (u *InvitationCodeUpsertOne) SetExpiresAt(v time.Time) *InvitationCodeUpsertOne { + return u.Update(func(s *InvitationCodeUpsert) { + s.SetExpiresAt(v) + }) +} + +// UpdateExpiresAt sets the "expires_at" field to the value that was provided on create. +func (u *InvitationCodeUpsertOne) UpdateExpiresAt() *InvitationCodeUpsertOne { + return u.Update(func(s *InvitationCodeUpsert) { + s.UpdateExpiresAt() + }) +} + +// ClearExpiresAt clears the value of the "expires_at" field. +func (u *InvitationCodeUpsertOne) ClearExpiresAt() *InvitationCodeUpsertOne { + return u.Update(func(s *InvitationCodeUpsert) { + s.ClearExpiresAt() + }) +} + +// Exec executes the query. +func (u *InvitationCodeUpsertOne) Exec(ctx context.Context) error { + if len(u.create.conflict) == 0 { + return errors.New("ent: missing options for InvitationCodeCreate.OnConflict") + } + return u.create.Exec(ctx) +} + +// ExecX is like Exec, but panics if an error occurs. +func (u *InvitationCodeUpsertOne) 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 *InvitationCodeUpsertOne) 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 *InvitationCodeUpsertOne) IDX(ctx context.Context) int { + id, err := u.ID(ctx) + if err != nil { + panic(err) + } + return id +} + +func (m *InvitationCodeCreate) SetRawID(t int) *InvitationCodeCreate { + m.mutation.SetRawID(t) + return m +} + +// InvitationCodeCreateBulk is the builder for creating many InvitationCode entities in bulk. +type InvitationCodeCreateBulk struct { + config + err error + builders []*InvitationCodeCreate + conflict []sql.ConflictOption +} + +// Save creates the InvitationCode entities in the database. +func (iccb *InvitationCodeCreateBulk) Save(ctx context.Context) ([]*InvitationCode, error) { + if iccb.err != nil { + return nil, iccb.err + } + specs := make([]*sqlgraph.CreateSpec, len(iccb.builders)) + nodes := make([]*InvitationCode, len(iccb.builders)) + mutators := make([]Mutator, len(iccb.builders)) + for i := range iccb.builders { + func(i int, root context.Context) { + builder := iccb.builders[i] + builder.defaults() + var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) { + mutation, ok := m.(*InvitationCodeMutation) + 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, iccb.builders[i+1].mutation) + } else { + spec := &sqlgraph.BatchCreateSpec{Nodes: specs} + spec.OnConflict = iccb.conflict + // Invoke the actual operation on the latest mutation in the chain. + if err = sqlgraph.BatchCreate(ctx, iccb.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, iccb.builders[0].mutation); err != nil { + return nil, err + } + } + return nodes, nil +} + +// SaveX is like Save, but panics if an error occurs. +func (iccb *InvitationCodeCreateBulk) SaveX(ctx context.Context) []*InvitationCode { + v, err := iccb.Save(ctx) + if err != nil { + panic(err) + } + return v +} + +// Exec executes the query. +func (iccb *InvitationCodeCreateBulk) Exec(ctx context.Context) error { + _, err := iccb.Save(ctx) + return err +} + +// ExecX is like Exec, but panics if an error occurs. +func (iccb *InvitationCodeCreateBulk) ExecX(ctx context.Context) { + if err := iccb.Exec(ctx); err != nil { + panic(err) + } +} + +// OnConflict allows configuring the `ON CONFLICT` / `ON DUPLICATE KEY` clause +// of the `INSERT` statement. For example: +// +// client.InvitationCode.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.InvitationCodeUpsert) { +// SetCreatedAt(v+v). +// }). +// Exec(ctx) +func (iccb *InvitationCodeCreateBulk) OnConflict(opts ...sql.ConflictOption) *InvitationCodeUpsertBulk { + iccb.conflict = opts + return &InvitationCodeUpsertBulk{ + create: iccb, + } +} + +// OnConflictColumns calls `OnConflict` and configures the columns +// as conflict target. Using this option is equivalent to using: +// +// client.InvitationCode.Create(). +// OnConflict(sql.ConflictColumns(columns...)). +// Exec(ctx) +func (iccb *InvitationCodeCreateBulk) OnConflictColumns(columns ...string) *InvitationCodeUpsertBulk { + iccb.conflict = append(iccb.conflict, sql.ConflictColumns(columns...)) + return &InvitationCodeUpsertBulk{ + create: iccb, + } +} + +// InvitationCodeUpsertBulk is the builder for "upsert"-ing +// a bulk of InvitationCode nodes. +type InvitationCodeUpsertBulk struct { + create *InvitationCodeCreateBulk +} + +// UpdateNewValues updates the mutable fields using the new values that +// were set on create. Using this option is equivalent to using: +// +// client.InvitationCode.Create(). +// OnConflict( +// sql.ResolveWithNewValues(), +// ). +// Exec(ctx) +func (u *InvitationCodeUpsertBulk) UpdateNewValues() *InvitationCodeUpsertBulk { + 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(invitationcode.FieldCreatedAt) + } + } + })) + return u +} + +// Ignore sets each column to itself in case of conflict. +// Using this option is equivalent to using: +// +// client.InvitationCode.Create(). +// OnConflict(sql.ResolveWithIgnore()). +// Exec(ctx) +func (u *InvitationCodeUpsertBulk) Ignore() *InvitationCodeUpsertBulk { + 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 *InvitationCodeUpsertBulk) DoNothing() *InvitationCodeUpsertBulk { + u.create.conflict = append(u.create.conflict, sql.DoNothing()) + return u +} + +// Update allows overriding fields `UPDATE` values. See the InvitationCodeCreateBulk.OnConflict +// documentation for more info. +func (u *InvitationCodeUpsertBulk) Update(set func(*InvitationCodeUpsert)) *InvitationCodeUpsertBulk { + u.create.conflict = append(u.create.conflict, sql.ResolveWith(func(update *sql.UpdateSet) { + set(&InvitationCodeUpsert{UpdateSet: update}) + })) + return u +} + +// SetUpdatedAt sets the "updated_at" field. +func (u *InvitationCodeUpsertBulk) SetUpdatedAt(v time.Time) *InvitationCodeUpsertBulk { + return u.Update(func(s *InvitationCodeUpsert) { + s.SetUpdatedAt(v) + }) +} + +// UpdateUpdatedAt sets the "updated_at" field to the value that was provided on create. +func (u *InvitationCodeUpsertBulk) UpdateUpdatedAt() *InvitationCodeUpsertBulk { + return u.Update(func(s *InvitationCodeUpsert) { + s.UpdateUpdatedAt() + }) +} + +// SetDeletedAt sets the "deleted_at" field. +func (u *InvitationCodeUpsertBulk) SetDeletedAt(v time.Time) *InvitationCodeUpsertBulk { + return u.Update(func(s *InvitationCodeUpsert) { + s.SetDeletedAt(v) + }) +} + +// UpdateDeletedAt sets the "deleted_at" field to the value that was provided on create. +func (u *InvitationCodeUpsertBulk) UpdateDeletedAt() *InvitationCodeUpsertBulk { + return u.Update(func(s *InvitationCodeUpsert) { + s.UpdateDeletedAt() + }) +} + +// ClearDeletedAt clears the value of the "deleted_at" field. +func (u *InvitationCodeUpsertBulk) ClearDeletedAt() *InvitationCodeUpsertBulk { + return u.Update(func(s *InvitationCodeUpsert) { + s.ClearDeletedAt() + }) +} + +// SetCode sets the "code" field. +func (u *InvitationCodeUpsertBulk) SetCode(v string) *InvitationCodeUpsertBulk { + return u.Update(func(s *InvitationCodeUpsert) { + s.SetCode(v) + }) +} + +// UpdateCode sets the "code" field to the value that was provided on create. +func (u *InvitationCodeUpsertBulk) UpdateCode() *InvitationCodeUpsertBulk { + return u.Update(func(s *InvitationCodeUpsert) { + s.UpdateCode() + }) +} + +// SetGroupID sets the "group_id" field. +func (u *InvitationCodeUpsertBulk) SetGroupID(v int) *InvitationCodeUpsertBulk { + return u.Update(func(s *InvitationCodeUpsert) { + s.SetGroupID(v) + }) +} + +// AddGroupID adds v to the "group_id" field. +func (u *InvitationCodeUpsertBulk) AddGroupID(v int) *InvitationCodeUpsertBulk { + return u.Update(func(s *InvitationCodeUpsert) { + s.AddGroupID(v) + }) +} + +// UpdateGroupID sets the "group_id" field to the value that was provided on create. +func (u *InvitationCodeUpsertBulk) UpdateGroupID() *InvitationCodeUpsertBulk { + return u.Update(func(s *InvitationCodeUpsert) { + s.UpdateGroupID() + }) +} + +// SetMaxUses sets the "max_uses" field. +func (u *InvitationCodeUpsertBulk) SetMaxUses(v int) *InvitationCodeUpsertBulk { + return u.Update(func(s *InvitationCodeUpsert) { + s.SetMaxUses(v) + }) +} + +// AddMaxUses adds v to the "max_uses" field. +func (u *InvitationCodeUpsertBulk) AddMaxUses(v int) *InvitationCodeUpsertBulk { + return u.Update(func(s *InvitationCodeUpsert) { + s.AddMaxUses(v) + }) +} + +// UpdateMaxUses sets the "max_uses" field to the value that was provided on create. +func (u *InvitationCodeUpsertBulk) UpdateMaxUses() *InvitationCodeUpsertBulk { + return u.Update(func(s *InvitationCodeUpsert) { + s.UpdateMaxUses() + }) +} + +// SetUsedCount sets the "used_count" field. +func (u *InvitationCodeUpsertBulk) SetUsedCount(v int) *InvitationCodeUpsertBulk { + return u.Update(func(s *InvitationCodeUpsert) { + s.SetUsedCount(v) + }) +} + +// AddUsedCount adds v to the "used_count" field. +func (u *InvitationCodeUpsertBulk) AddUsedCount(v int) *InvitationCodeUpsertBulk { + return u.Update(func(s *InvitationCodeUpsert) { + s.AddUsedCount(v) + }) +} + +// UpdateUsedCount sets the "used_count" field to the value that was provided on create. +func (u *InvitationCodeUpsertBulk) UpdateUsedCount() *InvitationCodeUpsertBulk { + return u.Update(func(s *InvitationCodeUpsert) { + s.UpdateUsedCount() + }) +} + +// SetExpiresAt sets the "expires_at" field. +func (u *InvitationCodeUpsertBulk) SetExpiresAt(v time.Time) *InvitationCodeUpsertBulk { + return u.Update(func(s *InvitationCodeUpsert) { + s.SetExpiresAt(v) + }) +} + +// UpdateExpiresAt sets the "expires_at" field to the value that was provided on create. +func (u *InvitationCodeUpsertBulk) UpdateExpiresAt() *InvitationCodeUpsertBulk { + return u.Update(func(s *InvitationCodeUpsert) { + s.UpdateExpiresAt() + }) +} + +// ClearExpiresAt clears the value of the "expires_at" field. +func (u *InvitationCodeUpsertBulk) ClearExpiresAt() *InvitationCodeUpsertBulk { + return u.Update(func(s *InvitationCodeUpsert) { + s.ClearExpiresAt() + }) +} + +// Exec executes the query. +func (u *InvitationCodeUpsertBulk) 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 InvitationCodeCreateBulk instead", i) + } + } + if len(u.create.conflict) == 0 { + return errors.New("ent: missing options for InvitationCodeCreateBulk.OnConflict") + } + return u.create.Exec(ctx) +} + +// ExecX is like Exec, but panics if an error occurs. +func (u *InvitationCodeUpsertBulk) ExecX(ctx context.Context) { + if err := u.create.Exec(ctx); err != nil { + panic(err) + } +} diff --git a/ent/invitationcode_delete.go b/ent/invitationcode_delete.go new file mode 100644 index 00000000..fb68ade6 --- /dev/null +++ b/ent/invitationcode_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/invitationcode" + "github.com/cloudreve/Cloudreve/v4/ent/predicate" +) + +// InvitationCodeDelete is the builder for deleting a InvitationCode entity. +type InvitationCodeDelete struct { + config + hooks []Hook + mutation *InvitationCodeMutation +} + +// Where appends a list predicates to the InvitationCodeDelete builder. +func (icd *InvitationCodeDelete) Where(ps ...predicate.InvitationCode) *InvitationCodeDelete { + icd.mutation.Where(ps...) + return icd +} + +// Exec executes the deletion query and returns how many vertices were deleted. +func (icd *InvitationCodeDelete) Exec(ctx context.Context) (int, error) { + return withHooks(ctx, icd.sqlExec, icd.mutation, icd.hooks) +} + +// ExecX is like Exec, but panics if an error occurs. +func (icd *InvitationCodeDelete) ExecX(ctx context.Context) int { + n, err := icd.Exec(ctx) + if err != nil { + panic(err) + } + return n +} + +func (icd *InvitationCodeDelete) sqlExec(ctx context.Context) (int, error) { + _spec := sqlgraph.NewDeleteSpec(invitationcode.Table, sqlgraph.NewFieldSpec(invitationcode.FieldID, field.TypeInt)) + if ps := icd.mutation.predicates; len(ps) > 0 { + _spec.Predicate = func(selector *sql.Selector) { + for i := range ps { + ps[i](selector) + } + } + } + affected, err := sqlgraph.DeleteNodes(ctx, icd.driver, _spec) + if err != nil && sqlgraph.IsConstraintError(err) { + err = &ConstraintError{msg: err.Error(), wrap: err} + } + icd.mutation.done = true + return affected, err +} + +// InvitationCodeDeleteOne is the builder for deleting a single InvitationCode entity. +type InvitationCodeDeleteOne struct { + icd *InvitationCodeDelete +} + +// Where appends a list predicates to the InvitationCodeDelete builder. +func (icdo *InvitationCodeDeleteOne) Where(ps ...predicate.InvitationCode) *InvitationCodeDeleteOne { + icdo.icd.mutation.Where(ps...) + return icdo +} + +// Exec executes the deletion query. +func (icdo *InvitationCodeDeleteOne) Exec(ctx context.Context) error { + n, err := icdo.icd.Exec(ctx) + switch { + case err != nil: + return err + case n == 0: + return &NotFoundError{invitationcode.Label} + default: + return nil + } +} + +// ExecX is like Exec, but panics if an error occurs. +func (icdo *InvitationCodeDeleteOne) ExecX(ctx context.Context) { + if err := icdo.Exec(ctx); err != nil { + panic(err) + } +} diff --git a/ent/invitationcode_query.go b/ent/invitationcode_query.go new file mode 100644 index 00000000..eb94def5 --- /dev/null +++ b/ent/invitationcode_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/invitationcode" + "github.com/cloudreve/Cloudreve/v4/ent/predicate" +) + +// InvitationCodeQuery is the builder for querying InvitationCode entities. +type InvitationCodeQuery struct { + config + ctx *QueryContext + order []invitationcode.OrderOption + inters []Interceptor + predicates []predicate.InvitationCode + // intermediate query (i.e. traversal path). + sql *sql.Selector + path func(context.Context) (*sql.Selector, error) +} + +// Where adds a new predicate for the InvitationCodeQuery builder. +func (icq *InvitationCodeQuery) Where(ps ...predicate.InvitationCode) *InvitationCodeQuery { + icq.predicates = append(icq.predicates, ps...) + return icq +} + +// Limit the number of records to be returned by this query. +func (icq *InvitationCodeQuery) Limit(limit int) *InvitationCodeQuery { + icq.ctx.Limit = &limit + return icq +} + +// Offset to start from. +func (icq *InvitationCodeQuery) Offset(offset int) *InvitationCodeQuery { + icq.ctx.Offset = &offset + return icq +} + +// 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 (icq *InvitationCodeQuery) Unique(unique bool) *InvitationCodeQuery { + icq.ctx.Unique = &unique + return icq +} + +// Order specifies how the records should be ordered. +func (icq *InvitationCodeQuery) Order(o ...invitationcode.OrderOption) *InvitationCodeQuery { + icq.order = append(icq.order, o...) + return icq +} + +// First returns the first InvitationCode entity from the query. +// Returns a *NotFoundError when no InvitationCode was found. +func (icq *InvitationCodeQuery) First(ctx context.Context) (*InvitationCode, error) { + nodes, err := icq.Limit(1).All(setContextOp(ctx, icq.ctx, "First")) + if err != nil { + return nil, err + } + if len(nodes) == 0 { + return nil, &NotFoundError{invitationcode.Label} + } + return nodes[0], nil +} + +// FirstX is like First, but panics if an error occurs. +func (icq *InvitationCodeQuery) FirstX(ctx context.Context) *InvitationCode { + node, err := icq.First(ctx) + if err != nil && !IsNotFound(err) { + panic(err) + } + return node +} + +// FirstID returns the first InvitationCode ID from the query. +// Returns a *NotFoundError when no InvitationCode ID was found. +func (icq *InvitationCodeQuery) FirstID(ctx context.Context) (id int, err error) { + var ids []int + if ids, err = icq.Limit(1).IDs(setContextOp(ctx, icq.ctx, "FirstID")); err != nil { + return + } + if len(ids) == 0 { + err = &NotFoundError{invitationcode.Label} + return + } + return ids[0], nil +} + +// FirstIDX is like FirstID, but panics if an error occurs. +func (icq *InvitationCodeQuery) FirstIDX(ctx context.Context) int { + id, err := icq.FirstID(ctx) + if err != nil && !IsNotFound(err) { + panic(err) + } + return id +} + +// Only returns a single InvitationCode entity found by the query, ensuring it only returns one. +// Returns a *NotSingularError when more than one InvitationCode entity is found. +// Returns a *NotFoundError when no InvitationCode entities are found. +func (icq *InvitationCodeQuery) Only(ctx context.Context) (*InvitationCode, error) { + nodes, err := icq.Limit(2).All(setContextOp(ctx, icq.ctx, "Only")) + if err != nil { + return nil, err + } + switch len(nodes) { + case 1: + return nodes[0], nil + case 0: + return nil, &NotFoundError{invitationcode.Label} + default: + return nil, &NotSingularError{invitationcode.Label} + } +} + +// OnlyX is like Only, but panics if an error occurs. +func (icq *InvitationCodeQuery) OnlyX(ctx context.Context) *InvitationCode { + node, err := icq.Only(ctx) + if err != nil { + panic(err) + } + return node +} + +// OnlyID is like Only, but returns the only InvitationCode ID in the query. +// Returns a *NotSingularError when more than one InvitationCode ID is found. +// Returns a *NotFoundError when no entities are found. +func (icq *InvitationCodeQuery) OnlyID(ctx context.Context) (id int, err error) { + var ids []int + if ids, err = icq.Limit(2).IDs(setContextOp(ctx, icq.ctx, "OnlyID")); err != nil { + return + } + switch len(ids) { + case 1: + id = ids[0] + case 0: + err = &NotFoundError{invitationcode.Label} + default: + err = &NotSingularError{invitationcode.Label} + } + return +} + +// OnlyIDX is like OnlyID, but panics if an error occurs. +func (icq *InvitationCodeQuery) OnlyIDX(ctx context.Context) int { + id, err := icq.OnlyID(ctx) + if err != nil { + panic(err) + } + return id +} + +// All executes the query and returns a list of InvitationCodes. +func (icq *InvitationCodeQuery) All(ctx context.Context) ([]*InvitationCode, error) { + ctx = setContextOp(ctx, icq.ctx, "All") + if err := icq.prepareQuery(ctx); err != nil { + return nil, err + } + qr := querierAll[[]*InvitationCode, *InvitationCodeQuery]() + return withInterceptors[[]*InvitationCode](ctx, icq, qr, icq.inters) +} + +// AllX is like All, but panics if an error occurs. +func (icq *InvitationCodeQuery) AllX(ctx context.Context) []*InvitationCode { + nodes, err := icq.All(ctx) + if err != nil { + panic(err) + } + return nodes +} + +// IDs executes the query and returns a list of InvitationCode IDs. +func (icq *InvitationCodeQuery) IDs(ctx context.Context) (ids []int, err error) { + if icq.ctx.Unique == nil && icq.path != nil { + icq.Unique(true) + } + ctx = setContextOp(ctx, icq.ctx, "IDs") + if err = icq.Select(invitationcode.FieldID).Scan(ctx, &ids); err != nil { + return nil, err + } + return ids, nil +} + +// IDsX is like IDs, but panics if an error occurs. +func (icq *InvitationCodeQuery) IDsX(ctx context.Context) []int { + ids, err := icq.IDs(ctx) + if err != nil { + panic(err) + } + return ids +} + +// Count returns the count of the given query. +func (icq *InvitationCodeQuery) Count(ctx context.Context) (int, error) { + ctx = setContextOp(ctx, icq.ctx, "Count") + if err := icq.prepareQuery(ctx); err != nil { + return 0, err + } + return withInterceptors[int](ctx, icq, querierCount[*InvitationCodeQuery](), icq.inters) +} + +// CountX is like Count, but panics if an error occurs. +func (icq *InvitationCodeQuery) CountX(ctx context.Context) int { + count, err := icq.Count(ctx) + if err != nil { + panic(err) + } + return count +} + +// Exist returns true if the query has elements in the graph. +func (icq *InvitationCodeQuery) Exist(ctx context.Context) (bool, error) { + ctx = setContextOp(ctx, icq.ctx, "Exist") + switch _, err := icq.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 (icq *InvitationCodeQuery) ExistX(ctx context.Context) bool { + exist, err := icq.Exist(ctx) + if err != nil { + panic(err) + } + return exist +} + +// Clone returns a duplicate of the InvitationCodeQuery builder, including all associated steps. It can be +// used to prepare common query builders and use them differently after the clone is made. +func (icq *InvitationCodeQuery) Clone() *InvitationCodeQuery { + if icq == nil { + return nil + } + return &InvitationCodeQuery{ + config: icq.config, + ctx: icq.ctx.Clone(), + order: append([]invitationcode.OrderOption{}, icq.order...), + inters: append([]Interceptor{}, icq.inters...), + predicates: append([]predicate.InvitationCode{}, icq.predicates...), + // clone intermediate query. + sql: icq.sql.Clone(), + path: icq.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.InvitationCode.Query(). +// GroupBy(invitationcode.FieldCreatedAt). +// Aggregate(ent.Count()). +// Scan(ctx, &v) +func (icq *InvitationCodeQuery) GroupBy(field string, fields ...string) *InvitationCodeGroupBy { + icq.ctx.Fields = append([]string{field}, fields...) + grbuild := &InvitationCodeGroupBy{build: icq} + grbuild.flds = &icq.ctx.Fields + grbuild.label = invitationcode.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.InvitationCode.Query(). +// Select(invitationcode.FieldCreatedAt). +// Scan(ctx, &v) +func (icq *InvitationCodeQuery) Select(fields ...string) *InvitationCodeSelect { + icq.ctx.Fields = append(icq.ctx.Fields, fields...) + sbuild := &InvitationCodeSelect{InvitationCodeQuery: icq} + sbuild.label = invitationcode.Label + sbuild.flds, sbuild.scan = &icq.ctx.Fields, sbuild.Scan + return sbuild +} + +// Aggregate returns a InvitationCodeSelect configured with the given aggregations. +func (icq *InvitationCodeQuery) Aggregate(fns ...AggregateFunc) *InvitationCodeSelect { + return icq.Select().Aggregate(fns...) +} + +func (icq *InvitationCodeQuery) prepareQuery(ctx context.Context) error { + for _, inter := range icq.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, icq); err != nil { + return err + } + } + } + for _, f := range icq.ctx.Fields { + if !invitationcode.ValidColumn(f) { + return &ValidationError{Name: f, err: fmt.Errorf("ent: invalid field %q for query", f)} + } + } + if icq.path != nil { + prev, err := icq.path(ctx) + if err != nil { + return err + } + icq.sql = prev + } + return nil +} + +func (icq *InvitationCodeQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*InvitationCode, error) { + var ( + nodes = []*InvitationCode{} + _spec = icq.querySpec() + ) + _spec.ScanValues = func(columns []string) ([]any, error) { + return (*InvitationCode).scanValues(nil, columns) + } + _spec.Assign = func(columns []string, values []any) error { + node := &InvitationCode{config: icq.config} + nodes = append(nodes, node) + return node.assignValues(columns, values) + } + for i := range hooks { + hooks[i](ctx, _spec) + } + if err := sqlgraph.QueryNodes(ctx, icq.driver, _spec); err != nil { + return nil, err + } + if len(nodes) == 0 { + return nodes, nil + } + return nodes, nil +} + +func (icq *InvitationCodeQuery) sqlCount(ctx context.Context) (int, error) { + _spec := icq.querySpec() + _spec.Node.Columns = icq.ctx.Fields + if len(icq.ctx.Fields) > 0 { + _spec.Unique = icq.ctx.Unique != nil && *icq.ctx.Unique + } + return sqlgraph.CountNodes(ctx, icq.driver, _spec) +} + +func (icq *InvitationCodeQuery) querySpec() *sqlgraph.QuerySpec { + _spec := sqlgraph.NewQuerySpec(invitationcode.Table, invitationcode.Columns, sqlgraph.NewFieldSpec(invitationcode.FieldID, field.TypeInt)) + _spec.From = icq.sql + if unique := icq.ctx.Unique; unique != nil { + _spec.Unique = *unique + } else if icq.path != nil { + _spec.Unique = true + } + if fields := icq.ctx.Fields; len(fields) > 0 { + _spec.Node.Columns = make([]string, 0, len(fields)) + _spec.Node.Columns = append(_spec.Node.Columns, invitationcode.FieldID) + for i := range fields { + if fields[i] != invitationcode.FieldID { + _spec.Node.Columns = append(_spec.Node.Columns, fields[i]) + } + } + } + if ps := icq.predicates; len(ps) > 0 { + _spec.Predicate = func(selector *sql.Selector) { + for i := range ps { + ps[i](selector) + } + } + } + if limit := icq.ctx.Limit; limit != nil { + _spec.Limit = *limit + } + if offset := icq.ctx.Offset; offset != nil { + _spec.Offset = *offset + } + if ps := icq.order; len(ps) > 0 { + _spec.Order = func(selector *sql.Selector) { + for i := range ps { + ps[i](selector) + } + } + } + return _spec +} + +func (icq *InvitationCodeQuery) sqlQuery(ctx context.Context) *sql.Selector { + builder := sql.Dialect(icq.driver.Dialect()) + t1 := builder.Table(invitationcode.Table) + columns := icq.ctx.Fields + if len(columns) == 0 { + columns = invitationcode.Columns + } + selector := builder.Select(t1.Columns(columns...)...).From(t1) + if icq.sql != nil { + selector = icq.sql + selector.Select(selector.Columns(columns...)...) + } + if icq.ctx.Unique != nil && *icq.ctx.Unique { + selector.Distinct() + } + for _, p := range icq.predicates { + p(selector) + } + for _, p := range icq.order { + p(selector) + } + if offset := icq.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 := icq.ctx.Limit; limit != nil { + selector.Limit(*limit) + } + return selector +} + +// InvitationCodeGroupBy is the group-by builder for InvitationCode entities. +type InvitationCodeGroupBy struct { + selector + build *InvitationCodeQuery +} + +// Aggregate adds the given aggregation functions to the group-by query. +func (icgb *InvitationCodeGroupBy) Aggregate(fns ...AggregateFunc) *InvitationCodeGroupBy { + icgb.fns = append(icgb.fns, fns...) + return icgb +} + +// Scan applies the selector query and scans the result into the given value. +func (icgb *InvitationCodeGroupBy) Scan(ctx context.Context, v any) error { + ctx = setContextOp(ctx, icgb.build.ctx, "GroupBy") + if err := icgb.build.prepareQuery(ctx); err != nil { + return err + } + return scanWithInterceptors[*InvitationCodeQuery, *InvitationCodeGroupBy](ctx, icgb.build, icgb, icgb.build.inters, v) +} + +func (icgb *InvitationCodeGroupBy) sqlScan(ctx context.Context, root *InvitationCodeQuery, v any) error { + selector := root.sqlQuery(ctx).Select() + aggregation := make([]string, 0, len(icgb.fns)) + for _, fn := range icgb.fns { + aggregation = append(aggregation, fn(selector)) + } + if len(selector.SelectedColumns()) == 0 { + columns := make([]string, 0, len(*icgb.flds)+len(icgb.fns)) + for _, f := range *icgb.flds { + columns = append(columns, selector.C(f)) + } + columns = append(columns, aggregation...) + selector.Select(columns...) + } + selector.GroupBy(selector.Columns(*icgb.flds...)...) + if err := selector.Err(); err != nil { + return err + } + rows := &sql.Rows{} + query, args := selector.Query() + if err := icgb.build.driver.Query(ctx, query, args, rows); err != nil { + return err + } + defer rows.Close() + return sql.ScanSlice(rows, v) +} + +// InvitationCodeSelect is the builder for selecting fields of InvitationCode entities. +type InvitationCodeSelect struct { + *InvitationCodeQuery + selector +} + +// Aggregate adds the given aggregation functions to the selector query. +func (ics *InvitationCodeSelect) Aggregate(fns ...AggregateFunc) *InvitationCodeSelect { + ics.fns = append(ics.fns, fns...) + return ics +} + +// Scan applies the selector query and scans the result into the given value. +func (ics *InvitationCodeSelect) Scan(ctx context.Context, v any) error { + ctx = setContextOp(ctx, ics.ctx, "Select") + if err := ics.prepareQuery(ctx); err != nil { + return err + } + return scanWithInterceptors[*InvitationCodeQuery, *InvitationCodeSelect](ctx, ics.InvitationCodeQuery, ics, ics.inters, v) +} + +func (ics *InvitationCodeSelect) sqlScan(ctx context.Context, root *InvitationCodeQuery, v any) error { + selector := root.sqlQuery(ctx) + aggregation := make([]string, 0, len(ics.fns)) + for _, fn := range ics.fns { + aggregation = append(aggregation, fn(selector)) + } + switch n := len(*ics.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 := ics.driver.Query(ctx, query, args, rows); err != nil { + return err + } + defer rows.Close() + return sql.ScanSlice(rows, v) +} diff --git a/ent/invitationcode_update.go b/ent/invitationcode_update.go new file mode 100644 index 00000000..58d23b94 --- /dev/null +++ b/ent/invitationcode_update.go @@ -0,0 +1,550 @@ +// 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/invitationcode" + "github.com/cloudreve/Cloudreve/v4/ent/predicate" +) + +// InvitationCodeUpdate is the builder for updating InvitationCode entities. +type InvitationCodeUpdate struct { + config + hooks []Hook + mutation *InvitationCodeMutation +} + +// Where appends a list predicates to the InvitationCodeUpdate builder. +func (icu *InvitationCodeUpdate) Where(ps ...predicate.InvitationCode) *InvitationCodeUpdate { + icu.mutation.Where(ps...) + return icu +} + +// SetUpdatedAt sets the "updated_at" field. +func (icu *InvitationCodeUpdate) SetUpdatedAt(t time.Time) *InvitationCodeUpdate { + icu.mutation.SetUpdatedAt(t) + return icu +} + +// SetDeletedAt sets the "deleted_at" field. +func (icu *InvitationCodeUpdate) SetDeletedAt(t time.Time) *InvitationCodeUpdate { + icu.mutation.SetDeletedAt(t) + return icu +} + +// SetNillableDeletedAt sets the "deleted_at" field if the given value is not nil. +func (icu *InvitationCodeUpdate) SetNillableDeletedAt(t *time.Time) *InvitationCodeUpdate { + if t != nil { + icu.SetDeletedAt(*t) + } + return icu +} + +// ClearDeletedAt clears the value of the "deleted_at" field. +func (icu *InvitationCodeUpdate) ClearDeletedAt() *InvitationCodeUpdate { + icu.mutation.ClearDeletedAt() + return icu +} + +// SetCode sets the "code" field. +func (icu *InvitationCodeUpdate) SetCode(s string) *InvitationCodeUpdate { + icu.mutation.SetCode(s) + return icu +} + +// SetNillableCode sets the "code" field if the given value is not nil. +func (icu *InvitationCodeUpdate) SetNillableCode(s *string) *InvitationCodeUpdate { + if s != nil { + icu.SetCode(*s) + } + return icu +} + +// SetGroupID sets the "group_id" field. +func (icu *InvitationCodeUpdate) SetGroupID(i int) *InvitationCodeUpdate { + icu.mutation.ResetGroupID() + icu.mutation.SetGroupID(i) + return icu +} + +// SetNillableGroupID sets the "group_id" field if the given value is not nil. +func (icu *InvitationCodeUpdate) SetNillableGroupID(i *int) *InvitationCodeUpdate { + if i != nil { + icu.SetGroupID(*i) + } + return icu +} + +// AddGroupID adds i to the "group_id" field. +func (icu *InvitationCodeUpdate) AddGroupID(i int) *InvitationCodeUpdate { + icu.mutation.AddGroupID(i) + return icu +} + +// SetMaxUses sets the "max_uses" field. +func (icu *InvitationCodeUpdate) SetMaxUses(i int) *InvitationCodeUpdate { + icu.mutation.ResetMaxUses() + icu.mutation.SetMaxUses(i) + return icu +} + +// SetNillableMaxUses sets the "max_uses" field if the given value is not nil. +func (icu *InvitationCodeUpdate) SetNillableMaxUses(i *int) *InvitationCodeUpdate { + if i != nil { + icu.SetMaxUses(*i) + } + return icu +} + +// AddMaxUses adds i to the "max_uses" field. +func (icu *InvitationCodeUpdate) AddMaxUses(i int) *InvitationCodeUpdate { + icu.mutation.AddMaxUses(i) + return icu +} + +// SetUsedCount sets the "used_count" field. +func (icu *InvitationCodeUpdate) SetUsedCount(i int) *InvitationCodeUpdate { + icu.mutation.ResetUsedCount() + icu.mutation.SetUsedCount(i) + return icu +} + +// SetNillableUsedCount sets the "used_count" field if the given value is not nil. +func (icu *InvitationCodeUpdate) SetNillableUsedCount(i *int) *InvitationCodeUpdate { + if i != nil { + icu.SetUsedCount(*i) + } + return icu +} + +// AddUsedCount adds i to the "used_count" field. +func (icu *InvitationCodeUpdate) AddUsedCount(i int) *InvitationCodeUpdate { + icu.mutation.AddUsedCount(i) + return icu +} + +// SetExpiresAt sets the "expires_at" field. +func (icu *InvitationCodeUpdate) SetExpiresAt(t time.Time) *InvitationCodeUpdate { + icu.mutation.SetExpiresAt(t) + return icu +} + +// SetNillableExpiresAt sets the "expires_at" field if the given value is not nil. +func (icu *InvitationCodeUpdate) SetNillableExpiresAt(t *time.Time) *InvitationCodeUpdate { + if t != nil { + icu.SetExpiresAt(*t) + } + return icu +} + +// ClearExpiresAt clears the value of the "expires_at" field. +func (icu *InvitationCodeUpdate) ClearExpiresAt() *InvitationCodeUpdate { + icu.mutation.ClearExpiresAt() + return icu +} + +// Mutation returns the InvitationCodeMutation object of the builder. +func (icu *InvitationCodeUpdate) Mutation() *InvitationCodeMutation { + return icu.mutation +} + +// Save executes the query and returns the number of nodes affected by the update operation. +func (icu *InvitationCodeUpdate) Save(ctx context.Context) (int, error) { + if err := icu.defaults(); err != nil { + return 0, err + } + return withHooks(ctx, icu.sqlSave, icu.mutation, icu.hooks) +} + +// SaveX is like Save, but panics if an error occurs. +func (icu *InvitationCodeUpdate) SaveX(ctx context.Context) int { + affected, err := icu.Save(ctx) + if err != nil { + panic(err) + } + return affected +} + +// Exec executes the query. +func (icu *InvitationCodeUpdate) Exec(ctx context.Context) error { + _, err := icu.Save(ctx) + return err +} + +// ExecX is like Exec, but panics if an error occurs. +func (icu *InvitationCodeUpdate) ExecX(ctx context.Context) { + if err := icu.Exec(ctx); err != nil { + panic(err) + } +} + +// defaults sets the default values of the builder before save. +func (icu *InvitationCodeUpdate) defaults() error { + if _, ok := icu.mutation.UpdatedAt(); !ok { + if invitationcode.UpdateDefaultUpdatedAt == nil { + return fmt.Errorf("ent: uninitialized invitationcode.UpdateDefaultUpdatedAt (forgotten import ent/runtime?)") + } + v := invitationcode.UpdateDefaultUpdatedAt() + icu.mutation.SetUpdatedAt(v) + } + return nil +} + +// check runs all checks and user-defined validators on the builder. +func (icu *InvitationCodeUpdate) check() error { + if v, ok := icu.mutation.Code(); ok { + if err := invitationcode.CodeValidator(v); err != nil { + return &ValidationError{Name: "code", err: fmt.Errorf(`ent: validator failed for field "InvitationCode.code": %w`, err)} + } + } + return nil +} + +func (icu *InvitationCodeUpdate) sqlSave(ctx context.Context) (n int, err error) { + if err := icu.check(); err != nil { + return n, err + } + _spec := sqlgraph.NewUpdateSpec(invitationcode.Table, invitationcode.Columns, sqlgraph.NewFieldSpec(invitationcode.FieldID, field.TypeInt)) + if ps := icu.mutation.predicates; len(ps) > 0 { + _spec.Predicate = func(selector *sql.Selector) { + for i := range ps { + ps[i](selector) + } + } + } + if value, ok := icu.mutation.UpdatedAt(); ok { + _spec.SetField(invitationcode.FieldUpdatedAt, field.TypeTime, value) + } + if value, ok := icu.mutation.DeletedAt(); ok { + _spec.SetField(invitationcode.FieldDeletedAt, field.TypeTime, value) + } + if icu.mutation.DeletedAtCleared() { + _spec.ClearField(invitationcode.FieldDeletedAt, field.TypeTime) + } + if value, ok := icu.mutation.Code(); ok { + _spec.SetField(invitationcode.FieldCode, field.TypeString, value) + } + if value, ok := icu.mutation.GroupID(); ok { + _spec.SetField(invitationcode.FieldGroupID, field.TypeInt, value) + } + if value, ok := icu.mutation.AddedGroupID(); ok { + _spec.AddField(invitationcode.FieldGroupID, field.TypeInt, value) + } + if value, ok := icu.mutation.MaxUses(); ok { + _spec.SetField(invitationcode.FieldMaxUses, field.TypeInt, value) + } + if value, ok := icu.mutation.AddedMaxUses(); ok { + _spec.AddField(invitationcode.FieldMaxUses, field.TypeInt, value) + } + if value, ok := icu.mutation.UsedCount(); ok { + _spec.SetField(invitationcode.FieldUsedCount, field.TypeInt, value) + } + if value, ok := icu.mutation.AddedUsedCount(); ok { + _spec.AddField(invitationcode.FieldUsedCount, field.TypeInt, value) + } + if value, ok := icu.mutation.ExpiresAt(); ok { + _spec.SetField(invitationcode.FieldExpiresAt, field.TypeTime, value) + } + if icu.mutation.ExpiresAtCleared() { + _spec.ClearField(invitationcode.FieldExpiresAt, field.TypeTime) + } + if n, err = sqlgraph.UpdateNodes(ctx, icu.driver, _spec); err != nil { + if _, ok := err.(*sqlgraph.NotFoundError); ok { + err = &NotFoundError{invitationcode.Label} + } else if sqlgraph.IsConstraintError(err) { + err = &ConstraintError{msg: err.Error(), wrap: err} + } + return 0, err + } + icu.mutation.done = true + return n, nil +} + +// InvitationCodeUpdateOne is the builder for updating a single InvitationCode entity. +type InvitationCodeUpdateOne struct { + config + fields []string + hooks []Hook + mutation *InvitationCodeMutation +} + +// SetUpdatedAt sets the "updated_at" field. +func (icuo *InvitationCodeUpdateOne) SetUpdatedAt(t time.Time) *InvitationCodeUpdateOne { + icuo.mutation.SetUpdatedAt(t) + return icuo +} + +// SetDeletedAt sets the "deleted_at" field. +func (icuo *InvitationCodeUpdateOne) SetDeletedAt(t time.Time) *InvitationCodeUpdateOne { + icuo.mutation.SetDeletedAt(t) + return icuo +} + +// SetNillableDeletedAt sets the "deleted_at" field if the given value is not nil. +func (icuo *InvitationCodeUpdateOne) SetNillableDeletedAt(t *time.Time) *InvitationCodeUpdateOne { + if t != nil { + icuo.SetDeletedAt(*t) + } + return icuo +} + +// ClearDeletedAt clears the value of the "deleted_at" field. +func (icuo *InvitationCodeUpdateOne) ClearDeletedAt() *InvitationCodeUpdateOne { + icuo.mutation.ClearDeletedAt() + return icuo +} + +// SetCode sets the "code" field. +func (icuo *InvitationCodeUpdateOne) SetCode(s string) *InvitationCodeUpdateOne { + icuo.mutation.SetCode(s) + return icuo +} + +// SetNillableCode sets the "code" field if the given value is not nil. +func (icuo *InvitationCodeUpdateOne) SetNillableCode(s *string) *InvitationCodeUpdateOne { + if s != nil { + icuo.SetCode(*s) + } + return icuo +} + +// SetGroupID sets the "group_id" field. +func (icuo *InvitationCodeUpdateOne) SetGroupID(i int) *InvitationCodeUpdateOne { + icuo.mutation.ResetGroupID() + icuo.mutation.SetGroupID(i) + return icuo +} + +// SetNillableGroupID sets the "group_id" field if the given value is not nil. +func (icuo *InvitationCodeUpdateOne) SetNillableGroupID(i *int) *InvitationCodeUpdateOne { + if i != nil { + icuo.SetGroupID(*i) + } + return icuo +} + +// AddGroupID adds i to the "group_id" field. +func (icuo *InvitationCodeUpdateOne) AddGroupID(i int) *InvitationCodeUpdateOne { + icuo.mutation.AddGroupID(i) + return icuo +} + +// SetMaxUses sets the "max_uses" field. +func (icuo *InvitationCodeUpdateOne) SetMaxUses(i int) *InvitationCodeUpdateOne { + icuo.mutation.ResetMaxUses() + icuo.mutation.SetMaxUses(i) + return icuo +} + +// SetNillableMaxUses sets the "max_uses" field if the given value is not nil. +func (icuo *InvitationCodeUpdateOne) SetNillableMaxUses(i *int) *InvitationCodeUpdateOne { + if i != nil { + icuo.SetMaxUses(*i) + } + return icuo +} + +// AddMaxUses adds i to the "max_uses" field. +func (icuo *InvitationCodeUpdateOne) AddMaxUses(i int) *InvitationCodeUpdateOne { + icuo.mutation.AddMaxUses(i) + return icuo +} + +// SetUsedCount sets the "used_count" field. +func (icuo *InvitationCodeUpdateOne) SetUsedCount(i int) *InvitationCodeUpdateOne { + icuo.mutation.ResetUsedCount() + icuo.mutation.SetUsedCount(i) + return icuo +} + +// SetNillableUsedCount sets the "used_count" field if the given value is not nil. +func (icuo *InvitationCodeUpdateOne) SetNillableUsedCount(i *int) *InvitationCodeUpdateOne { + if i != nil { + icuo.SetUsedCount(*i) + } + return icuo +} + +// AddUsedCount adds i to the "used_count" field. +func (icuo *InvitationCodeUpdateOne) AddUsedCount(i int) *InvitationCodeUpdateOne { + icuo.mutation.AddUsedCount(i) + return icuo +} + +// SetExpiresAt sets the "expires_at" field. +func (icuo *InvitationCodeUpdateOne) SetExpiresAt(t time.Time) *InvitationCodeUpdateOne { + icuo.mutation.SetExpiresAt(t) + return icuo +} + +// SetNillableExpiresAt sets the "expires_at" field if the given value is not nil. +func (icuo *InvitationCodeUpdateOne) SetNillableExpiresAt(t *time.Time) *InvitationCodeUpdateOne { + if t != nil { + icuo.SetExpiresAt(*t) + } + return icuo +} + +// ClearExpiresAt clears the value of the "expires_at" field. +func (icuo *InvitationCodeUpdateOne) ClearExpiresAt() *InvitationCodeUpdateOne { + icuo.mutation.ClearExpiresAt() + return icuo +} + +// Mutation returns the InvitationCodeMutation object of the builder. +func (icuo *InvitationCodeUpdateOne) Mutation() *InvitationCodeMutation { + return icuo.mutation +} + +// Where appends a list predicates to the InvitationCodeUpdate builder. +func (icuo *InvitationCodeUpdateOne) Where(ps ...predicate.InvitationCode) *InvitationCodeUpdateOne { + icuo.mutation.Where(ps...) + return icuo +} + +// Select allows selecting one or more fields (columns) of the returned entity. +// The default is selecting all fields defined in the entity schema. +func (icuo *InvitationCodeUpdateOne) Select(field string, fields ...string) *InvitationCodeUpdateOne { + icuo.fields = append([]string{field}, fields...) + return icuo +} + +// Save executes the query and returns the updated InvitationCode entity. +func (icuo *InvitationCodeUpdateOne) Save(ctx context.Context) (*InvitationCode, error) { + if err := icuo.defaults(); err != nil { + return nil, err + } + return withHooks(ctx, icuo.sqlSave, icuo.mutation, icuo.hooks) +} + +// SaveX is like Save, but panics if an error occurs. +func (icuo *InvitationCodeUpdateOne) SaveX(ctx context.Context) *InvitationCode { + node, err := icuo.Save(ctx) + if err != nil { + panic(err) + } + return node +} + +// Exec executes the query on the entity. +func (icuo *InvitationCodeUpdateOne) Exec(ctx context.Context) error { + _, err := icuo.Save(ctx) + return err +} + +// ExecX is like Exec, but panics if an error occurs. +func (icuo *InvitationCodeUpdateOne) ExecX(ctx context.Context) { + if err := icuo.Exec(ctx); err != nil { + panic(err) + } +} + +// defaults sets the default values of the builder before save. +func (icuo *InvitationCodeUpdateOne) defaults() error { + if _, ok := icuo.mutation.UpdatedAt(); !ok { + if invitationcode.UpdateDefaultUpdatedAt == nil { + return fmt.Errorf("ent: uninitialized invitationcode.UpdateDefaultUpdatedAt (forgotten import ent/runtime?)") + } + v := invitationcode.UpdateDefaultUpdatedAt() + icuo.mutation.SetUpdatedAt(v) + } + return nil +} + +// check runs all checks and user-defined validators on the builder. +func (icuo *InvitationCodeUpdateOne) check() error { + if v, ok := icuo.mutation.Code(); ok { + if err := invitationcode.CodeValidator(v); err != nil { + return &ValidationError{Name: "code", err: fmt.Errorf(`ent: validator failed for field "InvitationCode.code": %w`, err)} + } + } + return nil +} + +func (icuo *InvitationCodeUpdateOne) sqlSave(ctx context.Context) (_node *InvitationCode, err error) { + if err := icuo.check(); err != nil { + return _node, err + } + _spec := sqlgraph.NewUpdateSpec(invitationcode.Table, invitationcode.Columns, sqlgraph.NewFieldSpec(invitationcode.FieldID, field.TypeInt)) + id, ok := icuo.mutation.ID() + if !ok { + return nil, &ValidationError{Name: "id", err: errors.New(`ent: missing "InvitationCode.id" for update`)} + } + _spec.Node.ID.Value = id + if fields := icuo.fields; len(fields) > 0 { + _spec.Node.Columns = make([]string, 0, len(fields)) + _spec.Node.Columns = append(_spec.Node.Columns, invitationcode.FieldID) + for _, f := range fields { + if !invitationcode.ValidColumn(f) { + return nil, &ValidationError{Name: f, err: fmt.Errorf("ent: invalid field %q for query", f)} + } + if f != invitationcode.FieldID { + _spec.Node.Columns = append(_spec.Node.Columns, f) + } + } + } + if ps := icuo.mutation.predicates; len(ps) > 0 { + _spec.Predicate = func(selector *sql.Selector) { + for i := range ps { + ps[i](selector) + } + } + } + if value, ok := icuo.mutation.UpdatedAt(); ok { + _spec.SetField(invitationcode.FieldUpdatedAt, field.TypeTime, value) + } + if value, ok := icuo.mutation.DeletedAt(); ok { + _spec.SetField(invitationcode.FieldDeletedAt, field.TypeTime, value) + } + if icuo.mutation.DeletedAtCleared() { + _spec.ClearField(invitationcode.FieldDeletedAt, field.TypeTime) + } + if value, ok := icuo.mutation.Code(); ok { + _spec.SetField(invitationcode.FieldCode, field.TypeString, value) + } + if value, ok := icuo.mutation.GroupID(); ok { + _spec.SetField(invitationcode.FieldGroupID, field.TypeInt, value) + } + if value, ok := icuo.mutation.AddedGroupID(); ok { + _spec.AddField(invitationcode.FieldGroupID, field.TypeInt, value) + } + if value, ok := icuo.mutation.MaxUses(); ok { + _spec.SetField(invitationcode.FieldMaxUses, field.TypeInt, value) + } + if value, ok := icuo.mutation.AddedMaxUses(); ok { + _spec.AddField(invitationcode.FieldMaxUses, field.TypeInt, value) + } + if value, ok := icuo.mutation.UsedCount(); ok { + _spec.SetField(invitationcode.FieldUsedCount, field.TypeInt, value) + } + if value, ok := icuo.mutation.AddedUsedCount(); ok { + _spec.AddField(invitationcode.FieldUsedCount, field.TypeInt, value) + } + if value, ok := icuo.mutation.ExpiresAt(); ok { + _spec.SetField(invitationcode.FieldExpiresAt, field.TypeTime, value) + } + if icuo.mutation.ExpiresAtCleared() { + _spec.ClearField(invitationcode.FieldExpiresAt, field.TypeTime) + } + _node = &InvitationCode{config: icuo.config} + _spec.Assign = _node.assignValues + _spec.ScanValues = _node.scanValues + if err = sqlgraph.UpdateNode(ctx, icuo.driver, _spec); err != nil { + if _, ok := err.(*sqlgraph.NotFoundError); ok { + err = &NotFoundError{invitationcode.Label} + } else if sqlgraph.IsConstraintError(err) { + err = &ConstraintError{msg: err.Error(), wrap: err} + } + return nil, err + } + icuo.mutation.done = true + return _node, nil +} diff --git a/ent/migrate/schema.go b/ent/migrate/schema.go index 801465be..cb5031ba 100644 --- a/ent/migrate/schema.go +++ b/ent/migrate/schema.go @@ -216,6 +216,24 @@ var ( }, }, } + // InvitationCodesColumns holds the columns for the "invitation_codes" table. + InvitationCodesColumns = []*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: "code", Type: field.TypeString, Unique: true, Size: 64}, + {Name: "group_id", Type: field.TypeInt, Default: 0}, + {Name: "max_uses", Type: field.TypeInt, Default: 1}, + {Name: "used_count", Type: field.TypeInt, Default: 0}, + {Name: "expires_at", Type: field.TypeTime, Nullable: true}, + } + // InvitationCodesTable holds the schema information for the "invitation_codes" table. + InvitationCodesTable = &schema.Table{ + Name: "invitation_codes", + Columns: InvitationCodesColumns, + PrimaryKey: []*schema.Column{InvitationCodesColumns[0]}, + } // MetadataColumns holds the columns for the "metadata" table. MetadataColumns = []*schema.Column{ {Name: "id", Type: field.TypeInt, Increment: true}, @@ -540,6 +558,7 @@ var ( FilesTable, FsEventsTable, GroupsTable, + InvitationCodesTable, MetadataTable, NodesTable, OauthClientsTable, diff --git a/ent/mutation.go b/ent/mutation.go index f17115aa..46ef5404 100644 --- a/ent/mutation.go +++ b/ent/mutation.go @@ -17,6 +17,7 @@ import ( "github.com/cloudreve/Cloudreve/v4/ent/file" "github.com/cloudreve/Cloudreve/v4/ent/fsevent" "github.com/cloudreve/Cloudreve/v4/ent/group" + "github.com/cloudreve/Cloudreve/v4/ent/invitationcode" "github.com/cloudreve/Cloudreve/v4/ent/metadata" "github.com/cloudreve/Cloudreve/v4/ent/node" "github.com/cloudreve/Cloudreve/v4/ent/oauthclient" @@ -43,22 +44,23 @@ const ( OpUpdateOne = ent.OpUpdateOne // Node types. - TypeDavAccount = "DavAccount" - TypeDirectLink = "DirectLink" - TypeEntity = "Entity" - TypeFile = "File" - TypeFsEvent = "FsEvent" - TypeGroup = "Group" - TypeMetadata = "Metadata" - TypeNode = "Node" - TypeOAuthClient = "OAuthClient" - TypeOAuthGrant = "OAuthGrant" - TypePasskey = "Passkey" - TypeSetting = "Setting" - TypeShare = "Share" - TypeStoragePolicy = "StoragePolicy" - TypeTask = "Task" - TypeUser = "User" + TypeDavAccount = "DavAccount" + TypeDirectLink = "DirectLink" + TypeEntity = "Entity" + TypeFile = "File" + TypeFsEvent = "FsEvent" + TypeGroup = "Group" + TypeInvitationCode = "InvitationCode" + TypeMetadata = "Metadata" + TypeNode = "Node" + TypeOAuthClient = "OAuthClient" + TypeOAuthGrant = "OAuthGrant" + TypePasskey = "Passkey" + TypeSetting = "Setting" + TypeShare = "Share" + TypeStoragePolicy = "StoragePolicy" + TypeTask = "Task" + TypeUser = "User" ) // DavAccountMutation represents an operation that mutates the DavAccount nodes in the graph. @@ -6393,6 +6395,853 @@ func (m *GroupMutation) ResetEdge(name string) error { return fmt.Errorf("unknown Group edge %s", name) } +// InvitationCodeMutation represents an operation that mutates the InvitationCode nodes in the graph. +type InvitationCodeMutation struct { + config + op Op + typ string + id *int + created_at *time.Time + updated_at *time.Time + deleted_at *time.Time + code *string + group_id *int + addgroup_id *int + max_uses *int + addmax_uses *int + used_count *int + addused_count *int + expires_at *time.Time + clearedFields map[string]struct{} + done bool + oldValue func(context.Context) (*InvitationCode, error) + predicates []predicate.InvitationCode +} + +var _ ent.Mutation = (*InvitationCodeMutation)(nil) + +// invitationcodeOption allows management of the mutation configuration using functional options. +type invitationcodeOption func(*InvitationCodeMutation) + +// newInvitationCodeMutation creates new mutation for the InvitationCode entity. +func newInvitationCodeMutation(c config, op Op, opts ...invitationcodeOption) *InvitationCodeMutation { + m := &InvitationCodeMutation{ + config: c, + op: op, + typ: TypeInvitationCode, + clearedFields: make(map[string]struct{}), + } + for _, opt := range opts { + opt(m) + } + return m +} + +// withInvitationCodeID sets the ID field of the mutation. +func withInvitationCodeID(id int) invitationcodeOption { + return func(m *InvitationCodeMutation) { + var ( + err error + once sync.Once + value *InvitationCode + ) + m.oldValue = func(ctx context.Context) (*InvitationCode, error) { + once.Do(func() { + if m.done { + err = errors.New("querying old values post mutation is not allowed") + } else { + value, err = m.Client().InvitationCode.Get(ctx, id) + } + }) + return value, err + } + m.id = &id + } +} + +// withInvitationCode sets the old InvitationCode of the mutation. +func withInvitationCode(node *InvitationCode) invitationcodeOption { + return func(m *InvitationCodeMutation) { + m.oldValue = func(context.Context) (*InvitationCode, 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 InvitationCodeMutation) 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 InvitationCodeMutation) 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 *InvitationCodeMutation) 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 *InvitationCodeMutation) 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().InvitationCode.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 *InvitationCodeMutation) SetCreatedAt(t time.Time) { + m.created_at = &t +} + +// CreatedAt returns the value of the "created_at" field in the mutation. +func (m *InvitationCodeMutation) 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 InvitationCode entity. +// If the InvitationCode 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 *InvitationCodeMutation) 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 *InvitationCodeMutation) ResetCreatedAt() { + m.created_at = nil +} + +// SetUpdatedAt sets the "updated_at" field. +func (m *InvitationCodeMutation) SetUpdatedAt(t time.Time) { + m.updated_at = &t +} + +// UpdatedAt returns the value of the "updated_at" field in the mutation. +func (m *InvitationCodeMutation) 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 InvitationCode entity. +// If the InvitationCode 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 *InvitationCodeMutation) 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 *InvitationCodeMutation) ResetUpdatedAt() { + m.updated_at = nil +} + +// SetDeletedAt sets the "deleted_at" field. +func (m *InvitationCodeMutation) SetDeletedAt(t time.Time) { + m.deleted_at = &t +} + +// DeletedAt returns the value of the "deleted_at" field in the mutation. +func (m *InvitationCodeMutation) 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 InvitationCode entity. +// If the InvitationCode 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 *InvitationCodeMutation) 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 *InvitationCodeMutation) ClearDeletedAt() { + m.deleted_at = nil + m.clearedFields[invitationcode.FieldDeletedAt] = struct{}{} +} + +// DeletedAtCleared returns if the "deleted_at" field was cleared in this mutation. +func (m *InvitationCodeMutation) DeletedAtCleared() bool { + _, ok := m.clearedFields[invitationcode.FieldDeletedAt] + return ok +} + +// ResetDeletedAt resets all changes to the "deleted_at" field. +func (m *InvitationCodeMutation) ResetDeletedAt() { + m.deleted_at = nil + delete(m.clearedFields, invitationcode.FieldDeletedAt) +} + +// SetCode sets the "code" field. +func (m *InvitationCodeMutation) SetCode(s string) { + m.code = &s +} + +// Code returns the value of the "code" field in the mutation. +func (m *InvitationCodeMutation) Code() (r string, exists bool) { + v := m.code + if v == nil { + return + } + return *v, true +} + +// OldCode returns the old "code" field's value of the InvitationCode entity. +// If the InvitationCode 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 *InvitationCodeMutation) OldCode(ctx context.Context) (v string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldCode is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldCode requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldCode: %w", err) + } + return oldValue.Code, nil +} + +// ResetCode resets all changes to the "code" field. +func (m *InvitationCodeMutation) ResetCode() { + m.code = nil +} + +// SetGroupID sets the "group_id" field. +func (m *InvitationCodeMutation) SetGroupID(i int) { + m.group_id = &i + m.addgroup_id = nil +} + +// GroupID returns the value of the "group_id" field in the mutation. +func (m *InvitationCodeMutation) GroupID() (r int, exists bool) { + v := m.group_id + if v == nil { + return + } + return *v, true +} + +// OldGroupID returns the old "group_id" field's value of the InvitationCode entity. +// If the InvitationCode 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 *InvitationCodeMutation) OldGroupID(ctx context.Context) (v int, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldGroupID is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldGroupID requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldGroupID: %w", err) + } + return oldValue.GroupID, nil +} + +// AddGroupID adds i to the "group_id" field. +func (m *InvitationCodeMutation) AddGroupID(i int) { + if m.addgroup_id != nil { + *m.addgroup_id += i + } else { + m.addgroup_id = &i + } +} + +// AddedGroupID returns the value that was added to the "group_id" field in this mutation. +func (m *InvitationCodeMutation) AddedGroupID() (r int, exists bool) { + v := m.addgroup_id + if v == nil { + return + } + return *v, true +} + +// ResetGroupID resets all changes to the "group_id" field. +func (m *InvitationCodeMutation) ResetGroupID() { + m.group_id = nil + m.addgroup_id = nil +} + +// SetMaxUses sets the "max_uses" field. +func (m *InvitationCodeMutation) SetMaxUses(i int) { + m.max_uses = &i + m.addmax_uses = nil +} + +// MaxUses returns the value of the "max_uses" field in the mutation. +func (m *InvitationCodeMutation) MaxUses() (r int, exists bool) { + v := m.max_uses + if v == nil { + return + } + return *v, true +} + +// OldMaxUses returns the old "max_uses" field's value of the InvitationCode entity. +// If the InvitationCode 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 *InvitationCodeMutation) OldMaxUses(ctx context.Context) (v int, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldMaxUses is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldMaxUses requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldMaxUses: %w", err) + } + return oldValue.MaxUses, nil +} + +// AddMaxUses adds i to the "max_uses" field. +func (m *InvitationCodeMutation) AddMaxUses(i int) { + if m.addmax_uses != nil { + *m.addmax_uses += i + } else { + m.addmax_uses = &i + } +} + +// AddedMaxUses returns the value that was added to the "max_uses" field in this mutation. +func (m *InvitationCodeMutation) AddedMaxUses() (r int, exists bool) { + v := m.addmax_uses + if v == nil { + return + } + return *v, true +} + +// ResetMaxUses resets all changes to the "max_uses" field. +func (m *InvitationCodeMutation) ResetMaxUses() { + m.max_uses = nil + m.addmax_uses = nil +} + +// SetUsedCount sets the "used_count" field. +func (m *InvitationCodeMutation) SetUsedCount(i int) { + m.used_count = &i + m.addused_count = nil +} + +// UsedCount returns the value of the "used_count" field in the mutation. +func (m *InvitationCodeMutation) UsedCount() (r int, exists bool) { + v := m.used_count + if v == nil { + return + } + return *v, true +} + +// OldUsedCount returns the old "used_count" field's value of the InvitationCode entity. +// If the InvitationCode 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 *InvitationCodeMutation) OldUsedCount(ctx context.Context) (v int, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldUsedCount is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldUsedCount requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldUsedCount: %w", err) + } + return oldValue.UsedCount, nil +} + +// AddUsedCount adds i to the "used_count" field. +func (m *InvitationCodeMutation) AddUsedCount(i int) { + if m.addused_count != nil { + *m.addused_count += i + } else { + m.addused_count = &i + } +} + +// AddedUsedCount returns the value that was added to the "used_count" field in this mutation. +func (m *InvitationCodeMutation) AddedUsedCount() (r int, exists bool) { + v := m.addused_count + if v == nil { + return + } + return *v, true +} + +// ResetUsedCount resets all changes to the "used_count" field. +func (m *InvitationCodeMutation) ResetUsedCount() { + m.used_count = nil + m.addused_count = nil +} + +// SetExpiresAt sets the "expires_at" field. +func (m *InvitationCodeMutation) SetExpiresAt(t time.Time) { + m.expires_at = &t +} + +// ExpiresAt returns the value of the "expires_at" field in the mutation. +func (m *InvitationCodeMutation) ExpiresAt() (r time.Time, exists bool) { + v := m.expires_at + if v == nil { + return + } + return *v, true +} + +// OldExpiresAt returns the old "expires_at" field's value of the InvitationCode entity. +// If the InvitationCode 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 *InvitationCodeMutation) OldExpiresAt(ctx context.Context) (v *time.Time, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldExpiresAt is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldExpiresAt requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldExpiresAt: %w", err) + } + return oldValue.ExpiresAt, nil +} + +// ClearExpiresAt clears the value of the "expires_at" field. +func (m *InvitationCodeMutation) ClearExpiresAt() { + m.expires_at = nil + m.clearedFields[invitationcode.FieldExpiresAt] = struct{}{} +} + +// ExpiresAtCleared returns if the "expires_at" field was cleared in this mutation. +func (m *InvitationCodeMutation) ExpiresAtCleared() bool { + _, ok := m.clearedFields[invitationcode.FieldExpiresAt] + return ok +} + +// ResetExpiresAt resets all changes to the "expires_at" field. +func (m *InvitationCodeMutation) ResetExpiresAt() { + m.expires_at = nil + delete(m.clearedFields, invitationcode.FieldExpiresAt) +} + +// Where appends a list predicates to the InvitationCodeMutation builder. +func (m *InvitationCodeMutation) Where(ps ...predicate.InvitationCode) { + m.predicates = append(m.predicates, ps...) +} + +// WhereP appends storage-level predicates to the InvitationCodeMutation builder. Using this method, +// users can use type-assertion to append predicates that do not depend on any generated package. +func (m *InvitationCodeMutation) WhereP(ps ...func(*sql.Selector)) { + p := make([]predicate.InvitationCode, len(ps)) + for i := range ps { + p[i] = ps[i] + } + m.Where(p...) +} + +// Op returns the operation name. +func (m *InvitationCodeMutation) Op() Op { + return m.op +} + +// SetOp allows setting the mutation operation. +func (m *InvitationCodeMutation) SetOp(op Op) { + m.op = op +} + +// Type returns the node type of this mutation (InvitationCode). +func (m *InvitationCodeMutation) 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 *InvitationCodeMutation) Fields() []string { + fields := make([]string, 0, 8) + if m.created_at != nil { + fields = append(fields, invitationcode.FieldCreatedAt) + } + if m.updated_at != nil { + fields = append(fields, invitationcode.FieldUpdatedAt) + } + if m.deleted_at != nil { + fields = append(fields, invitationcode.FieldDeletedAt) + } + if m.code != nil { + fields = append(fields, invitationcode.FieldCode) + } + if m.group_id != nil { + fields = append(fields, invitationcode.FieldGroupID) + } + if m.max_uses != nil { + fields = append(fields, invitationcode.FieldMaxUses) + } + if m.used_count != nil { + fields = append(fields, invitationcode.FieldUsedCount) + } + if m.expires_at != nil { + fields = append(fields, invitationcode.FieldExpiresAt) + } + 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 *InvitationCodeMutation) Field(name string) (ent.Value, bool) { + switch name { + case invitationcode.FieldCreatedAt: + return m.CreatedAt() + case invitationcode.FieldUpdatedAt: + return m.UpdatedAt() + case invitationcode.FieldDeletedAt: + return m.DeletedAt() + case invitationcode.FieldCode: + return m.Code() + case invitationcode.FieldGroupID: + return m.GroupID() + case invitationcode.FieldMaxUses: + return m.MaxUses() + case invitationcode.FieldUsedCount: + return m.UsedCount() + case invitationcode.FieldExpiresAt: + return m.ExpiresAt() + } + 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 *InvitationCodeMutation) OldField(ctx context.Context, name string) (ent.Value, error) { + switch name { + case invitationcode.FieldCreatedAt: + return m.OldCreatedAt(ctx) + case invitationcode.FieldUpdatedAt: + return m.OldUpdatedAt(ctx) + case invitationcode.FieldDeletedAt: + return m.OldDeletedAt(ctx) + case invitationcode.FieldCode: + return m.OldCode(ctx) + case invitationcode.FieldGroupID: + return m.OldGroupID(ctx) + case invitationcode.FieldMaxUses: + return m.OldMaxUses(ctx) + case invitationcode.FieldUsedCount: + return m.OldUsedCount(ctx) + case invitationcode.FieldExpiresAt: + return m.OldExpiresAt(ctx) + } + return nil, fmt.Errorf("unknown InvitationCode 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 *InvitationCodeMutation) SetField(name string, value ent.Value) error { + switch name { + case invitationcode.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 invitationcode.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 invitationcode.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 invitationcode.FieldCode: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetCode(v) + return nil + case invitationcode.FieldGroupID: + v, ok := value.(int) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetGroupID(v) + return nil + case invitationcode.FieldMaxUses: + v, ok := value.(int) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetMaxUses(v) + return nil + case invitationcode.FieldUsedCount: + v, ok := value.(int) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetUsedCount(v) + return nil + case invitationcode.FieldExpiresAt: + v, ok := value.(time.Time) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetExpiresAt(v) + return nil + } + return fmt.Errorf("unknown InvitationCode field %s", name) +} + +// AddedFields returns all numeric fields that were incremented/decremented during +// this mutation. +func (m *InvitationCodeMutation) AddedFields() []string { + var fields []string + if m.addgroup_id != nil { + fields = append(fields, invitationcode.FieldGroupID) + } + if m.addmax_uses != nil { + fields = append(fields, invitationcode.FieldMaxUses) + } + if m.addused_count != nil { + fields = append(fields, invitationcode.FieldUsedCount) + } + 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 *InvitationCodeMutation) AddedField(name string) (ent.Value, bool) { + switch name { + case invitationcode.FieldGroupID: + return m.AddedGroupID() + case invitationcode.FieldMaxUses: + return m.AddedMaxUses() + case invitationcode.FieldUsedCount: + return m.AddedUsedCount() + } + 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 *InvitationCodeMutation) AddField(name string, value ent.Value) error { + switch name { + case invitationcode.FieldGroupID: + v, ok := value.(int) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.AddGroupID(v) + return nil + case invitationcode.FieldMaxUses: + v, ok := value.(int) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.AddMaxUses(v) + return nil + case invitationcode.FieldUsedCount: + v, ok := value.(int) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.AddUsedCount(v) + return nil + } + return fmt.Errorf("unknown InvitationCode numeric field %s", name) +} + +// ClearedFields returns all nullable fields that were cleared during this +// mutation. +func (m *InvitationCodeMutation) ClearedFields() []string { + var fields []string + if m.FieldCleared(invitationcode.FieldDeletedAt) { + fields = append(fields, invitationcode.FieldDeletedAt) + } + if m.FieldCleared(invitationcode.FieldExpiresAt) { + fields = append(fields, invitationcode.FieldExpiresAt) + } + return fields +} + +// FieldCleared returns a boolean indicating if a field with the given name was +// cleared in this mutation. +func (m *InvitationCodeMutation) 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 *InvitationCodeMutation) ClearField(name string) error { + switch name { + case invitationcode.FieldDeletedAt: + m.ClearDeletedAt() + return nil + case invitationcode.FieldExpiresAt: + m.ClearExpiresAt() + return nil + } + return fmt.Errorf("unknown InvitationCode 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 *InvitationCodeMutation) ResetField(name string) error { + switch name { + case invitationcode.FieldCreatedAt: + m.ResetCreatedAt() + return nil + case invitationcode.FieldUpdatedAt: + m.ResetUpdatedAt() + return nil + case invitationcode.FieldDeletedAt: + m.ResetDeletedAt() + return nil + case invitationcode.FieldCode: + m.ResetCode() + return nil + case invitationcode.FieldGroupID: + m.ResetGroupID() + return nil + case invitationcode.FieldMaxUses: + m.ResetMaxUses() + return nil + case invitationcode.FieldUsedCount: + m.ResetUsedCount() + return nil + case invitationcode.FieldExpiresAt: + m.ResetExpiresAt() + return nil + } + return fmt.Errorf("unknown InvitationCode field %s", name) +} + +// AddedEdges returns all edge names that were set/added in this mutation. +func (m *InvitationCodeMutation) 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 *InvitationCodeMutation) AddedIDs(name string) []ent.Value { + return nil +} + +// RemovedEdges returns all edge names that were removed in this mutation. +func (m *InvitationCodeMutation) 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 *InvitationCodeMutation) RemovedIDs(name string) []ent.Value { + return nil +} + +// ClearedEdges returns all edge names that were cleared in this mutation. +func (m *InvitationCodeMutation) 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 *InvitationCodeMutation) 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 *InvitationCodeMutation) ClearEdge(name string) error { + return fmt.Errorf("unknown InvitationCode 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 *InvitationCodeMutation) ResetEdge(name string) error { + return fmt.Errorf("unknown InvitationCode edge %s", name) +} + // MetadataMutation represents an operation that mutates the Metadata nodes in the graph. type MetadataMutation struct { config diff --git a/ent/mutationhelper.go b/ent/mutationhelper.go index 2361bddf..08964da8 100644 --- a/ent/mutationhelper.go +++ b/ent/mutationhelper.go @@ -40,6 +40,12 @@ func (m *GroupMutation) SetRawID(t int) { // SetUpdatedAt sets the "updated_at" field. +func (m *InvitationCodeMutation) SetRawID(t int) { + m.id = &t +} + +// SetUpdatedAt sets the "updated_at" field. + func (m *MetadataMutation) SetRawID(t int) { m.id = &t } diff --git a/ent/predicate/predicate.go b/ent/predicate/predicate.go index d258dac0..dc8b3716 100644 --- a/ent/predicate/predicate.go +++ b/ent/predicate/predicate.go @@ -24,6 +24,9 @@ type FsEvent func(*sql.Selector) // Group is the predicate function for group builders. type Group func(*sql.Selector) +// InvitationCode is the predicate function for invitationcode builders. +type InvitationCode func(*sql.Selector) + // Metadata is the predicate function for metadata builders. type Metadata func(*sql.Selector) diff --git a/ent/runtime/runtime.go b/ent/runtime/runtime.go index 3ccbbb8b..34e079c7 100644 --- a/ent/runtime/runtime.go +++ b/ent/runtime/runtime.go @@ -11,6 +11,7 @@ import ( "github.com/cloudreve/Cloudreve/v4/ent/file" "github.com/cloudreve/Cloudreve/v4/ent/fsevent" "github.com/cloudreve/Cloudreve/v4/ent/group" + "github.com/cloudreve/Cloudreve/v4/ent/invitationcode" "github.com/cloudreve/Cloudreve/v4/ent/metadata" "github.com/cloudreve/Cloudreve/v4/ent/node" "github.com/cloudreve/Cloudreve/v4/ent/oauthclient" @@ -152,6 +153,41 @@ func init() { groupDescSettings := groupFields[4].Descriptor() // group.DefaultSettings holds the default value on creation for the settings field. group.DefaultSettings = groupDescSettings.Default.(*types.GroupSetting) + invitationcodeMixin := schema.InvitationCode{}.Mixin() + invitationcodeMixinHooks0 := invitationcodeMixin[0].Hooks() + invitationcode.Hooks[0] = invitationcodeMixinHooks0[0] + invitationcodeMixinInters0 := invitationcodeMixin[0].Interceptors() + invitationcode.Interceptors[0] = invitationcodeMixinInters0[0] + invitationcodeMixinFields0 := invitationcodeMixin[0].Fields() + _ = invitationcodeMixinFields0 + invitationcodeFields := schema.InvitationCode{}.Fields() + _ = invitationcodeFields + // invitationcodeDescCreatedAt is the schema descriptor for created_at field. + invitationcodeDescCreatedAt := invitationcodeMixinFields0[0].Descriptor() + // invitationcode.DefaultCreatedAt holds the default value on creation for the created_at field. + invitationcode.DefaultCreatedAt = invitationcodeDescCreatedAt.Default.(func() time.Time) + // invitationcodeDescUpdatedAt is the schema descriptor for updated_at field. + invitationcodeDescUpdatedAt := invitationcodeMixinFields0[1].Descriptor() + // invitationcode.DefaultUpdatedAt holds the default value on creation for the updated_at field. + invitationcode.DefaultUpdatedAt = invitationcodeDescUpdatedAt.Default.(func() time.Time) + // invitationcode.UpdateDefaultUpdatedAt holds the default value on update for the updated_at field. + invitationcode.UpdateDefaultUpdatedAt = invitationcodeDescUpdatedAt.UpdateDefault.(func() time.Time) + // invitationcodeDescCode is the schema descriptor for code field. + invitationcodeDescCode := invitationcodeFields[0].Descriptor() + // invitationcode.CodeValidator is a validator for the "code" field. It is called by the builders before save. + invitationcode.CodeValidator = invitationcodeDescCode.Validators[0].(func(string) error) + // invitationcodeDescGroupID is the schema descriptor for group_id field. + invitationcodeDescGroupID := invitationcodeFields[1].Descriptor() + // invitationcode.DefaultGroupID holds the default value on creation for the group_id field. + invitationcode.DefaultGroupID = invitationcodeDescGroupID.Default.(int) + // invitationcodeDescMaxUses is the schema descriptor for max_uses field. + invitationcodeDescMaxUses := invitationcodeFields[2].Descriptor() + // invitationcode.DefaultMaxUses holds the default value on creation for the max_uses field. + invitationcode.DefaultMaxUses = invitationcodeDescMaxUses.Default.(int) + // invitationcodeDescUsedCount is the schema descriptor for used_count field. + invitationcodeDescUsedCount := invitationcodeFields[3].Descriptor() + // invitationcode.DefaultUsedCount holds the default value on creation for the used_count field. + invitationcode.DefaultUsedCount = invitationcodeDescUsedCount.Default.(int) metadataMixin := schema.Metadata{}.Mixin() metadataMixinHooks0 := metadataMixin[0].Hooks() metadata.Hooks[0] = metadataMixinHooks0[0] diff --git a/ent/schema/invitationcode.go b/ent/schema/invitationcode.go new file mode 100644 index 00000000..4bee8100 --- /dev/null +++ b/ent/schema/invitationcode.go @@ -0,0 +1,37 @@ +package schema + +import ( + "entgo.io/ent" + "entgo.io/ent/schema/field" +) + +// InvitationCode holds the schema definition for invitation codes that can +// gate public registration. +type InvitationCode struct { + ent.Schema +} + +func (InvitationCode) Fields() []ent.Field { + return []ent.Field{ + field.String("code"). + MaxLen(64). + Unique(), + // group_id assigns new users to this group; 0 means the default group. + field.Int("group_id"). + Default(0), + // max_uses limits how many accounts the code can create; 0 = unlimited. + field.Int("max_uses"). + Default(1), + field.Int("used_count"). + Default(0), + field.Time("expires_at"). + Optional(). + Nillable(), + } +} + +func (InvitationCode) Mixin() []ent.Mixin { + return []ent.Mixin{ + CommonMixin{}, + } +} diff --git a/ent/tx.go b/ent/tx.go index 9d71651a..8d6aa9da 100644 --- a/ent/tx.go +++ b/ent/tx.go @@ -26,6 +26,8 @@ type Tx struct { FsEvent *FsEventClient // Group is the client for interacting with the Group builders. Group *GroupClient + // InvitationCode is the client for interacting with the InvitationCode builders. + InvitationCode *InvitationCodeClient // Metadata is the client for interacting with the Metadata builders. Metadata *MetadataClient // Node is the client for interacting with the Node builders. @@ -183,6 +185,7 @@ func (tx *Tx) init() { tx.File = NewFileClient(tx.config) tx.FsEvent = NewFsEventClient(tx.config) tx.Group = NewGroupClient(tx.config) + tx.InvitationCode = NewInvitationCodeClient(tx.config) tx.Metadata = NewMetadataClient(tx.config) tx.Node = NewNodeClient(tx.config) tx.OAuthClient = NewOAuthClientClient(tx.config) diff --git a/frontend/public/locales/en-US/application.json b/frontend/public/locales/en-US/application.json index 144447ff..7d5b97f8 100644 --- a/frontend/public/locales/en-US/application.json +++ b/frontend/public/locales/en-US/application.json @@ -33,6 +33,7 @@ "newPassword": "New password", "repeatNewPassword": "Repeat the new password", "repeatPassword": "Repeat the password", + "invitationCode": "Invitation code", "resetPassword": "Reset my password", "backToSingIn": "Back to sign in", "sendMeAnEmail": "Send me an email", diff --git a/frontend/public/locales/en-US/dashboard.json b/frontend/public/locales/en-US/dashboard.json index ffc04805..7ef72f58 100644 --- a/frontend/public/locales/en-US/dashboard.json +++ b/frontend/public/locales/en-US/dashboard.json @@ -399,6 +399,8 @@ "accountManagement": "Accounts", "allowNewRegistrations": "Accept new signups", "allowNewRegistrationsDes": "After disabled, no new users can be registered, unless manually added by admins.", + "invitationCodeRequired": "Require invitation code", + "invitationCodeRequiredDes": "New signups must provide a valid invitation code. Codes are managed under Users - Invitation codes.", "emailActivation": "Email activation", "emailActivationDes": "After enabled, new users need to click the activation link in the email to complete signups. Please make sure the <0>email delivery settings are correct, otherwise the activation email will not be delivered.", "captchaForSignup": "Captcha for signups", @@ -1428,7 +1430,22 @@ "uidsPlaceholder": "Comma-separated IDs, e.g. 2,3,5", "editXUsers": "Edit {{num}} users", "batchEditXUsers": "Batch edit {{num}} users", - "noChange": "No change" + "noChange": "No change", + "invitationCodes": "Invitation codes", + "invitationCodesDes": "Codes that can be required for public signups. Create, share and revoke them here.", + "invitationCode": "Code", + "invitationCodeAuto": "Auto-generate", + "invitationCodeGroup": "Group", + "invitationCodeMaxUses": "Max uses", + "invitationCodeExpires": "Expires at", + "invitationCodeUses": "Uses", + "invitationCodeCreated": "Invitation code created.", + "invitationCodeCopied": "Code copied to clipboard.", + "invitationCodeCopy": "Copy", + "invitationCodeDefaultGroup": "Default", + "noInvitationCodes": "No invitation codes yet.", + "loadMore": "Load more", + "createdAt": "Created at" }, "file": { "deleteXFiles": "Delete {{num}} files", diff --git a/frontend/public/locales/zh-CN/application.json b/frontend/public/locales/zh-CN/application.json index 1f0a4fc7..dae65b0b 100644 --- a/frontend/public/locales/zh-CN/application.json +++ b/frontend/public/locales/zh-CN/application.json @@ -33,6 +33,7 @@ "newPassword": "新密码", "repeatNewPassword": "重复新密码", "repeatPassword": "重复密码", + "invitationCode": "邀请码", "resetPassword": "重设密码", "backToSingIn": "返回登录", "sendMeAnEmail": "发送密码重置邮件", diff --git a/frontend/public/locales/zh-CN/dashboard.json b/frontend/public/locales/zh-CN/dashboard.json index 98e9982f..acda0f37 100644 --- a/frontend/public/locales/zh-CN/dashboard.json +++ b/frontend/public/locales/zh-CN/dashboard.json @@ -399,6 +399,8 @@ "accountManagement": "注册与登录", "allowNewRegistrations": "允许新用户注册", "allowNewRegistrationsDes": "关闭后,无法再通过前台注册新的用户。", + "invitationCodeRequired": "需要邀请码", + "invitationCodeRequiredDes": "开启后,新用户注册必须提供有效的邀请码。邀请码可在 用户 - 邀请码 中管理。", "emailActivation": "邮件激活", "emailActivationDes": "开启后,新用户注册需要点击邮件中的激活链接才能完成。请确认 <0>邮件发信设置 是否正确,否则激活邮件无法送达。", "captchaForSignup": "注册验证码", @@ -1428,7 +1430,22 @@ "uidsPlaceholder": "逗号分隔的 ID,如 2,3,5", "editXUsers": "编辑 {{num}} 个用户", "batchEditXUsers": "批量编辑 {{num}} 个用户", - "noChange": "不修改" + "noChange": "不修改", + "invitationCodes": "邀请码", + "invitationCodesDes": "用于前台注册的邀请码。可在此创建、分享和吊销。", + "invitationCode": "邀请码", + "invitationCodeAuto": "自动生成", + "invitationCodeGroup": "用户组", + "invitationCodeMaxUses": "最大使用次数", + "invitationCodeExpires": "过期时间", + "invitationCodeUses": "使用次数", + "invitationCodeCreated": "邀请码已创建。", + "invitationCodeCopied": "邀请码已复制到剪贴板。", + "invitationCodeCopy": "复制", + "invitationCodeDefaultGroup": "默认组", + "noInvitationCodes": "暂无邀请码。", + "loadMore": "加载更多", + "createdAt": "创建时间" }, "file": { "deleteXFiles": "删除 {{num}} 个文件", diff --git a/frontend/src/api/api.ts b/frontend/src/api/api.ts index 2c820e65..0affced9 100644 --- a/frontend/src/api/api.ts +++ b/frontend/src/api/api.ts @@ -1918,6 +1918,77 @@ export function batchUpdateUser(args: BatchUserUpdateService): ThunkResponse { + return async (dispatch, _getState) => { + return await dispatch( + send( + `/admin/user/invitation/list`, + { method: "POST", data: args }, + { + ...defaultOpts, + }, + ), + ); + }; +} + +export function createInvitationCode(args: CreateInvitationCodeService): ThunkResponse { + return async (dispatch, _getState) => { + return await dispatch( + send( + `/admin/user/invitation`, + { method: "PUT", data: args }, + { + ...defaultOpts, + }, + ), + ); + }; +} + +export function deleteInvitationCode(id: number): ThunkResponse { + return async (dispatch, _getState) => { + return await dispatch( + send( + `/admin/user/invitation/${id}`, + { method: "DELETE" }, + { + ...defaultOpts, + }, + ), + ); + }; +} + export function getFlattenFileList(args: AdminListService): ThunkResponse { return async (dispatch, _getState) => { return await dispatch( diff --git a/frontend/src/api/site.ts b/frontend/src/api/site.ts index 70ce8214..a3d57804 100644 --- a/frontend/src/api/site.ts +++ b/frontend/src/api/site.ts @@ -28,6 +28,7 @@ export interface SiteConfig { captcha_cap_secret_key?: string; captcha_cap_asset_server?: string; register_enabled?: boolean; + invitation_code?: boolean; sso_enabled?: boolean; sso_display_name?: string; sso_auto_redirect?: boolean; diff --git a/frontend/src/api/user.ts b/frontend/src/api/user.ts index 8dfc65e3..c7caa780 100644 --- a/frontend/src/api/user.ts +++ b/frontend/src/api/user.ts @@ -239,6 +239,7 @@ export interface SignUpService extends CaptchaRequest { email: string; password: string; language: string; + invite_code?: string; } export interface SendResetEmailService extends CaptchaRequest { diff --git a/frontend/src/component/Admin/Settings/Settings.tsx b/frontend/src/component/Admin/Settings/Settings.tsx index d26f7cdf..377632f1 100644 --- a/frontend/src/component/Admin/Settings/Settings.tsx +++ b/frontend/src/component/Admin/Settings/Settings.tsx @@ -184,6 +184,7 @@ const Settings = () => { { {t("settings.allowNewRegistrationsDes")} + {isTrueVal(values.register_enabled) && ( + + + + setSettings({ + invitation_code_required: e.target.checked ? "1" : "0", + }) + } + /> + } + label={t("settings.invitationCodeRequired")} + /> + {t("settings.invitationCodeRequiredDes")} + + + )} void; +} + +const InvitationCodeDialog = ({ open, onClose }: InvitationCodeDialogProps) => { + const { t } = useTranslation("dashboard"); + const dispatch = useAppDispatch(); + const { enqueueSnackbar } = useSnackbar(); + + const [codes, setCodes] = useState([]); + const [nextToken, setNextToken] = useState(""); + const [loading, setLoading] = useState(false); + const [creating, setCreating] = useState(false); + + const [code, setCode] = useState(""); + const [groupId, setGroupId] = useState(""); + const [maxUses, setMaxUses] = useState("1"); + const [expiresAt, setExpiresAt] = useState(""); + + const fetchCodes = useCallback( + (token?: string) => { + setLoading(true); + dispatch(listInvitationCodes({ page_size: 20, page_token: token })) + .then((res) => { + setCodes((prev) => (token ? [...prev, ...res.codes] : res.codes)); + setNextToken(res.pagination.next_token ?? ""); + }) + .finally(() => setLoading(false)); + }, + [dispatch], + ); + + useEffect(() => { + if (open) { + setCodes([]); + setCode(""); + setGroupId(""); + setMaxUses("1"); + setExpiresAt(""); + fetchCodes(); + } + }, [open, fetchCodes]); + + const handleCreate = () => { + setCreating(true); + dispatch( + createInvitationCode({ + code: code || undefined, + group_id: groupId ? parseInt(groupId) : undefined, + max_uses: maxUses ? parseInt(maxUses) : undefined, + expires_at: expiresAt ? new Date(expiresAt).toISOString() : undefined, + }), + ) + .then(() => { + setCode(""); + fetchCodes(); + enqueueSnackbar({ message: t("user.invitationCodeCreated"), variant: "success", action: DefaultCloseAction }); + }) + .finally(() => setCreating(false)); + }; + + const handleDelete = (id: number) => { + dispatch(deleteInvitationCode(id)).then(() => fetchCodes()); + }; + + const handleCopy = (value: string) => { + navigator.clipboard.writeText(value); + enqueueSnackbar({ message: t("user.invitationCodeCopied"), variant: "success", action: DefaultCloseAction }); + }; + + const formatDate = (value?: string) => (value ? new Date(value).toLocaleString() : "-"); + + return ( + + + + + {t("user.invitationCodesDes")} + + + + setCode(e.target.value)} + /> + + + + + + setMaxUses(e.target.value)} + /> + + + setExpiresAt(e.target.value)} + /> + + + + + + + + } onClick={() => fetchCodes()} disabled={loading}> + {t("node.refresh")} + + + + + + + + {t("user.invitationCode")} + {t("user.group")} + {t("user.invitationCodeUses")} + {t("user.invitationCodeExpires")} + {t("user.createdAt")} + + + + + {codes.map((c) => { + const expired = !!c.expires_at && new Date(c.expires_at) < new Date(); + const exhausted = c.max_uses > 0 && c.used_count >= c.max_uses; + return ( + + + + + {c.code} + + + handleCopy(c.code)}> + + + + + + {c.group_id > 0 ? c.group_id : t("user.invitationCodeDefaultGroup")} + + {c.used_count}/{c.max_uses > 0 ? c.max_uses : "∞"} + + {formatDate(c.expires_at)} + {formatDate(c.created_at)} + + handleDelete(c.id)}> + + + + + ); + })} + {codes.length === 0 && !loading && ( + + + + {t("user.noInvitationCodes")} + + + + )} + +
+
+ {nextToken && ( + + fetchCodes(nextToken)} disabled={loading}> + {t("user.loadMore")} + + + )} +
+
+
+ ); +}; + +export default InvitationCodeDialog; diff --git a/frontend/src/component/Admin/User/UserSetting.tsx b/frontend/src/component/Admin/User/UserSetting.tsx index 4360aab5..0ec8e974 100644 --- a/frontend/src/component/Admin/User/UserSetting.tsx +++ b/frontend/src/component/Admin/User/UserSetting.tsx @@ -34,6 +34,7 @@ import PageHeader from "../../Pages/PageHeader"; import TablePagination from "../Common/TablePagination"; import { OrderByQuery, OrderDirectionQuery, PageQuery, PageSizeQuery } from "../StoragePolicy/StoragePolicySetting"; import BatchUserDialog from "./BatchUserDialog"; +import InvitationCodeDialog from "./InvitationCodeDialog"; import NewUserDialog from "./NewUserDialog"; import UserDialog from "./UserDialog/UserDialog"; import UserFilterPopover from "./UserFilterPopover"; @@ -68,6 +69,7 @@ const UserSetting = () => { const [selected, setSelected] = useState([]); const [createNewOpen, setCreateNewOpen] = useState(false); const [batchEditOpen, setBatchEditOpen] = useState(false); + const [invitationOpen, setInvitationOpen] = useState(false); const filterPopupState = usePopupState({ variant: "popover", popupId: "userFilterPopover", @@ -205,6 +207,7 @@ const UserSetting = () => { ids={Array.from(selected)} onUpdated={() => fetchUsers()} /> + setInvitationOpen(false)} /> @@ -212,6 +215,10 @@ const UserSetting = () => { {t("group.create")} + setInvitationOpen(true)}> + {t("user.invitationCodes")} + + = { const SignUp = () => { const { t } = useTranslation(); - const { reg_captcha } = useAppSelector((state) => state.siteConfig.login.config); + const { reg_captcha, invitation_code } = useAppSelector((state) => state.siteConfig.login.config); const tos = useAppSelector((state) => state.siteConfig.login.config.tos_url); const privacyPolicy = useAppSelector((state) => state.siteConfig.login.config.privacy_policy_url); const navigate = useNavigate(); @@ -52,6 +53,7 @@ const SignUp = () => { const [email, setEmail] = useState(""); const [password, setPassword] = useState(""); const [passwordRepeat, setPasswordRepeat] = useState(""); + const [inviteCode, setInviteCode] = useState(""); const [captchaGen, setCaptchaGen] = useState(0); const captchaState = useRef(); const [loading, setLoading] = useState(false); @@ -89,6 +91,7 @@ const SignUp = () => { email, password, language: i18next.language, + invite_code: inviteCode || undefined, ...captchaState.current, }), ) @@ -206,6 +209,23 @@ const SignUp = () => { autoComplete={"false"} />
+ {invitation_code && ( + + setInviteCode(e.target.value)} + icon={} + value={inviteCode} + /> + + )} {reg_captcha && ( 0 && record.UsedCount >= record.MaxUses { + return nil, ErrInvitationCodeExhausted + } + + // Guarded increment keeps concurrent registrations honest: only one can win + // the last remaining use. + affected, err := c.client.InvitationCode.Update(). + Where( + invitationcode.ID(record.ID), + invitationcode.Or( + invitationcode.ExpiresAtIsNil(), + invitationcode.ExpiresAtGT(time.Now()), + ), + invitationcode.Or( + invitationcode.MaxUsesEQ(0), + invitationcode.UsedCountLT(record.MaxUses), + ), + ). + AddUsedCount(1). + Save(ctx) + if err != nil { + return nil, err + } + if affected == 0 { + return nil, ErrInvitationCodeExhausted + } + + return record, nil +} + +func (c *invitationCodeClient) List(ctx context.Context, args *ListInvitationCodeArgs) (*ListInvitationCodeResult, error) { + query := c.client.InvitationCode.Query() + if args.Keyword != "" { + query.Where(invitationcode.CodeContainsFold(args.Keyword)) + } + query.Order(invitationcode.ByID(sql.OrderDesc())) + + pageSize := capPageSize(c.maxSQlParam, args.PageSize, 10) + var pageToken *PageToken + if args.PageToken != "" { + var err error + pageToken, err = pageTokenFromString(args.PageToken, c.hasher, hashid.InvitationCodeID) + if err != nil { + return nil, fmt.Errorf("invalid page token %q: %w", args.PageToken, err) + } + query.Where(invitationcode.IDLT(pageToken.ID)) + } + + query.Limit(pageSize + 1) + codes, err := query.All(ctx) + if err != nil { + return nil, err + } + + nextTokenStr := "" + if len(codes) > pageSize { + nextToken, err := (&PageToken{ID: codes[len(codes)-2].ID}).Encode(c.hasher, hashid.EncodeInvitationCodeID) + if err != nil { + return nil, fmt.Errorf("failed to generate next page token: %w", err) + } + nextTokenStr = nextToken + } + + return &ListInvitationCodeResult{ + Codes: lo.Subset(codes, 0, uint(pageSize)), + PaginationResults: &PaginationResults{ + PageSize: pageSize, + NextPageToken: nextTokenStr, + IsCursor: true, + }, + }, nil +} diff --git a/pkg/hashid/hash.go b/pkg/hashid/hash.go index d3017b61..65e910ee 100644 --- a/pkg/hashid/hash.go +++ b/pkg/hashid/hash.go @@ -22,6 +22,7 @@ const ( TaskID DavAccountID PaymentID + InvitationCodeID ) var ( @@ -140,6 +141,11 @@ func EncodeSourceLinkID(encoder Encoder, id int) string { return encodeID(encoder, id, SourceLinkID) } +// EncodeInvitationCodeID encode invitation code id to hash id +func EncodeInvitationCodeID(encoder Encoder, id int) string { + return encodeID(encoder, id, InvitationCodeID) +} + func FromContext(c context.Context) int { return c.Value(ObjectIDCtx{}).(int) } diff --git a/pkg/serializer/error.go b/pkg/serializer/error.go index bccbfac5..00d2db60 100644 --- a/pkg/serializer/error.go +++ b/pkg/serializer/error.go @@ -259,6 +259,10 @@ const ( CodeInsufficientScope = 40089 // CodeRateLimited 请求频率超限 CodeRateLimited = 40090 + // CodeInvitationCodeRequired 注册需要邀请码 + CodeInvitationCodeRequired = 40091 + // CodeInvitationCodeInvalid 邀请码无效、过期或已用完 + CodeInvitationCodeInvalid = 40092 // CodeDBError 数据库操作失败 CodeDBError = 50001 // CodeEncryptError 加密失败 diff --git a/pkg/setting/provider.go b/pkg/setting/provider.go index c547f9a8..6629c0de 100644 --- a/pkg/setting/provider.go +++ b/pkg/setting/provider.go @@ -25,6 +25,8 @@ type ( PWA(ctx context.Context) *PWASetting // RegisterEnabled returns true if public sign-up is enabled. RegisterEnabled(ctx context.Context) bool + // InvitationCodeRequired returns true if registration requires an invitation code. + InvitationCodeRequired(ctx context.Context) bool // AuthnEnabled returns true if Webauthn is enabled. AuthnEnabled(ctx context.Context) bool // RegCaptchaEnabled returns true if registration captcha is enabled. @@ -881,6 +883,10 @@ func (s *settingProvider) RegisterEnabled(ctx context.Context) bool { return s.getBoolean(ctx, "register_enabled", false) } +func (s *settingProvider) InvitationCodeRequired(ctx context.Context) bool { + return s.getBoolean(ctx, "invitation_code_required", false) +} + func (s *settingProvider) SSO(ctx context.Context) *SSO { // Base scopes are always requested; sso_scopes holds extras only, so the // admin cannot break the flow by removing "openid". diff --git a/routers/controllers/admin.go b/routers/controllers/admin.go index b6d2e4a8..5424abf1 100644 --- a/routers/controllers/admin.go +++ b/routers/controllers/admin.go @@ -270,6 +270,33 @@ func AdminCreateUser(c *gin.Context) { c.JSON(200, serializer.Response{Data: res}) } +func AdminListInvitationCodes(c *gin.Context) { + service := ParametersFromContext[*admin.InvitationCodeListService](c, admin.InvitationCodeListParamCtx{}) + res, err := service.List(c) + if respondErr(c, err) { + return + } + c.JSON(200, serializer.Response{Data: res}) +} + +func AdminCreateInvitationCode(c *gin.Context) { + service := ParametersFromContext[*admin.UpsertInvitationCodeService](c, admin.UpsertInvitationCodeParamCtx{}) + res, err := service.Create(c) + if respondErr(c, err) { + return + } + c.JSON(200, serializer.Response{Data: res}) +} + +func AdminDeleteInvitationCode(c *gin.Context) { + service := ParametersFromContext[*admin.SingleInvitationCodeService](c, admin.SingleInvitationCodeParamCtx{}) + err := service.Delete(c) + if respondErr(c, err) { + return + } + c.JSON(200, serializer.Response{}) +} + // func AdminHashIDEncode(c *gin.Context) { // service := ParametersFromContext[*admin.HashIDService](c, admin.HashIDParamCtx{}) // resp, err := service.Encode(c) diff --git a/routers/router.go b/routers/router.go index 001b4225..df1c2f47 100644 --- a/routers/router.go +++ b/routers/router.go @@ -1225,6 +1225,23 @@ func initMasterRouter(dep dependency.Dep) *gin.Engine { controllers.FromUri[adminsvc.SingleUserService](adminsvc.SingleUserParamCtx{}), controllers.AdminCalibrateStorage, ) + // 列出邀请码 + user.POST("invitation/list", + controllers.FromJSON[adminsvc.InvitationCodeListService](adminsvc.InvitationCodeListParamCtx{}), + controllers.AdminListInvitationCodes, + ) + // 创建邀请码 + user.PUT("invitation", + middleware.RequiredScopes(types.ScopeAdminWrite), + controllers.FromJSON[adminsvc.UpsertInvitationCodeService](adminsvc.UpsertInvitationCodeParamCtx{}), + controllers.AdminCreateInvitationCode, + ) + // 删除邀请码 + user.DELETE("invitation/:id", + middleware.RequiredScopes(types.ScopeAdminWrite), + controllers.FromUri[adminsvc.SingleInvitationCodeService](adminsvc.SingleInvitationCodeParamCtx{}), + controllers.AdminDeleteInvitationCode, + ) } file := admin.Group("file", middleware.AdminSection(types.GroupPermissionAdminFiles)) diff --git a/service/admin/invitation.go b/service/admin/invitation.go new file mode 100644 index 00000000..9b70f663 --- /dev/null +++ b/service/admin/invitation.go @@ -0,0 +1,107 @@ +package admin + +import ( + "time" + + "github.com/cloudreve/Cloudreve/v4/application/dependency" + "github.com/cloudreve/Cloudreve/v4/ent" + "github.com/cloudreve/Cloudreve/v4/inventory" + "github.com/cloudreve/Cloudreve/v4/pkg/hashid" + "github.com/cloudreve/Cloudreve/v4/pkg/serializer" + "github.com/cloudreve/Cloudreve/v4/pkg/util" + "github.com/gin-gonic/gin" + "github.com/samber/lo" +) + +type ( + // InvitationCodeListService lists invitation codes for admins. + InvitationCodeListService struct { + Keyword string `form:"keyword" json:"keyword"` + PageSize int `form:"page_size" json:"page_size" binding:"required,min=1"` + PageToken string `form:"page_token" json:"page_token"` + } + InvitationCodeListParamCtx struct{} + + // UpsertInvitationCodeService creates an invitation code. An empty Code + // auto-generates one. + UpsertInvitationCodeService struct { + Code string `json:"code" binding:"omitempty,min=4,max=64"` + GroupID int `json:"group_id" binding:"omitempty,min=0"` + MaxUses int `json:"max_uses" binding:"omitempty,min=0"` + ExpiresAt *time.Time `json:"expires_at"` + } + UpsertInvitationCodeParamCtx struct{} + + // SingleInvitationCodeService targets one code by ID. + SingleInvitationCodeService struct { + ID int `uri:"id" json:"id" binding:"required"` + } + SingleInvitationCodeParamCtx struct{} + + InvitationCodeResponse struct { + *ent.InvitationCode + HashID string `json:"hash_id"` + } +) + +func (service *InvitationCodeListService) List(c *gin.Context) (*ListInvitationCodeResult, error) { + dep := dependency.FromContext(c) + res, err := dep.InvitationCodeClient().List(c, &inventory.ListInvitationCodeArgs{ + PaginationArgs: &inventory.PaginationArgs{ + PageSize: service.PageSize, + PageToken: service.PageToken, + }, + Keyword: service.Keyword, + }) + if err != nil { + return nil, serializer.NewError(serializer.CodeDBError, "Failed to list invitation codes", err) + } + + return &ListInvitationCodeResult{ + Pagination: res.PaginationResults, + Codes: lo.Map(res.Codes, func(code *ent.InvitationCode, _ int) *InvitationCodeResponse { + return &InvitationCodeResponse{ + InvitationCode: code, + HashID: hashid.EncodeInvitationCodeID(dep.HashIDEncoder(), code.ID), + } + }), + }, nil +} + +func (service *UpsertInvitationCodeService) Create(c *gin.Context) (*InvitationCodeResponse, error) { + dep := dependency.FromContext(c) + + code := service.Code + if code == "" { + code = util.RandString(16, util.RandomLowerCases) + } + + if service.GroupID > 0 { + if _, err := dep.GroupClient().GetByID(c, service.GroupID); err != nil { + return nil, serializer.NewError(serializer.CodeParamErr, "Invalid group", err) + } + } + + record, err := dep.InvitationCodeClient().Create(c, &inventory.CreateInvitationCodeParams{ + Code: code, + GroupID: service.GroupID, + MaxUses: service.MaxUses, + ExpiresAt: service.ExpiresAt, + }) + if err != nil { + return nil, serializer.NewError(serializer.CodeDBError, "Failed to create invitation code", err) + } + + return &InvitationCodeResponse{ + InvitationCode: record, + HashID: hashid.EncodeInvitationCodeID(dep.HashIDEncoder(), record.ID), + }, nil +} + +func (service *SingleInvitationCodeService) Delete(c *gin.Context) error { + dep := dependency.FromContext(c) + if err := dep.InvitationCodeClient().Delete(c, service.ID); err != nil { + return serializer.NewError(serializer.CodeDBError, "Failed to delete invitation code", err) + } + return nil +} diff --git a/service/admin/response.go b/service/admin/response.go index fbfb3358..92ad8503 100644 --- a/service/admin/response.go +++ b/service/admin/response.go @@ -114,6 +114,11 @@ type ListGroupResponse struct { Pagination *inventory.PaginationResults `json:"pagination"` } +type ListInvitationCodeResult struct { + Pagination *inventory.PaginationResults `json:"pagination"` + Codes []*InvitationCodeResponse `json:"codes"` +} + type ListOAuthClientResponse struct { Clients []GetOAuthClientResponse `json:"clients"` Pagination *inventory.PaginationResults `json:"pagination"` diff --git a/service/basic/site.go b/service/basic/site.go index 196be9b6..04b037d6 100644 --- a/service/basic/site.go +++ b/service/basic/site.go @@ -43,6 +43,7 @@ type SiteConfig struct { CapSiteKey string `json:"captcha_cap_site_key,omitempty"` CapAssetServer string `json:"captcha_cap_asset_server,omitempty"` RegisterEnabled bool `json:"register_enabled,omitempty"` + InvitationCode bool `json:"invitation_code,omitempty"` TosUrl string `json:"tos_url,omitempty"` PrivacyPolicyUrl string `json:"privacy_policy_url,omitempty"` SSOEnabled bool `json:"sso_enabled,omitempty"` @@ -111,6 +112,7 @@ func (s *GetSettingService) GetSiteConfig(c *gin.Context) (*SiteConfig, error) { ForgetCaptcha: settings.ForgotPasswordCaptchaEnabled(c), Authn: settings.AuthnEnabled(c), RegisterEnabled: settings.RegisterEnabled(c), + InvitationCode: settings.InvitationCodeRequired(c), PrivacyPolicyUrl: legalDocs.PrivacyPolicy, TosUrl: legalDocs.TermsOfService, SSOEnabled: sso.Enabled && sso.Issuer != "" && sso.ClientID != "", diff --git a/service/user/register.go b/service/user/register.go index 2117fa32..f76d2712 100644 --- a/service/user/register.go +++ b/service/user/register.go @@ -24,9 +24,10 @@ type RegisterParameterCtx struct{} // UserRegisterService 管理用户注册的服务 type UserRegisterService struct { - UserName string `form:"email" json:"email" binding:"required,email"` - Password string `form:"password" json:"password" binding:"required,min=6,max=128"` - Language string `form:"language" json:"language"` + UserName string `form:"email" json:"email" binding:"required,email"` + Password string `form:"password" json:"password" binding:"required,min=6,max=128"` + InviteCode string `form:"invite_code" json:"invite_code"` + Language string `form:"language" json:"language"` } // Register 新用户注册 @@ -40,6 +41,11 @@ func (service *UserRegisterService) Register(c *gin.Context) serializer.Response return serializer.Err(c, err) } + inviteCode := strings.TrimSpace(service.InviteCode) + if inviteCode == "" && settings.InvitationCodeRequired(c) { + return serializer.ErrWithDetails(c, serializer.CodeInvitationCodeRequired, "Invitation code is required", nil) + } + args := &inventory.NewUserArgs{ Email: email, PlainPassword: service.Password, @@ -52,11 +58,25 @@ func (service *UserRegisterService) Register(c *gin.Context) serializer.Response } userClient := dep.UserClient() - uc, tx, _, err := inventory.WithTx(c, userClient) + uc, tx, txCtx, err := inventory.WithTx(c, userClient) if err != nil { return serializer.DBErr(c, "Failed to start transaction", err) } + if inviteCode != "" { + // Consume inside the registration transaction: if user creation fails + // the use count rolls back with it. + invClient, _ := inventory.InheritTx(txCtx, dep.InvitationCodeClient()) + invite, err := invClient.Consume(txCtx, inviteCode) + if err != nil { + _ = inventory.Rollback(tx) + return serializer.ErrWithDetails(c, serializer.CodeInvitationCodeInvalid, "Invalid invitation code", err) + } + if invite.GroupID > 0 { + args.GroupID = invite.GroupID + } + } + expectedUser, err := uc.Create(c, args) if expectedUser != nil { util.WithValue(c, inventory.UserCtx{}, expectedUser)