Compare commits

...

5 Commits

Author SHA1 Message Date
Aaron Liu 32632db36f feat(fs): change event debounce before emitting to subscriber 2025-12-13 14:48:01 +08:00
Aaron Liu c01b748dfc feat(fs): fs change event notification via SSE / show panic stack trace in task queue 2025-12-13 14:48:01 +08:00
Darren Yu 05c68b4062
fix(thumb blob path): separators be wrongly modified (#3062) (#3116)
* fix(thumb blob path): separators be wrongly modified

* Update common.go
2025-12-05 15:57:58 +08:00
Darren Yu a08c796e3f
fix(ks3): fix content disposition format for download filename (#3040) (#3057) 2025-12-05 15:33:18 +08:00
Aaron Liu fec4dec3ac feat(upload): etag check in client-side upload / support empty policy ID 2025-12-05 15:17:07 +08:00
48 changed files with 5347 additions and 29 deletions

View File

@ -178,6 +178,8 @@ func (s *server) Close() {
defer cancel() defer cancel()
} }
s.dep.EventHub().Close()
// Shutdown http server // Shutdown http server
if s.server != nil { if s.server != nil {
err := s.server.Shutdown(ctx) err := s.server.Shutdown(ctx)

View File

@ -18,6 +18,7 @@ import (
"github.com/cloudreve/Cloudreve/v4/pkg/credmanager" "github.com/cloudreve/Cloudreve/v4/pkg/credmanager"
"github.com/cloudreve/Cloudreve/v4/pkg/email" "github.com/cloudreve/Cloudreve/v4/pkg/email"
"github.com/cloudreve/Cloudreve/v4/pkg/filemanager/encrypt" "github.com/cloudreve/Cloudreve/v4/pkg/filemanager/encrypt"
"github.com/cloudreve/Cloudreve/v4/pkg/filemanager/eventhub"
"github.com/cloudreve/Cloudreve/v4/pkg/filemanager/fs/mime" "github.com/cloudreve/Cloudreve/v4/pkg/filemanager/fs/mime"
"github.com/cloudreve/Cloudreve/v4/pkg/filemanager/lock" "github.com/cloudreve/Cloudreve/v4/pkg/filemanager/lock"
"github.com/cloudreve/Cloudreve/v4/pkg/hashid" "github.com/cloudreve/Cloudreve/v4/pkg/hashid"
@ -134,6 +135,8 @@ type Dep interface {
MasterEncryptKeyVault(ctx context.Context) encrypt.MasterEncryptKeyVault MasterEncryptKeyVault(ctx context.Context) encrypt.MasterEncryptKeyVault
// EncryptorFactory Get a new encrypt.CryptorFactory instance. // EncryptorFactory Get a new encrypt.CryptorFactory instance.
EncryptorFactory(ctx context.Context) encrypt.CryptorFactory EncryptorFactory(ctx context.Context) encrypt.CryptorFactory
// EventHub Get a singleton eventhub.EventHub instance for event publishing.
EventHub() eventhub.EventHub
} }
type dependency struct { type dependency struct {
@ -156,6 +159,7 @@ type dependency struct {
nodeClient inventory.NodeClient nodeClient inventory.NodeClient
davAccountClient inventory.DavAccountClient davAccountClient inventory.DavAccountClient
directLinkClient inventory.DirectLinkClient directLinkClient inventory.DirectLinkClient
fsEventClient inventory.FsEventClient
emailClient email.Driver emailClient email.Driver
generalAuth auth.Auth generalAuth auth.Auth
hashidEncoder hashid.Encoder hashidEncoder hashid.Encoder
@ -179,6 +183,7 @@ type dependency struct {
parser *uaparser.Parser parser *uaparser.Parser
cron *cron.Cron cron *cron.Cron
masterEncryptKeyVault encrypt.MasterEncryptKeyVault masterEncryptKeyVault encrypt.MasterEncryptKeyVault
eventHub eventhub.EventHub
configPath string configPath string
isPro bool isPro bool
@ -364,6 +369,21 @@ func (d *dependency) NavigatorStateKV() cache.Driver {
return d.navigatorStateKv return d.navigatorStateKv
} }
func (d *dependency) EventHub() eventhub.EventHub {
if d.eventHub != nil {
return d.eventHub
}
d.eventHub = eventhub.NewEventHub(d.UserClient(), d.FsEventClient())
return d.eventHub
}
func (d *dependency) FsEventClient() inventory.FsEventClient {
if d.fsEventClient != nil {
return d.fsEventClient
}
return inventory.NewFsEventClient(d.DBClient(), d.ConfigProvider().Database().Type)
}
func (d *dependency) SettingClient() inventory.SettingClient { func (d *dependency) SettingClient() inventory.SettingClient {
if d.settingClient != nil { if d.settingClient != nil {
return d.settingClient return d.settingClient
@ -861,6 +881,14 @@ func (d *dependency) Shutdown(ctx context.Context) error {
}() }()
} }
if d.eventHub != nil {
wg.Add(1)
go func() {
d.eventHub.Close()
defer wg.Done()
}()
}
d.mu.Unlock() d.mu.Unlock()
wg.Wait() wg.Wait()

2
assets

@ -1 +1 @@
Subproject commit 1b1f9f4c8e35d72ac60216af611c81355bd4f7ce Subproject commit 0b388cc50a6c8e67f645d1b7d569bd9e58ae2c30

View File

@ -19,6 +19,7 @@ import (
"github.com/cloudreve/Cloudreve/v4/ent/directlink" "github.com/cloudreve/Cloudreve/v4/ent/directlink"
"github.com/cloudreve/Cloudreve/v4/ent/entity" "github.com/cloudreve/Cloudreve/v4/ent/entity"
"github.com/cloudreve/Cloudreve/v4/ent/file" "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/group"
"github.com/cloudreve/Cloudreve/v4/ent/metadata" "github.com/cloudreve/Cloudreve/v4/ent/metadata"
"github.com/cloudreve/Cloudreve/v4/ent/node" "github.com/cloudreve/Cloudreve/v4/ent/node"
@ -45,6 +46,8 @@ type Client struct {
Entity *EntityClient Entity *EntityClient
// File is the client for interacting with the File builders. // File is the client for interacting with the File builders.
File *FileClient File *FileClient
// FsEvent is the client for interacting with the FsEvent builders.
FsEvent *FsEventClient
// Group is the client for interacting with the Group builders. // Group is the client for interacting with the Group builders.
Group *GroupClient Group *GroupClient
// Metadata is the client for interacting with the Metadata builders. // Metadata is the client for interacting with the Metadata builders.
@ -78,6 +81,7 @@ func (c *Client) init() {
c.DirectLink = NewDirectLinkClient(c.config) c.DirectLink = NewDirectLinkClient(c.config)
c.Entity = NewEntityClient(c.config) c.Entity = NewEntityClient(c.config)
c.File = NewFileClient(c.config) c.File = NewFileClient(c.config)
c.FsEvent = NewFsEventClient(c.config)
c.Group = NewGroupClient(c.config) c.Group = NewGroupClient(c.config)
c.Metadata = NewMetadataClient(c.config) c.Metadata = NewMetadataClient(c.config)
c.Node = NewNodeClient(c.config) c.Node = NewNodeClient(c.config)
@ -183,6 +187,7 @@ func (c *Client) Tx(ctx context.Context) (*Tx, error) {
DirectLink: NewDirectLinkClient(cfg), DirectLink: NewDirectLinkClient(cfg),
Entity: NewEntityClient(cfg), Entity: NewEntityClient(cfg),
File: NewFileClient(cfg), File: NewFileClient(cfg),
FsEvent: NewFsEventClient(cfg),
Group: NewGroupClient(cfg), Group: NewGroupClient(cfg),
Metadata: NewMetadataClient(cfg), Metadata: NewMetadataClient(cfg),
Node: NewNodeClient(cfg), Node: NewNodeClient(cfg),
@ -215,6 +220,7 @@ func (c *Client) BeginTx(ctx context.Context, opts *sql.TxOptions) (*Tx, error)
DirectLink: NewDirectLinkClient(cfg), DirectLink: NewDirectLinkClient(cfg),
Entity: NewEntityClient(cfg), Entity: NewEntityClient(cfg),
File: NewFileClient(cfg), File: NewFileClient(cfg),
FsEvent: NewFsEventClient(cfg),
Group: NewGroupClient(cfg), Group: NewGroupClient(cfg),
Metadata: NewMetadataClient(cfg), Metadata: NewMetadataClient(cfg),
Node: NewNodeClient(cfg), Node: NewNodeClient(cfg),
@ -253,8 +259,8 @@ func (c *Client) Close() error {
// In order to add hooks to a specific client, call: `client.Node.Use(...)`. // In order to add hooks to a specific client, call: `client.Node.Use(...)`.
func (c *Client) Use(hooks ...Hook) { func (c *Client) Use(hooks ...Hook) {
for _, n := range []interface{ Use(...Hook) }{ for _, n := range []interface{ Use(...Hook) }{
c.DavAccount, c.DirectLink, c.Entity, c.File, c.Group, c.Metadata, c.Node, c.DavAccount, c.DirectLink, c.Entity, c.File, c.FsEvent, c.Group, c.Metadata,
c.Passkey, c.Setting, c.Share, c.StoragePolicy, c.Task, c.User, c.Node, c.Passkey, c.Setting, c.Share, c.StoragePolicy, c.Task, c.User,
} { } {
n.Use(hooks...) n.Use(hooks...)
} }
@ -264,8 +270,8 @@ func (c *Client) Use(hooks ...Hook) {
// In order to add interceptors to a specific client, call: `client.Node.Intercept(...)`. // In order to add interceptors to a specific client, call: `client.Node.Intercept(...)`.
func (c *Client) Intercept(interceptors ...Interceptor) { func (c *Client) Intercept(interceptors ...Interceptor) {
for _, n := range []interface{ Intercept(...Interceptor) }{ for _, n := range []interface{ Intercept(...Interceptor) }{
c.DavAccount, c.DirectLink, c.Entity, c.File, c.Group, c.Metadata, c.Node, c.DavAccount, c.DirectLink, c.Entity, c.File, c.FsEvent, c.Group, c.Metadata,
c.Passkey, c.Setting, c.Share, c.StoragePolicy, c.Task, c.User, c.Node, c.Passkey, c.Setting, c.Share, c.StoragePolicy, c.Task, c.User,
} { } {
n.Intercept(interceptors...) n.Intercept(interceptors...)
} }
@ -282,6 +288,8 @@ func (c *Client) Mutate(ctx context.Context, m Mutation) (Value, error) {
return c.Entity.mutate(ctx, m) return c.Entity.mutate(ctx, m)
case *FileMutation: case *FileMutation:
return c.File.mutate(ctx, m) return c.File.mutate(ctx, m)
case *FsEventMutation:
return c.FsEvent.mutate(ctx, m)
case *GroupMutation: case *GroupMutation:
return c.Group.mutate(ctx, m) return c.Group.mutate(ctx, m)
case *MetadataMutation: case *MetadataMutation:
@ -1052,6 +1060,157 @@ func (c *FileClient) mutate(ctx context.Context, m *FileMutation) (Value, error)
} }
} }
// FsEventClient is a client for the FsEvent schema.
type FsEventClient struct {
config
}
// NewFsEventClient returns a client for the FsEvent from the given config.
func NewFsEventClient(c config) *FsEventClient {
return &FsEventClient{config: c}
}
// Use adds a list of mutation hooks to the hooks stack.
// A call to `Use(f, g, h)` equals to `fsevent.Hooks(f(g(h())))`.
func (c *FsEventClient) Use(hooks ...Hook) {
c.hooks.FsEvent = append(c.hooks.FsEvent, hooks...)
}
// Intercept adds a list of query interceptors to the interceptors stack.
// A call to `Intercept(f, g, h)` equals to `fsevent.Intercept(f(g(h())))`.
func (c *FsEventClient) Intercept(interceptors ...Interceptor) {
c.inters.FsEvent = append(c.inters.FsEvent, interceptors...)
}
// Create returns a builder for creating a FsEvent entity.
func (c *FsEventClient) Create() *FsEventCreate {
mutation := newFsEventMutation(c.config, OpCreate)
return &FsEventCreate{config: c.config, hooks: c.Hooks(), mutation: mutation}
}
// CreateBulk returns a builder for creating a bulk of FsEvent entities.
func (c *FsEventClient) CreateBulk(builders ...*FsEventCreate) *FsEventCreateBulk {
return &FsEventCreateBulk{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 *FsEventClient) MapCreateBulk(slice any, setFunc func(*FsEventCreate, int)) *FsEventCreateBulk {
rv := reflect.ValueOf(slice)
if rv.Kind() != reflect.Slice {
return &FsEventCreateBulk{err: fmt.Errorf("calling to FsEventClient.MapCreateBulk with wrong type %T, need slice", slice)}
}
builders := make([]*FsEventCreate, rv.Len())
for i := 0; i < rv.Len(); i++ {
builders[i] = c.Create()
setFunc(builders[i], i)
}
return &FsEventCreateBulk{config: c.config, builders: builders}
}
// Update returns an update builder for FsEvent.
func (c *FsEventClient) Update() *FsEventUpdate {
mutation := newFsEventMutation(c.config, OpUpdate)
return &FsEventUpdate{config: c.config, hooks: c.Hooks(), mutation: mutation}
}
// UpdateOne returns an update builder for the given entity.
func (c *FsEventClient) UpdateOne(fe *FsEvent) *FsEventUpdateOne {
mutation := newFsEventMutation(c.config, OpUpdateOne, withFsEvent(fe))
return &FsEventUpdateOne{config: c.config, hooks: c.Hooks(), mutation: mutation}
}
// UpdateOneID returns an update builder for the given id.
func (c *FsEventClient) UpdateOneID(id int) *FsEventUpdateOne {
mutation := newFsEventMutation(c.config, OpUpdateOne, withFsEventID(id))
return &FsEventUpdateOne{config: c.config, hooks: c.Hooks(), mutation: mutation}
}
// Delete returns a delete builder for FsEvent.
func (c *FsEventClient) Delete() *FsEventDelete {
mutation := newFsEventMutation(c.config, OpDelete)
return &FsEventDelete{config: c.config, hooks: c.Hooks(), mutation: mutation}
}
// DeleteOne returns a builder for deleting the given entity.
func (c *FsEventClient) DeleteOne(fe *FsEvent) *FsEventDeleteOne {
return c.DeleteOneID(fe.ID)
}
// DeleteOneID returns a builder for deleting the given entity by its id.
func (c *FsEventClient) DeleteOneID(id int) *FsEventDeleteOne {
builder := c.Delete().Where(fsevent.ID(id))
builder.mutation.id = &id
builder.mutation.op = OpDeleteOne
return &FsEventDeleteOne{builder}
}
// Query returns a query builder for FsEvent.
func (c *FsEventClient) Query() *FsEventQuery {
return &FsEventQuery{
config: c.config,
ctx: &QueryContext{Type: TypeFsEvent},
inters: c.Interceptors(),
}
}
// Get returns a FsEvent entity by its id.
func (c *FsEventClient) Get(ctx context.Context, id int) (*FsEvent, error) {
return c.Query().Where(fsevent.ID(id)).Only(ctx)
}
// GetX is like Get, but panics if an error occurs.
func (c *FsEventClient) GetX(ctx context.Context, id int) *FsEvent {
obj, err := c.Get(ctx, id)
if err != nil {
panic(err)
}
return obj
}
// QueryUser queries the user edge of a FsEvent.
func (c *FsEventClient) QueryUser(fe *FsEvent) *UserQuery {
query := (&UserClient{config: c.config}).Query()
query.path = func(context.Context) (fromV *sql.Selector, _ error) {
id := fe.ID
step := sqlgraph.NewStep(
sqlgraph.From(fsevent.Table, fsevent.FieldID, id),
sqlgraph.To(user.Table, user.FieldID),
sqlgraph.Edge(sqlgraph.M2O, true, fsevent.UserTable, fsevent.UserColumn),
)
fromV = sqlgraph.Neighbors(fe.driver.Dialect(), step)
return fromV, nil
}
return query
}
// Hooks returns the client hooks.
func (c *FsEventClient) Hooks() []Hook {
hooks := c.hooks.FsEvent
return append(hooks[:len(hooks):len(hooks)], fsevent.Hooks[:]...)
}
// Interceptors returns the client interceptors.
func (c *FsEventClient) Interceptors() []Interceptor {
inters := c.inters.FsEvent
return append(inters[:len(inters):len(inters)], fsevent.Interceptors[:]...)
}
func (c *FsEventClient) mutate(ctx context.Context, m *FsEventMutation) (Value, error) {
switch m.Op() {
case OpCreate:
return (&FsEventCreate{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx)
case OpUpdate:
return (&FsEventUpdate{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx)
case OpUpdateOne:
return (&FsEventUpdateOne{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx)
case OpDelete, OpDeleteOne:
return (&FsEventDelete{config: c.config, hooks: c.Hooks(), mutation: m}).Exec(ctx)
default:
return nil, fmt.Errorf("ent: unknown FsEvent mutation op: %q", m.Op())
}
}
// GroupClient is a client for the Group schema. // GroupClient is a client for the Group schema.
type GroupClient struct { type GroupClient struct {
config config
@ -2528,6 +2687,22 @@ func (c *UserClient) QueryTasks(u *User) *TaskQuery {
return query return query
} }
// QueryFsevents queries the fsevents edge of a User.
func (c *UserClient) QueryFsevents(u *User) *FsEventQuery {
query := (&FsEventClient{config: c.config}).Query()
query.path = func(context.Context) (fromV *sql.Selector, _ error) {
id := u.ID
step := sqlgraph.NewStep(
sqlgraph.From(user.Table, user.FieldID, id),
sqlgraph.To(fsevent.Table, fsevent.FieldID),
sqlgraph.Edge(sqlgraph.O2M, false, user.FseventsTable, user.FseventsColumn),
)
fromV = sqlgraph.Neighbors(u.driver.Dialect(), step)
return fromV, nil
}
return query
}
// QueryEntities queries the entities edge of a User. // QueryEntities queries the entities edge of a User.
func (c *UserClient) QueryEntities(u *User) *EntityQuery { func (c *UserClient) QueryEntities(u *User) *EntityQuery {
query := (&EntityClient{config: c.config}).Query() query := (&EntityClient{config: c.config}).Query()
@ -2574,12 +2749,12 @@ func (c *UserClient) mutate(ctx context.Context, m *UserMutation) (Value, error)
// hooks and interceptors per client, for fast access. // hooks and interceptors per client, for fast access.
type ( type (
hooks struct { hooks struct {
DavAccount, DirectLink, Entity, File, Group, Metadata, Node, Passkey, Setting, DavAccount, DirectLink, Entity, File, FsEvent, Group, Metadata, Node, Passkey,
Share, StoragePolicy, Task, User []ent.Hook Setting, Share, StoragePolicy, Task, User []ent.Hook
} }
inters struct { inters struct {
DavAccount, DirectLink, Entity, File, Group, Metadata, Node, Passkey, Setting, DavAccount, DirectLink, Entity, File, FsEvent, Group, Metadata, Node, Passkey,
Share, StoragePolicy, Task, User []ent.Interceptor Setting, Share, StoragePolicy, Task, User []ent.Interceptor
} }
) )

View File

@ -16,6 +16,7 @@ import (
"github.com/cloudreve/Cloudreve/v4/ent/directlink" "github.com/cloudreve/Cloudreve/v4/ent/directlink"
"github.com/cloudreve/Cloudreve/v4/ent/entity" "github.com/cloudreve/Cloudreve/v4/ent/entity"
"github.com/cloudreve/Cloudreve/v4/ent/file" "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/group"
"github.com/cloudreve/Cloudreve/v4/ent/metadata" "github.com/cloudreve/Cloudreve/v4/ent/metadata"
"github.com/cloudreve/Cloudreve/v4/ent/node" "github.com/cloudreve/Cloudreve/v4/ent/node"
@ -89,6 +90,7 @@ func checkColumn(table, column string) error {
directlink.Table: directlink.ValidColumn, directlink.Table: directlink.ValidColumn,
entity.Table: entity.ValidColumn, entity.Table: entity.ValidColumn,
file.Table: file.ValidColumn, file.Table: file.ValidColumn,
fsevent.Table: fsevent.ValidColumn,
group.Table: group.ValidColumn, group.Table: group.ValidColumn,
metadata.Table: metadata.ValidColumn, metadata.Table: metadata.ValidColumn,
node.Table: node.ValidColumn, node.Table: node.ValidColumn,

204
ent/fsevent.go Normal file
View File

@ -0,0 +1,204 @@
// 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/fsevent"
"github.com/cloudreve/Cloudreve/v4/ent/user"
"github.com/gofrs/uuid"
)
// FsEvent is the model entity for the FsEvent schema.
type FsEvent 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"`
// Event holds the value of the "event" field.
Event string `json:"event,omitempty"`
// Subscriber holds the value of the "subscriber" field.
Subscriber uuid.UUID `json:"subscriber,omitempty"`
// UserFsevent holds the value of the "user_fsevent" field.
UserFsevent int `json:"user_fsevent,omitempty"`
// Edges holds the relations/edges for other nodes in the graph.
// The values are being populated by the FsEventQuery when eager-loading is set.
Edges FsEventEdges `json:"edges"`
selectValues sql.SelectValues
}
// FsEventEdges holds the relations/edges for other nodes in the graph.
type FsEventEdges struct {
// User holds the value of the user edge.
User *User `json:"user,omitempty"`
// loadedTypes holds the information for reporting if a
// type was loaded (or requested) in eager-loading or not.
loadedTypes [1]bool
}
// UserOrErr returns the User value or an error if the edge
// was not loaded in eager-loading, or loaded but was not found.
func (e FsEventEdges) UserOrErr() (*User, error) {
if e.loadedTypes[0] {
if e.User == nil {
// Edge was loaded but was not found.
return nil, &NotFoundError{label: user.Label}
}
return e.User, nil
}
return nil, &NotLoadedError{edge: "user"}
}
// scanValues returns the types for scanning values from sql.Rows.
func (*FsEvent) scanValues(columns []string) ([]any, error) {
values := make([]any, len(columns))
for i := range columns {
switch columns[i] {
case fsevent.FieldID, fsevent.FieldUserFsevent:
values[i] = new(sql.NullInt64)
case fsevent.FieldEvent:
values[i] = new(sql.NullString)
case fsevent.FieldCreatedAt, fsevent.FieldUpdatedAt, fsevent.FieldDeletedAt:
values[i] = new(sql.NullTime)
case fsevent.FieldSubscriber:
values[i] = new(uuid.UUID)
default:
values[i] = new(sql.UnknownType)
}
}
return values, nil
}
// assignValues assigns the values that were returned from sql.Rows (after scanning)
// to the FsEvent fields.
func (fe *FsEvent) 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 fsevent.FieldID:
value, ok := values[i].(*sql.NullInt64)
if !ok {
return fmt.Errorf("unexpected type %T for field id", value)
}
fe.ID = int(value.Int64)
case fsevent.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 {
fe.CreatedAt = value.Time
}
case fsevent.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 {
fe.UpdatedAt = value.Time
}
case fsevent.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 {
fe.DeletedAt = new(time.Time)
*fe.DeletedAt = value.Time
}
case fsevent.FieldEvent:
if value, ok := values[i].(*sql.NullString); !ok {
return fmt.Errorf("unexpected type %T for field event", values[i])
} else if value.Valid {
fe.Event = value.String
}
case fsevent.FieldSubscriber:
if value, ok := values[i].(*uuid.UUID); !ok {
return fmt.Errorf("unexpected type %T for field subscriber", values[i])
} else if value != nil {
fe.Subscriber = *value
}
case fsevent.FieldUserFsevent:
if value, ok := values[i].(*sql.NullInt64); !ok {
return fmt.Errorf("unexpected type %T for field user_fsevent", values[i])
} else if value.Valid {
fe.UserFsevent = int(value.Int64)
}
default:
fe.selectValues.Set(columns[i], values[i])
}
}
return nil
}
// Value returns the ent.Value that was dynamically selected and assigned to the FsEvent.
// This includes values selected through modifiers, order, etc.
func (fe *FsEvent) Value(name string) (ent.Value, error) {
return fe.selectValues.Get(name)
}
// QueryUser queries the "user" edge of the FsEvent entity.
func (fe *FsEvent) QueryUser() *UserQuery {
return NewFsEventClient(fe.config).QueryUser(fe)
}
// Update returns a builder for updating this FsEvent.
// Note that you need to call FsEvent.Unwrap() before calling this method if this FsEvent
// was returned from a transaction, and the transaction was committed or rolled back.
func (fe *FsEvent) Update() *FsEventUpdateOne {
return NewFsEventClient(fe.config).UpdateOne(fe)
}
// Unwrap unwraps the FsEvent 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 (fe *FsEvent) Unwrap() *FsEvent {
_tx, ok := fe.config.driver.(*txDriver)
if !ok {
panic("ent: FsEvent is not a transactional entity")
}
fe.config.driver = _tx.drv
return fe
}
// String implements the fmt.Stringer.
func (fe *FsEvent) String() string {
var builder strings.Builder
builder.WriteString("FsEvent(")
builder.WriteString(fmt.Sprintf("id=%v, ", fe.ID))
builder.WriteString("created_at=")
builder.WriteString(fe.CreatedAt.Format(time.ANSIC))
builder.WriteString(", ")
builder.WriteString("updated_at=")
builder.WriteString(fe.UpdatedAt.Format(time.ANSIC))
builder.WriteString(", ")
if v := fe.DeletedAt; v != nil {
builder.WriteString("deleted_at=")
builder.WriteString(v.Format(time.ANSIC))
}
builder.WriteString(", ")
builder.WriteString("event=")
builder.WriteString(fe.Event)
builder.WriteString(", ")
builder.WriteString("subscriber=")
builder.WriteString(fmt.Sprintf("%v", fe.Subscriber))
builder.WriteString(", ")
builder.WriteString("user_fsevent=")
builder.WriteString(fmt.Sprintf("%v", fe.UserFsevent))
builder.WriteByte(')')
return builder.String()
}
// SetUser manually set the edge as loaded state.
func (e *FsEvent) SetUser(v *User) {
e.Edges.User = v
e.Edges.loadedTypes[0] = true
}
// FsEvents is a parsable slice of FsEvent.
type FsEvents []*FsEvent

130
ent/fsevent/fsevent.go Normal file
View File

@ -0,0 +1,130 @@
// Code generated by ent, DO NOT EDIT.
package fsevent
import (
"time"
"entgo.io/ent"
"entgo.io/ent/dialect/sql"
"entgo.io/ent/dialect/sql/sqlgraph"
)
const (
// Label holds the string label denoting the fsevent type in the database.
Label = "fs_event"
// 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"
// FieldEvent holds the string denoting the event field in the database.
FieldEvent = "event"
// FieldSubscriber holds the string denoting the subscriber field in the database.
FieldSubscriber = "subscriber"
// FieldUserFsevent holds the string denoting the user_fsevent field in the database.
FieldUserFsevent = "user_fsevent"
// EdgeUser holds the string denoting the user edge name in mutations.
EdgeUser = "user"
// Table holds the table name of the fsevent in the database.
Table = "fs_events"
// UserTable is the table that holds the user relation/edge.
UserTable = "fs_events"
// UserInverseTable is the table name for the User entity.
// It exists in this package in order to avoid circular dependency with the "user" package.
UserInverseTable = "users"
// UserColumn is the table column denoting the user relation/edge.
UserColumn = "user_fsevent"
)
// Columns holds all SQL columns for fsevent fields.
var Columns = []string{
FieldID,
FieldCreatedAt,
FieldUpdatedAt,
FieldDeletedAt,
FieldEvent,
FieldSubscriber,
FieldUserFsevent,
}
// 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
)
// OrderOption defines the ordering options for the FsEvent 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()
}
// ByEvent orders the results by the event field.
func ByEvent(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldEvent, opts...).ToFunc()
}
// BySubscriber orders the results by the subscriber field.
func BySubscriber(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldSubscriber, opts...).ToFunc()
}
// ByUserFsevent orders the results by the user_fsevent field.
func ByUserFsevent(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldUserFsevent, opts...).ToFunc()
}
// ByUserField orders the results by user field.
func ByUserField(field string, opts ...sql.OrderTermOption) OrderOption {
return func(s *sql.Selector) {
sqlgraph.OrderByNeighborTerms(s, newUserStep(), sql.OrderByField(field, opts...))
}
}
func newUserStep() *sqlgraph.Step {
return sqlgraph.NewStep(
sqlgraph.From(Table, FieldID),
sqlgraph.To(UserInverseTable, FieldID),
sqlgraph.Edge(sqlgraph.M2O, true, UserTable, UserColumn),
)
}

390
ent/fsevent/where.go Normal file
View File

@ -0,0 +1,390 @@
// Code generated by ent, DO NOT EDIT.
package fsevent
import (
"time"
"entgo.io/ent/dialect/sql"
"entgo.io/ent/dialect/sql/sqlgraph"
"github.com/cloudreve/Cloudreve/v4/ent/predicate"
"github.com/gofrs/uuid"
)
// ID filters vertices based on their ID field.
func ID(id int) predicate.FsEvent {
return predicate.FsEvent(sql.FieldEQ(FieldID, id))
}
// IDEQ applies the EQ predicate on the ID field.
func IDEQ(id int) predicate.FsEvent {
return predicate.FsEvent(sql.FieldEQ(FieldID, id))
}
// IDNEQ applies the NEQ predicate on the ID field.
func IDNEQ(id int) predicate.FsEvent {
return predicate.FsEvent(sql.FieldNEQ(FieldID, id))
}
// IDIn applies the In predicate on the ID field.
func IDIn(ids ...int) predicate.FsEvent {
return predicate.FsEvent(sql.FieldIn(FieldID, ids...))
}
// IDNotIn applies the NotIn predicate on the ID field.
func IDNotIn(ids ...int) predicate.FsEvent {
return predicate.FsEvent(sql.FieldNotIn(FieldID, ids...))
}
// IDGT applies the GT predicate on the ID field.
func IDGT(id int) predicate.FsEvent {
return predicate.FsEvent(sql.FieldGT(FieldID, id))
}
// IDGTE applies the GTE predicate on the ID field.
func IDGTE(id int) predicate.FsEvent {
return predicate.FsEvent(sql.FieldGTE(FieldID, id))
}
// IDLT applies the LT predicate on the ID field.
func IDLT(id int) predicate.FsEvent {
return predicate.FsEvent(sql.FieldLT(FieldID, id))
}
// IDLTE applies the LTE predicate on the ID field.
func IDLTE(id int) predicate.FsEvent {
return predicate.FsEvent(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.FsEvent {
return predicate.FsEvent(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.FsEvent {
return predicate.FsEvent(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.FsEvent {
return predicate.FsEvent(sql.FieldEQ(FieldDeletedAt, v))
}
// Event applies equality check predicate on the "event" field. It's identical to EventEQ.
func Event(v string) predicate.FsEvent {
return predicate.FsEvent(sql.FieldEQ(FieldEvent, v))
}
// Subscriber applies equality check predicate on the "subscriber" field. It's identical to SubscriberEQ.
func Subscriber(v uuid.UUID) predicate.FsEvent {
return predicate.FsEvent(sql.FieldEQ(FieldSubscriber, v))
}
// UserFsevent applies equality check predicate on the "user_fsevent" field. It's identical to UserFseventEQ.
func UserFsevent(v int) predicate.FsEvent {
return predicate.FsEvent(sql.FieldEQ(FieldUserFsevent, v))
}
// CreatedAtEQ applies the EQ predicate on the "created_at" field.
func CreatedAtEQ(v time.Time) predicate.FsEvent {
return predicate.FsEvent(sql.FieldEQ(FieldCreatedAt, v))
}
// CreatedAtNEQ applies the NEQ predicate on the "created_at" field.
func CreatedAtNEQ(v time.Time) predicate.FsEvent {
return predicate.FsEvent(sql.FieldNEQ(FieldCreatedAt, v))
}
// CreatedAtIn applies the In predicate on the "created_at" field.
func CreatedAtIn(vs ...time.Time) predicate.FsEvent {
return predicate.FsEvent(sql.FieldIn(FieldCreatedAt, vs...))
}
// CreatedAtNotIn applies the NotIn predicate on the "created_at" field.
func CreatedAtNotIn(vs ...time.Time) predicate.FsEvent {
return predicate.FsEvent(sql.FieldNotIn(FieldCreatedAt, vs...))
}
// CreatedAtGT applies the GT predicate on the "created_at" field.
func CreatedAtGT(v time.Time) predicate.FsEvent {
return predicate.FsEvent(sql.FieldGT(FieldCreatedAt, v))
}
// CreatedAtGTE applies the GTE predicate on the "created_at" field.
func CreatedAtGTE(v time.Time) predicate.FsEvent {
return predicate.FsEvent(sql.FieldGTE(FieldCreatedAt, v))
}
// CreatedAtLT applies the LT predicate on the "created_at" field.
func CreatedAtLT(v time.Time) predicate.FsEvent {
return predicate.FsEvent(sql.FieldLT(FieldCreatedAt, v))
}
// CreatedAtLTE applies the LTE predicate on the "created_at" field.
func CreatedAtLTE(v time.Time) predicate.FsEvent {
return predicate.FsEvent(sql.FieldLTE(FieldCreatedAt, v))
}
// UpdatedAtEQ applies the EQ predicate on the "updated_at" field.
func UpdatedAtEQ(v time.Time) predicate.FsEvent {
return predicate.FsEvent(sql.FieldEQ(FieldUpdatedAt, v))
}
// UpdatedAtNEQ applies the NEQ predicate on the "updated_at" field.
func UpdatedAtNEQ(v time.Time) predicate.FsEvent {
return predicate.FsEvent(sql.FieldNEQ(FieldUpdatedAt, v))
}
// UpdatedAtIn applies the In predicate on the "updated_at" field.
func UpdatedAtIn(vs ...time.Time) predicate.FsEvent {
return predicate.FsEvent(sql.FieldIn(FieldUpdatedAt, vs...))
}
// UpdatedAtNotIn applies the NotIn predicate on the "updated_at" field.
func UpdatedAtNotIn(vs ...time.Time) predicate.FsEvent {
return predicate.FsEvent(sql.FieldNotIn(FieldUpdatedAt, vs...))
}
// UpdatedAtGT applies the GT predicate on the "updated_at" field.
func UpdatedAtGT(v time.Time) predicate.FsEvent {
return predicate.FsEvent(sql.FieldGT(FieldUpdatedAt, v))
}
// UpdatedAtGTE applies the GTE predicate on the "updated_at" field.
func UpdatedAtGTE(v time.Time) predicate.FsEvent {
return predicate.FsEvent(sql.FieldGTE(FieldUpdatedAt, v))
}
// UpdatedAtLT applies the LT predicate on the "updated_at" field.
func UpdatedAtLT(v time.Time) predicate.FsEvent {
return predicate.FsEvent(sql.FieldLT(FieldUpdatedAt, v))
}
// UpdatedAtLTE applies the LTE predicate on the "updated_at" field.
func UpdatedAtLTE(v time.Time) predicate.FsEvent {
return predicate.FsEvent(sql.FieldLTE(FieldUpdatedAt, v))
}
// DeletedAtEQ applies the EQ predicate on the "deleted_at" field.
func DeletedAtEQ(v time.Time) predicate.FsEvent {
return predicate.FsEvent(sql.FieldEQ(FieldDeletedAt, v))
}
// DeletedAtNEQ applies the NEQ predicate on the "deleted_at" field.
func DeletedAtNEQ(v time.Time) predicate.FsEvent {
return predicate.FsEvent(sql.FieldNEQ(FieldDeletedAt, v))
}
// DeletedAtIn applies the In predicate on the "deleted_at" field.
func DeletedAtIn(vs ...time.Time) predicate.FsEvent {
return predicate.FsEvent(sql.FieldIn(FieldDeletedAt, vs...))
}
// DeletedAtNotIn applies the NotIn predicate on the "deleted_at" field.
func DeletedAtNotIn(vs ...time.Time) predicate.FsEvent {
return predicate.FsEvent(sql.FieldNotIn(FieldDeletedAt, vs...))
}
// DeletedAtGT applies the GT predicate on the "deleted_at" field.
func DeletedAtGT(v time.Time) predicate.FsEvent {
return predicate.FsEvent(sql.FieldGT(FieldDeletedAt, v))
}
// DeletedAtGTE applies the GTE predicate on the "deleted_at" field.
func DeletedAtGTE(v time.Time) predicate.FsEvent {
return predicate.FsEvent(sql.FieldGTE(FieldDeletedAt, v))
}
// DeletedAtLT applies the LT predicate on the "deleted_at" field.
func DeletedAtLT(v time.Time) predicate.FsEvent {
return predicate.FsEvent(sql.FieldLT(FieldDeletedAt, v))
}
// DeletedAtLTE applies the LTE predicate on the "deleted_at" field.
func DeletedAtLTE(v time.Time) predicate.FsEvent {
return predicate.FsEvent(sql.FieldLTE(FieldDeletedAt, v))
}
// DeletedAtIsNil applies the IsNil predicate on the "deleted_at" field.
func DeletedAtIsNil() predicate.FsEvent {
return predicate.FsEvent(sql.FieldIsNull(FieldDeletedAt))
}
// DeletedAtNotNil applies the NotNil predicate on the "deleted_at" field.
func DeletedAtNotNil() predicate.FsEvent {
return predicate.FsEvent(sql.FieldNotNull(FieldDeletedAt))
}
// EventEQ applies the EQ predicate on the "event" field.
func EventEQ(v string) predicate.FsEvent {
return predicate.FsEvent(sql.FieldEQ(FieldEvent, v))
}
// EventNEQ applies the NEQ predicate on the "event" field.
func EventNEQ(v string) predicate.FsEvent {
return predicate.FsEvent(sql.FieldNEQ(FieldEvent, v))
}
// EventIn applies the In predicate on the "event" field.
func EventIn(vs ...string) predicate.FsEvent {
return predicate.FsEvent(sql.FieldIn(FieldEvent, vs...))
}
// EventNotIn applies the NotIn predicate on the "event" field.
func EventNotIn(vs ...string) predicate.FsEvent {
return predicate.FsEvent(sql.FieldNotIn(FieldEvent, vs...))
}
// EventGT applies the GT predicate on the "event" field.
func EventGT(v string) predicate.FsEvent {
return predicate.FsEvent(sql.FieldGT(FieldEvent, v))
}
// EventGTE applies the GTE predicate on the "event" field.
func EventGTE(v string) predicate.FsEvent {
return predicate.FsEvent(sql.FieldGTE(FieldEvent, v))
}
// EventLT applies the LT predicate on the "event" field.
func EventLT(v string) predicate.FsEvent {
return predicate.FsEvent(sql.FieldLT(FieldEvent, v))
}
// EventLTE applies the LTE predicate on the "event" field.
func EventLTE(v string) predicate.FsEvent {
return predicate.FsEvent(sql.FieldLTE(FieldEvent, v))
}
// EventContains applies the Contains predicate on the "event" field.
func EventContains(v string) predicate.FsEvent {
return predicate.FsEvent(sql.FieldContains(FieldEvent, v))
}
// EventHasPrefix applies the HasPrefix predicate on the "event" field.
func EventHasPrefix(v string) predicate.FsEvent {
return predicate.FsEvent(sql.FieldHasPrefix(FieldEvent, v))
}
// EventHasSuffix applies the HasSuffix predicate on the "event" field.
func EventHasSuffix(v string) predicate.FsEvent {
return predicate.FsEvent(sql.FieldHasSuffix(FieldEvent, v))
}
// EventEqualFold applies the EqualFold predicate on the "event" field.
func EventEqualFold(v string) predicate.FsEvent {
return predicate.FsEvent(sql.FieldEqualFold(FieldEvent, v))
}
// EventContainsFold applies the ContainsFold predicate on the "event" field.
func EventContainsFold(v string) predicate.FsEvent {
return predicate.FsEvent(sql.FieldContainsFold(FieldEvent, v))
}
// SubscriberEQ applies the EQ predicate on the "subscriber" field.
func SubscriberEQ(v uuid.UUID) predicate.FsEvent {
return predicate.FsEvent(sql.FieldEQ(FieldSubscriber, v))
}
// SubscriberNEQ applies the NEQ predicate on the "subscriber" field.
func SubscriberNEQ(v uuid.UUID) predicate.FsEvent {
return predicate.FsEvent(sql.FieldNEQ(FieldSubscriber, v))
}
// SubscriberIn applies the In predicate on the "subscriber" field.
func SubscriberIn(vs ...uuid.UUID) predicate.FsEvent {
return predicate.FsEvent(sql.FieldIn(FieldSubscriber, vs...))
}
// SubscriberNotIn applies the NotIn predicate on the "subscriber" field.
func SubscriberNotIn(vs ...uuid.UUID) predicate.FsEvent {
return predicate.FsEvent(sql.FieldNotIn(FieldSubscriber, vs...))
}
// SubscriberGT applies the GT predicate on the "subscriber" field.
func SubscriberGT(v uuid.UUID) predicate.FsEvent {
return predicate.FsEvent(sql.FieldGT(FieldSubscriber, v))
}
// SubscriberGTE applies the GTE predicate on the "subscriber" field.
func SubscriberGTE(v uuid.UUID) predicate.FsEvent {
return predicate.FsEvent(sql.FieldGTE(FieldSubscriber, v))
}
// SubscriberLT applies the LT predicate on the "subscriber" field.
func SubscriberLT(v uuid.UUID) predicate.FsEvent {
return predicate.FsEvent(sql.FieldLT(FieldSubscriber, v))
}
// SubscriberLTE applies the LTE predicate on the "subscriber" field.
func SubscriberLTE(v uuid.UUID) predicate.FsEvent {
return predicate.FsEvent(sql.FieldLTE(FieldSubscriber, v))
}
// UserFseventEQ applies the EQ predicate on the "user_fsevent" field.
func UserFseventEQ(v int) predicate.FsEvent {
return predicate.FsEvent(sql.FieldEQ(FieldUserFsevent, v))
}
// UserFseventNEQ applies the NEQ predicate on the "user_fsevent" field.
func UserFseventNEQ(v int) predicate.FsEvent {
return predicate.FsEvent(sql.FieldNEQ(FieldUserFsevent, v))
}
// UserFseventIn applies the In predicate on the "user_fsevent" field.
func UserFseventIn(vs ...int) predicate.FsEvent {
return predicate.FsEvent(sql.FieldIn(FieldUserFsevent, vs...))
}
// UserFseventNotIn applies the NotIn predicate on the "user_fsevent" field.
func UserFseventNotIn(vs ...int) predicate.FsEvent {
return predicate.FsEvent(sql.FieldNotIn(FieldUserFsevent, vs...))
}
// UserFseventIsNil applies the IsNil predicate on the "user_fsevent" field.
func UserFseventIsNil() predicate.FsEvent {
return predicate.FsEvent(sql.FieldIsNull(FieldUserFsevent))
}
// UserFseventNotNil applies the NotNil predicate on the "user_fsevent" field.
func UserFseventNotNil() predicate.FsEvent {
return predicate.FsEvent(sql.FieldNotNull(FieldUserFsevent))
}
// HasUser applies the HasEdge predicate on the "user" edge.
func HasUser() predicate.FsEvent {
return predicate.FsEvent(func(s *sql.Selector) {
step := sqlgraph.NewStep(
sqlgraph.From(Table, FieldID),
sqlgraph.Edge(sqlgraph.M2O, true, UserTable, UserColumn),
)
sqlgraph.HasNeighbors(s, step)
})
}
// HasUserWith applies the HasEdge predicate on the "user" edge with a given conditions (other predicates).
func HasUserWith(preds ...predicate.User) predicate.FsEvent {
return predicate.FsEvent(func(s *sql.Selector) {
step := newUserStep()
sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) {
for _, p := range preds {
p(s)
}
})
})
}
// And groups predicates with the AND operator between them.
func And(predicates ...predicate.FsEvent) predicate.FsEvent {
return predicate.FsEvent(sql.AndPredicates(predicates...))
}
// Or groups predicates with the OR operator between them.
func Or(predicates ...predicate.FsEvent) predicate.FsEvent {
return predicate.FsEvent(sql.OrPredicates(predicates...))
}
// Not applies the not operator on the given predicate.
func Not(p predicate.FsEvent) predicate.FsEvent {
return predicate.FsEvent(sql.NotPredicates(p))
}

827
ent/fsevent_create.go Normal file
View File

@ -0,0 +1,827 @@
// 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/fsevent"
"github.com/cloudreve/Cloudreve/v4/ent/user"
"github.com/gofrs/uuid"
)
// FsEventCreate is the builder for creating a FsEvent entity.
type FsEventCreate struct {
config
mutation *FsEventMutation
hooks []Hook
conflict []sql.ConflictOption
}
// SetCreatedAt sets the "created_at" field.
func (fec *FsEventCreate) SetCreatedAt(t time.Time) *FsEventCreate {
fec.mutation.SetCreatedAt(t)
return fec
}
// SetNillableCreatedAt sets the "created_at" field if the given value is not nil.
func (fec *FsEventCreate) SetNillableCreatedAt(t *time.Time) *FsEventCreate {
if t != nil {
fec.SetCreatedAt(*t)
}
return fec
}
// SetUpdatedAt sets the "updated_at" field.
func (fec *FsEventCreate) SetUpdatedAt(t time.Time) *FsEventCreate {
fec.mutation.SetUpdatedAt(t)
return fec
}
// SetNillableUpdatedAt sets the "updated_at" field if the given value is not nil.
func (fec *FsEventCreate) SetNillableUpdatedAt(t *time.Time) *FsEventCreate {
if t != nil {
fec.SetUpdatedAt(*t)
}
return fec
}
// SetDeletedAt sets the "deleted_at" field.
func (fec *FsEventCreate) SetDeletedAt(t time.Time) *FsEventCreate {
fec.mutation.SetDeletedAt(t)
return fec
}
// SetNillableDeletedAt sets the "deleted_at" field if the given value is not nil.
func (fec *FsEventCreate) SetNillableDeletedAt(t *time.Time) *FsEventCreate {
if t != nil {
fec.SetDeletedAt(*t)
}
return fec
}
// SetEvent sets the "event" field.
func (fec *FsEventCreate) SetEvent(s string) *FsEventCreate {
fec.mutation.SetEvent(s)
return fec
}
// SetSubscriber sets the "subscriber" field.
func (fec *FsEventCreate) SetSubscriber(u uuid.UUID) *FsEventCreate {
fec.mutation.SetSubscriber(u)
return fec
}
// SetUserFsevent sets the "user_fsevent" field.
func (fec *FsEventCreate) SetUserFsevent(i int) *FsEventCreate {
fec.mutation.SetUserFsevent(i)
return fec
}
// SetNillableUserFsevent sets the "user_fsevent" field if the given value is not nil.
func (fec *FsEventCreate) SetNillableUserFsevent(i *int) *FsEventCreate {
if i != nil {
fec.SetUserFsevent(*i)
}
return fec
}
// SetUserID sets the "user" edge to the User entity by ID.
func (fec *FsEventCreate) SetUserID(id int) *FsEventCreate {
fec.mutation.SetUserID(id)
return fec
}
// SetNillableUserID sets the "user" edge to the User entity by ID if the given value is not nil.
func (fec *FsEventCreate) SetNillableUserID(id *int) *FsEventCreate {
if id != nil {
fec = fec.SetUserID(*id)
}
return fec
}
// SetUser sets the "user" edge to the User entity.
func (fec *FsEventCreate) SetUser(u *User) *FsEventCreate {
return fec.SetUserID(u.ID)
}
// Mutation returns the FsEventMutation object of the builder.
func (fec *FsEventCreate) Mutation() *FsEventMutation {
return fec.mutation
}
// Save creates the FsEvent in the database.
func (fec *FsEventCreate) Save(ctx context.Context) (*FsEvent, error) {
if err := fec.defaults(); err != nil {
return nil, err
}
return withHooks(ctx, fec.sqlSave, fec.mutation, fec.hooks)
}
// SaveX calls Save and panics if Save returns an error.
func (fec *FsEventCreate) SaveX(ctx context.Context) *FsEvent {
v, err := fec.Save(ctx)
if err != nil {
panic(err)
}
return v
}
// Exec executes the query.
func (fec *FsEventCreate) Exec(ctx context.Context) error {
_, err := fec.Save(ctx)
return err
}
// ExecX is like Exec, but panics if an error occurs.
func (fec *FsEventCreate) ExecX(ctx context.Context) {
if err := fec.Exec(ctx); err != nil {
panic(err)
}
}
// defaults sets the default values of the builder before save.
func (fec *FsEventCreate) defaults() error {
if _, ok := fec.mutation.CreatedAt(); !ok {
if fsevent.DefaultCreatedAt == nil {
return fmt.Errorf("ent: uninitialized fsevent.DefaultCreatedAt (forgotten import ent/runtime?)")
}
v := fsevent.DefaultCreatedAt()
fec.mutation.SetCreatedAt(v)
}
if _, ok := fec.mutation.UpdatedAt(); !ok {
if fsevent.DefaultUpdatedAt == nil {
return fmt.Errorf("ent: uninitialized fsevent.DefaultUpdatedAt (forgotten import ent/runtime?)")
}
v := fsevent.DefaultUpdatedAt()
fec.mutation.SetUpdatedAt(v)
}
return nil
}
// check runs all checks and user-defined validators on the builder.
func (fec *FsEventCreate) check() error {
if _, ok := fec.mutation.CreatedAt(); !ok {
return &ValidationError{Name: "created_at", err: errors.New(`ent: missing required field "FsEvent.created_at"`)}
}
if _, ok := fec.mutation.UpdatedAt(); !ok {
return &ValidationError{Name: "updated_at", err: errors.New(`ent: missing required field "FsEvent.updated_at"`)}
}
if _, ok := fec.mutation.Event(); !ok {
return &ValidationError{Name: "event", err: errors.New(`ent: missing required field "FsEvent.event"`)}
}
if _, ok := fec.mutation.Subscriber(); !ok {
return &ValidationError{Name: "subscriber", err: errors.New(`ent: missing required field "FsEvent.subscriber"`)}
}
return nil
}
func (fec *FsEventCreate) sqlSave(ctx context.Context) (*FsEvent, error) {
if err := fec.check(); err != nil {
return nil, err
}
_node, _spec := fec.createSpec()
if err := sqlgraph.CreateNode(ctx, fec.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)
fec.mutation.id = &_node.ID
fec.mutation.done = true
return _node, nil
}
func (fec *FsEventCreate) createSpec() (*FsEvent, *sqlgraph.CreateSpec) {
var (
_node = &FsEvent{config: fec.config}
_spec = sqlgraph.NewCreateSpec(fsevent.Table, sqlgraph.NewFieldSpec(fsevent.FieldID, field.TypeInt))
)
if id, ok := fec.mutation.ID(); ok {
_node.ID = id
id64 := int64(id)
_spec.ID.Value = id64
}
_spec.OnConflict = fec.conflict
if value, ok := fec.mutation.CreatedAt(); ok {
_spec.SetField(fsevent.FieldCreatedAt, field.TypeTime, value)
_node.CreatedAt = value
}
if value, ok := fec.mutation.UpdatedAt(); ok {
_spec.SetField(fsevent.FieldUpdatedAt, field.TypeTime, value)
_node.UpdatedAt = value
}
if value, ok := fec.mutation.DeletedAt(); ok {
_spec.SetField(fsevent.FieldDeletedAt, field.TypeTime, value)
_node.DeletedAt = &value
}
if value, ok := fec.mutation.Event(); ok {
_spec.SetField(fsevent.FieldEvent, field.TypeString, value)
_node.Event = value
}
if value, ok := fec.mutation.Subscriber(); ok {
_spec.SetField(fsevent.FieldSubscriber, field.TypeUUID, value)
_node.Subscriber = value
}
if nodes := fec.mutation.UserIDs(); len(nodes) > 0 {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.M2O,
Inverse: true,
Table: fsevent.UserTable,
Columns: []string{fsevent.UserColumn},
Bidi: false,
Target: &sqlgraph.EdgeTarget{
IDSpec: sqlgraph.NewFieldSpec(user.FieldID, field.TypeInt),
},
}
for _, k := range nodes {
edge.Target.Nodes = append(edge.Target.Nodes, k)
}
_node.UserFsevent = nodes[0]
_spec.Edges = append(_spec.Edges, edge)
}
return _node, _spec
}
// OnConflict allows configuring the `ON CONFLICT` / `ON DUPLICATE KEY` clause
// of the `INSERT` statement. For example:
//
// client.FsEvent.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.FsEventUpsert) {
// SetCreatedAt(v+v).
// }).
// Exec(ctx)
func (fec *FsEventCreate) OnConflict(opts ...sql.ConflictOption) *FsEventUpsertOne {
fec.conflict = opts
return &FsEventUpsertOne{
create: fec,
}
}
// OnConflictColumns calls `OnConflict` and configures the columns
// as conflict target. Using this option is equivalent to using:
//
// client.FsEvent.Create().
// OnConflict(sql.ConflictColumns(columns...)).
// Exec(ctx)
func (fec *FsEventCreate) OnConflictColumns(columns ...string) *FsEventUpsertOne {
fec.conflict = append(fec.conflict, sql.ConflictColumns(columns...))
return &FsEventUpsertOne{
create: fec,
}
}
type (
// FsEventUpsertOne is the builder for "upsert"-ing
// one FsEvent node.
FsEventUpsertOne struct {
create *FsEventCreate
}
// FsEventUpsert is the "OnConflict" setter.
FsEventUpsert struct {
*sql.UpdateSet
}
)
// SetUpdatedAt sets the "updated_at" field.
func (u *FsEventUpsert) SetUpdatedAt(v time.Time) *FsEventUpsert {
u.Set(fsevent.FieldUpdatedAt, v)
return u
}
// UpdateUpdatedAt sets the "updated_at" field to the value that was provided on create.
func (u *FsEventUpsert) UpdateUpdatedAt() *FsEventUpsert {
u.SetExcluded(fsevent.FieldUpdatedAt)
return u
}
// SetDeletedAt sets the "deleted_at" field.
func (u *FsEventUpsert) SetDeletedAt(v time.Time) *FsEventUpsert {
u.Set(fsevent.FieldDeletedAt, v)
return u
}
// UpdateDeletedAt sets the "deleted_at" field to the value that was provided on create.
func (u *FsEventUpsert) UpdateDeletedAt() *FsEventUpsert {
u.SetExcluded(fsevent.FieldDeletedAt)
return u
}
// ClearDeletedAt clears the value of the "deleted_at" field.
func (u *FsEventUpsert) ClearDeletedAt() *FsEventUpsert {
u.SetNull(fsevent.FieldDeletedAt)
return u
}
// SetEvent sets the "event" field.
func (u *FsEventUpsert) SetEvent(v string) *FsEventUpsert {
u.Set(fsevent.FieldEvent, v)
return u
}
// UpdateEvent sets the "event" field to the value that was provided on create.
func (u *FsEventUpsert) UpdateEvent() *FsEventUpsert {
u.SetExcluded(fsevent.FieldEvent)
return u
}
// SetSubscriber sets the "subscriber" field.
func (u *FsEventUpsert) SetSubscriber(v uuid.UUID) *FsEventUpsert {
u.Set(fsevent.FieldSubscriber, v)
return u
}
// UpdateSubscriber sets the "subscriber" field to the value that was provided on create.
func (u *FsEventUpsert) UpdateSubscriber() *FsEventUpsert {
u.SetExcluded(fsevent.FieldSubscriber)
return u
}
// SetUserFsevent sets the "user_fsevent" field.
func (u *FsEventUpsert) SetUserFsevent(v int) *FsEventUpsert {
u.Set(fsevent.FieldUserFsevent, v)
return u
}
// UpdateUserFsevent sets the "user_fsevent" field to the value that was provided on create.
func (u *FsEventUpsert) UpdateUserFsevent() *FsEventUpsert {
u.SetExcluded(fsevent.FieldUserFsevent)
return u
}
// ClearUserFsevent clears the value of the "user_fsevent" field.
func (u *FsEventUpsert) ClearUserFsevent() *FsEventUpsert {
u.SetNull(fsevent.FieldUserFsevent)
return u
}
// UpdateNewValues updates the mutable fields using the new values that were set on create.
// Using this option is equivalent to using:
//
// client.FsEvent.Create().
// OnConflict(
// sql.ResolveWithNewValues(),
// ).
// Exec(ctx)
func (u *FsEventUpsertOne) UpdateNewValues() *FsEventUpsertOne {
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(fsevent.FieldCreatedAt)
}
}))
return u
}
// Ignore sets each column to itself in case of conflict.
// Using this option is equivalent to using:
//
// client.FsEvent.Create().
// OnConflict(sql.ResolveWithIgnore()).
// Exec(ctx)
func (u *FsEventUpsertOne) Ignore() *FsEventUpsertOne {
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 *FsEventUpsertOne) DoNothing() *FsEventUpsertOne {
u.create.conflict = append(u.create.conflict, sql.DoNothing())
return u
}
// Update allows overriding fields `UPDATE` values. See the FsEventCreate.OnConflict
// documentation for more info.
func (u *FsEventUpsertOne) Update(set func(*FsEventUpsert)) *FsEventUpsertOne {
u.create.conflict = append(u.create.conflict, sql.ResolveWith(func(update *sql.UpdateSet) {
set(&FsEventUpsert{UpdateSet: update})
}))
return u
}
// SetUpdatedAt sets the "updated_at" field.
func (u *FsEventUpsertOne) SetUpdatedAt(v time.Time) *FsEventUpsertOne {
return u.Update(func(s *FsEventUpsert) {
s.SetUpdatedAt(v)
})
}
// UpdateUpdatedAt sets the "updated_at" field to the value that was provided on create.
func (u *FsEventUpsertOne) UpdateUpdatedAt() *FsEventUpsertOne {
return u.Update(func(s *FsEventUpsert) {
s.UpdateUpdatedAt()
})
}
// SetDeletedAt sets the "deleted_at" field.
func (u *FsEventUpsertOne) SetDeletedAt(v time.Time) *FsEventUpsertOne {
return u.Update(func(s *FsEventUpsert) {
s.SetDeletedAt(v)
})
}
// UpdateDeletedAt sets the "deleted_at" field to the value that was provided on create.
func (u *FsEventUpsertOne) UpdateDeletedAt() *FsEventUpsertOne {
return u.Update(func(s *FsEventUpsert) {
s.UpdateDeletedAt()
})
}
// ClearDeletedAt clears the value of the "deleted_at" field.
func (u *FsEventUpsertOne) ClearDeletedAt() *FsEventUpsertOne {
return u.Update(func(s *FsEventUpsert) {
s.ClearDeletedAt()
})
}
// SetEvent sets the "event" field.
func (u *FsEventUpsertOne) SetEvent(v string) *FsEventUpsertOne {
return u.Update(func(s *FsEventUpsert) {
s.SetEvent(v)
})
}
// UpdateEvent sets the "event" field to the value that was provided on create.
func (u *FsEventUpsertOne) UpdateEvent() *FsEventUpsertOne {
return u.Update(func(s *FsEventUpsert) {
s.UpdateEvent()
})
}
// SetSubscriber sets the "subscriber" field.
func (u *FsEventUpsertOne) SetSubscriber(v uuid.UUID) *FsEventUpsertOne {
return u.Update(func(s *FsEventUpsert) {
s.SetSubscriber(v)
})
}
// UpdateSubscriber sets the "subscriber" field to the value that was provided on create.
func (u *FsEventUpsertOne) UpdateSubscriber() *FsEventUpsertOne {
return u.Update(func(s *FsEventUpsert) {
s.UpdateSubscriber()
})
}
// SetUserFsevent sets the "user_fsevent" field.
func (u *FsEventUpsertOne) SetUserFsevent(v int) *FsEventUpsertOne {
return u.Update(func(s *FsEventUpsert) {
s.SetUserFsevent(v)
})
}
// UpdateUserFsevent sets the "user_fsevent" field to the value that was provided on create.
func (u *FsEventUpsertOne) UpdateUserFsevent() *FsEventUpsertOne {
return u.Update(func(s *FsEventUpsert) {
s.UpdateUserFsevent()
})
}
// ClearUserFsevent clears the value of the "user_fsevent" field.
func (u *FsEventUpsertOne) ClearUserFsevent() *FsEventUpsertOne {
return u.Update(func(s *FsEventUpsert) {
s.ClearUserFsevent()
})
}
// Exec executes the query.
func (u *FsEventUpsertOne) Exec(ctx context.Context) error {
if len(u.create.conflict) == 0 {
return errors.New("ent: missing options for FsEventCreate.OnConflict")
}
return u.create.Exec(ctx)
}
// ExecX is like Exec, but panics if an error occurs.
func (u *FsEventUpsertOne) 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 *FsEventUpsertOne) 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 *FsEventUpsertOne) IDX(ctx context.Context) int {
id, err := u.ID(ctx)
if err != nil {
panic(err)
}
return id
}
func (m *FsEventCreate) SetRawID(t int) *FsEventCreate {
m.mutation.SetRawID(t)
return m
}
// FsEventCreateBulk is the builder for creating many FsEvent entities in bulk.
type FsEventCreateBulk struct {
config
err error
builders []*FsEventCreate
conflict []sql.ConflictOption
}
// Save creates the FsEvent entities in the database.
func (fecb *FsEventCreateBulk) Save(ctx context.Context) ([]*FsEvent, error) {
if fecb.err != nil {
return nil, fecb.err
}
specs := make([]*sqlgraph.CreateSpec, len(fecb.builders))
nodes := make([]*FsEvent, len(fecb.builders))
mutators := make([]Mutator, len(fecb.builders))
for i := range fecb.builders {
func(i int, root context.Context) {
builder := fecb.builders[i]
builder.defaults()
var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) {
mutation, ok := m.(*FsEventMutation)
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, fecb.builders[i+1].mutation)
} else {
spec := &sqlgraph.BatchCreateSpec{Nodes: specs}
spec.OnConflict = fecb.conflict
// Invoke the actual operation on the latest mutation in the chain.
if err = sqlgraph.BatchCreate(ctx, fecb.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, fecb.builders[0].mutation); err != nil {
return nil, err
}
}
return nodes, nil
}
// SaveX is like Save, but panics if an error occurs.
func (fecb *FsEventCreateBulk) SaveX(ctx context.Context) []*FsEvent {
v, err := fecb.Save(ctx)
if err != nil {
panic(err)
}
return v
}
// Exec executes the query.
func (fecb *FsEventCreateBulk) Exec(ctx context.Context) error {
_, err := fecb.Save(ctx)
return err
}
// ExecX is like Exec, but panics if an error occurs.
func (fecb *FsEventCreateBulk) ExecX(ctx context.Context) {
if err := fecb.Exec(ctx); err != nil {
panic(err)
}
}
// OnConflict allows configuring the `ON CONFLICT` / `ON DUPLICATE KEY` clause
// of the `INSERT` statement. For example:
//
// client.FsEvent.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.FsEventUpsert) {
// SetCreatedAt(v+v).
// }).
// Exec(ctx)
func (fecb *FsEventCreateBulk) OnConflict(opts ...sql.ConflictOption) *FsEventUpsertBulk {
fecb.conflict = opts
return &FsEventUpsertBulk{
create: fecb,
}
}
// OnConflictColumns calls `OnConflict` and configures the columns
// as conflict target. Using this option is equivalent to using:
//
// client.FsEvent.Create().
// OnConflict(sql.ConflictColumns(columns...)).
// Exec(ctx)
func (fecb *FsEventCreateBulk) OnConflictColumns(columns ...string) *FsEventUpsertBulk {
fecb.conflict = append(fecb.conflict, sql.ConflictColumns(columns...))
return &FsEventUpsertBulk{
create: fecb,
}
}
// FsEventUpsertBulk is the builder for "upsert"-ing
// a bulk of FsEvent nodes.
type FsEventUpsertBulk struct {
create *FsEventCreateBulk
}
// UpdateNewValues updates the mutable fields using the new values that
// were set on create. Using this option is equivalent to using:
//
// client.FsEvent.Create().
// OnConflict(
// sql.ResolveWithNewValues(),
// ).
// Exec(ctx)
func (u *FsEventUpsertBulk) UpdateNewValues() *FsEventUpsertBulk {
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(fsevent.FieldCreatedAt)
}
}
}))
return u
}
// Ignore sets each column to itself in case of conflict.
// Using this option is equivalent to using:
//
// client.FsEvent.Create().
// OnConflict(sql.ResolveWithIgnore()).
// Exec(ctx)
func (u *FsEventUpsertBulk) Ignore() *FsEventUpsertBulk {
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 *FsEventUpsertBulk) DoNothing() *FsEventUpsertBulk {
u.create.conflict = append(u.create.conflict, sql.DoNothing())
return u
}
// Update allows overriding fields `UPDATE` values. See the FsEventCreateBulk.OnConflict
// documentation for more info.
func (u *FsEventUpsertBulk) Update(set func(*FsEventUpsert)) *FsEventUpsertBulk {
u.create.conflict = append(u.create.conflict, sql.ResolveWith(func(update *sql.UpdateSet) {
set(&FsEventUpsert{UpdateSet: update})
}))
return u
}
// SetUpdatedAt sets the "updated_at" field.
func (u *FsEventUpsertBulk) SetUpdatedAt(v time.Time) *FsEventUpsertBulk {
return u.Update(func(s *FsEventUpsert) {
s.SetUpdatedAt(v)
})
}
// UpdateUpdatedAt sets the "updated_at" field to the value that was provided on create.
func (u *FsEventUpsertBulk) UpdateUpdatedAt() *FsEventUpsertBulk {
return u.Update(func(s *FsEventUpsert) {
s.UpdateUpdatedAt()
})
}
// SetDeletedAt sets the "deleted_at" field.
func (u *FsEventUpsertBulk) SetDeletedAt(v time.Time) *FsEventUpsertBulk {
return u.Update(func(s *FsEventUpsert) {
s.SetDeletedAt(v)
})
}
// UpdateDeletedAt sets the "deleted_at" field to the value that was provided on create.
func (u *FsEventUpsertBulk) UpdateDeletedAt() *FsEventUpsertBulk {
return u.Update(func(s *FsEventUpsert) {
s.UpdateDeletedAt()
})
}
// ClearDeletedAt clears the value of the "deleted_at" field.
func (u *FsEventUpsertBulk) ClearDeletedAt() *FsEventUpsertBulk {
return u.Update(func(s *FsEventUpsert) {
s.ClearDeletedAt()
})
}
// SetEvent sets the "event" field.
func (u *FsEventUpsertBulk) SetEvent(v string) *FsEventUpsertBulk {
return u.Update(func(s *FsEventUpsert) {
s.SetEvent(v)
})
}
// UpdateEvent sets the "event" field to the value that was provided on create.
func (u *FsEventUpsertBulk) UpdateEvent() *FsEventUpsertBulk {
return u.Update(func(s *FsEventUpsert) {
s.UpdateEvent()
})
}
// SetSubscriber sets the "subscriber" field.
func (u *FsEventUpsertBulk) SetSubscriber(v uuid.UUID) *FsEventUpsertBulk {
return u.Update(func(s *FsEventUpsert) {
s.SetSubscriber(v)
})
}
// UpdateSubscriber sets the "subscriber" field to the value that was provided on create.
func (u *FsEventUpsertBulk) UpdateSubscriber() *FsEventUpsertBulk {
return u.Update(func(s *FsEventUpsert) {
s.UpdateSubscriber()
})
}
// SetUserFsevent sets the "user_fsevent" field.
func (u *FsEventUpsertBulk) SetUserFsevent(v int) *FsEventUpsertBulk {
return u.Update(func(s *FsEventUpsert) {
s.SetUserFsevent(v)
})
}
// UpdateUserFsevent sets the "user_fsevent" field to the value that was provided on create.
func (u *FsEventUpsertBulk) UpdateUserFsevent() *FsEventUpsertBulk {
return u.Update(func(s *FsEventUpsert) {
s.UpdateUserFsevent()
})
}
// ClearUserFsevent clears the value of the "user_fsevent" field.
func (u *FsEventUpsertBulk) ClearUserFsevent() *FsEventUpsertBulk {
return u.Update(func(s *FsEventUpsert) {
s.ClearUserFsevent()
})
}
// Exec executes the query.
func (u *FsEventUpsertBulk) 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 FsEventCreateBulk instead", i)
}
}
if len(u.create.conflict) == 0 {
return errors.New("ent: missing options for FsEventCreateBulk.OnConflict")
}
return u.create.Exec(ctx)
}
// ExecX is like Exec, but panics if an error occurs.
func (u *FsEventUpsertBulk) ExecX(ctx context.Context) {
if err := u.create.Exec(ctx); err != nil {
panic(err)
}
}

88
ent/fsevent_delete.go Normal file
View File

@ -0,0 +1,88 @@
// Code generated by ent, DO NOT EDIT.
package ent
import (
"context"
"entgo.io/ent/dialect/sql"
"entgo.io/ent/dialect/sql/sqlgraph"
"entgo.io/ent/schema/field"
"github.com/cloudreve/Cloudreve/v4/ent/fsevent"
"github.com/cloudreve/Cloudreve/v4/ent/predicate"
)
// FsEventDelete is the builder for deleting a FsEvent entity.
type FsEventDelete struct {
config
hooks []Hook
mutation *FsEventMutation
}
// Where appends a list predicates to the FsEventDelete builder.
func (fed *FsEventDelete) Where(ps ...predicate.FsEvent) *FsEventDelete {
fed.mutation.Where(ps...)
return fed
}
// Exec executes the deletion query and returns how many vertices were deleted.
func (fed *FsEventDelete) Exec(ctx context.Context) (int, error) {
return withHooks(ctx, fed.sqlExec, fed.mutation, fed.hooks)
}
// ExecX is like Exec, but panics if an error occurs.
func (fed *FsEventDelete) ExecX(ctx context.Context) int {
n, err := fed.Exec(ctx)
if err != nil {
panic(err)
}
return n
}
func (fed *FsEventDelete) sqlExec(ctx context.Context) (int, error) {
_spec := sqlgraph.NewDeleteSpec(fsevent.Table, sqlgraph.NewFieldSpec(fsevent.FieldID, field.TypeInt))
if ps := fed.mutation.predicates; len(ps) > 0 {
_spec.Predicate = func(selector *sql.Selector) {
for i := range ps {
ps[i](selector)
}
}
}
affected, err := sqlgraph.DeleteNodes(ctx, fed.driver, _spec)
if err != nil && sqlgraph.IsConstraintError(err) {
err = &ConstraintError{msg: err.Error(), wrap: err}
}
fed.mutation.done = true
return affected, err
}
// FsEventDeleteOne is the builder for deleting a single FsEvent entity.
type FsEventDeleteOne struct {
fed *FsEventDelete
}
// Where appends a list predicates to the FsEventDelete builder.
func (fedo *FsEventDeleteOne) Where(ps ...predicate.FsEvent) *FsEventDeleteOne {
fedo.fed.mutation.Where(ps...)
return fedo
}
// Exec executes the deletion query.
func (fedo *FsEventDeleteOne) Exec(ctx context.Context) error {
n, err := fedo.fed.Exec(ctx)
switch {
case err != nil:
return err
case n == 0:
return &NotFoundError{fsevent.Label}
default:
return nil
}
}
// ExecX is like Exec, but panics if an error occurs.
func (fedo *FsEventDeleteOne) ExecX(ctx context.Context) {
if err := fedo.Exec(ctx); err != nil {
panic(err)
}
}

605
ent/fsevent_query.go Normal file
View File

@ -0,0 +1,605 @@
// 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/fsevent"
"github.com/cloudreve/Cloudreve/v4/ent/predicate"
"github.com/cloudreve/Cloudreve/v4/ent/user"
)
// FsEventQuery is the builder for querying FsEvent entities.
type FsEventQuery struct {
config
ctx *QueryContext
order []fsevent.OrderOption
inters []Interceptor
predicates []predicate.FsEvent
withUser *UserQuery
// intermediate query (i.e. traversal path).
sql *sql.Selector
path func(context.Context) (*sql.Selector, error)
}
// Where adds a new predicate for the FsEventQuery builder.
func (feq *FsEventQuery) Where(ps ...predicate.FsEvent) *FsEventQuery {
feq.predicates = append(feq.predicates, ps...)
return feq
}
// Limit the number of records to be returned by this query.
func (feq *FsEventQuery) Limit(limit int) *FsEventQuery {
feq.ctx.Limit = &limit
return feq
}
// Offset to start from.
func (feq *FsEventQuery) Offset(offset int) *FsEventQuery {
feq.ctx.Offset = &offset
return feq
}
// 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 (feq *FsEventQuery) Unique(unique bool) *FsEventQuery {
feq.ctx.Unique = &unique
return feq
}
// Order specifies how the records should be ordered.
func (feq *FsEventQuery) Order(o ...fsevent.OrderOption) *FsEventQuery {
feq.order = append(feq.order, o...)
return feq
}
// QueryUser chains the current query on the "user" edge.
func (feq *FsEventQuery) QueryUser() *UserQuery {
query := (&UserClient{config: feq.config}).Query()
query.path = func(ctx context.Context) (fromU *sql.Selector, err error) {
if err := feq.prepareQuery(ctx); err != nil {
return nil, err
}
selector := feq.sqlQuery(ctx)
if err := selector.Err(); err != nil {
return nil, err
}
step := sqlgraph.NewStep(
sqlgraph.From(fsevent.Table, fsevent.FieldID, selector),
sqlgraph.To(user.Table, user.FieldID),
sqlgraph.Edge(sqlgraph.M2O, true, fsevent.UserTable, fsevent.UserColumn),
)
fromU = sqlgraph.SetNeighbors(feq.driver.Dialect(), step)
return fromU, nil
}
return query
}
// First returns the first FsEvent entity from the query.
// Returns a *NotFoundError when no FsEvent was found.
func (feq *FsEventQuery) First(ctx context.Context) (*FsEvent, error) {
nodes, err := feq.Limit(1).All(setContextOp(ctx, feq.ctx, "First"))
if err != nil {
return nil, err
}
if len(nodes) == 0 {
return nil, &NotFoundError{fsevent.Label}
}
return nodes[0], nil
}
// FirstX is like First, but panics if an error occurs.
func (feq *FsEventQuery) FirstX(ctx context.Context) *FsEvent {
node, err := feq.First(ctx)
if err != nil && !IsNotFound(err) {
panic(err)
}
return node
}
// FirstID returns the first FsEvent ID from the query.
// Returns a *NotFoundError when no FsEvent ID was found.
func (feq *FsEventQuery) FirstID(ctx context.Context) (id int, err error) {
var ids []int
if ids, err = feq.Limit(1).IDs(setContextOp(ctx, feq.ctx, "FirstID")); err != nil {
return
}
if len(ids) == 0 {
err = &NotFoundError{fsevent.Label}
return
}
return ids[0], nil
}
// FirstIDX is like FirstID, but panics if an error occurs.
func (feq *FsEventQuery) FirstIDX(ctx context.Context) int {
id, err := feq.FirstID(ctx)
if err != nil && !IsNotFound(err) {
panic(err)
}
return id
}
// Only returns a single FsEvent entity found by the query, ensuring it only returns one.
// Returns a *NotSingularError when more than one FsEvent entity is found.
// Returns a *NotFoundError when no FsEvent entities are found.
func (feq *FsEventQuery) Only(ctx context.Context) (*FsEvent, error) {
nodes, err := feq.Limit(2).All(setContextOp(ctx, feq.ctx, "Only"))
if err != nil {
return nil, err
}
switch len(nodes) {
case 1:
return nodes[0], nil
case 0:
return nil, &NotFoundError{fsevent.Label}
default:
return nil, &NotSingularError{fsevent.Label}
}
}
// OnlyX is like Only, but panics if an error occurs.
func (feq *FsEventQuery) OnlyX(ctx context.Context) *FsEvent {
node, err := feq.Only(ctx)
if err != nil {
panic(err)
}
return node
}
// OnlyID is like Only, but returns the only FsEvent ID in the query.
// Returns a *NotSingularError when more than one FsEvent ID is found.
// Returns a *NotFoundError when no entities are found.
func (feq *FsEventQuery) OnlyID(ctx context.Context) (id int, err error) {
var ids []int
if ids, err = feq.Limit(2).IDs(setContextOp(ctx, feq.ctx, "OnlyID")); err != nil {
return
}
switch len(ids) {
case 1:
id = ids[0]
case 0:
err = &NotFoundError{fsevent.Label}
default:
err = &NotSingularError{fsevent.Label}
}
return
}
// OnlyIDX is like OnlyID, but panics if an error occurs.
func (feq *FsEventQuery) OnlyIDX(ctx context.Context) int {
id, err := feq.OnlyID(ctx)
if err != nil {
panic(err)
}
return id
}
// All executes the query and returns a list of FsEvents.
func (feq *FsEventQuery) All(ctx context.Context) ([]*FsEvent, error) {
ctx = setContextOp(ctx, feq.ctx, "All")
if err := feq.prepareQuery(ctx); err != nil {
return nil, err
}
qr := querierAll[[]*FsEvent, *FsEventQuery]()
return withInterceptors[[]*FsEvent](ctx, feq, qr, feq.inters)
}
// AllX is like All, but panics if an error occurs.
func (feq *FsEventQuery) AllX(ctx context.Context) []*FsEvent {
nodes, err := feq.All(ctx)
if err != nil {
panic(err)
}
return nodes
}
// IDs executes the query and returns a list of FsEvent IDs.
func (feq *FsEventQuery) IDs(ctx context.Context) (ids []int, err error) {
if feq.ctx.Unique == nil && feq.path != nil {
feq.Unique(true)
}
ctx = setContextOp(ctx, feq.ctx, "IDs")
if err = feq.Select(fsevent.FieldID).Scan(ctx, &ids); err != nil {
return nil, err
}
return ids, nil
}
// IDsX is like IDs, but panics if an error occurs.
func (feq *FsEventQuery) IDsX(ctx context.Context) []int {
ids, err := feq.IDs(ctx)
if err != nil {
panic(err)
}
return ids
}
// Count returns the count of the given query.
func (feq *FsEventQuery) Count(ctx context.Context) (int, error) {
ctx = setContextOp(ctx, feq.ctx, "Count")
if err := feq.prepareQuery(ctx); err != nil {
return 0, err
}
return withInterceptors[int](ctx, feq, querierCount[*FsEventQuery](), feq.inters)
}
// CountX is like Count, but panics if an error occurs.
func (feq *FsEventQuery) CountX(ctx context.Context) int {
count, err := feq.Count(ctx)
if err != nil {
panic(err)
}
return count
}
// Exist returns true if the query has elements in the graph.
func (feq *FsEventQuery) Exist(ctx context.Context) (bool, error) {
ctx = setContextOp(ctx, feq.ctx, "Exist")
switch _, err := feq.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 (feq *FsEventQuery) ExistX(ctx context.Context) bool {
exist, err := feq.Exist(ctx)
if err != nil {
panic(err)
}
return exist
}
// Clone returns a duplicate of the FsEventQuery builder, including all associated steps. It can be
// used to prepare common query builders and use them differently after the clone is made.
func (feq *FsEventQuery) Clone() *FsEventQuery {
if feq == nil {
return nil
}
return &FsEventQuery{
config: feq.config,
ctx: feq.ctx.Clone(),
order: append([]fsevent.OrderOption{}, feq.order...),
inters: append([]Interceptor{}, feq.inters...),
predicates: append([]predicate.FsEvent{}, feq.predicates...),
withUser: feq.withUser.Clone(),
// clone intermediate query.
sql: feq.sql.Clone(),
path: feq.path,
}
}
// WithUser tells the query-builder to eager-load the nodes that are connected to
// the "user" edge. The optional arguments are used to configure the query builder of the edge.
func (feq *FsEventQuery) WithUser(opts ...func(*UserQuery)) *FsEventQuery {
query := (&UserClient{config: feq.config}).Query()
for _, opt := range opts {
opt(query)
}
feq.withUser = query
return feq
}
// 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.FsEvent.Query().
// GroupBy(fsevent.FieldCreatedAt).
// Aggregate(ent.Count()).
// Scan(ctx, &v)
func (feq *FsEventQuery) GroupBy(field string, fields ...string) *FsEventGroupBy {
feq.ctx.Fields = append([]string{field}, fields...)
grbuild := &FsEventGroupBy{build: feq}
grbuild.flds = &feq.ctx.Fields
grbuild.label = fsevent.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.FsEvent.Query().
// Select(fsevent.FieldCreatedAt).
// Scan(ctx, &v)
func (feq *FsEventQuery) Select(fields ...string) *FsEventSelect {
feq.ctx.Fields = append(feq.ctx.Fields, fields...)
sbuild := &FsEventSelect{FsEventQuery: feq}
sbuild.label = fsevent.Label
sbuild.flds, sbuild.scan = &feq.ctx.Fields, sbuild.Scan
return sbuild
}
// Aggregate returns a FsEventSelect configured with the given aggregations.
func (feq *FsEventQuery) Aggregate(fns ...AggregateFunc) *FsEventSelect {
return feq.Select().Aggregate(fns...)
}
func (feq *FsEventQuery) prepareQuery(ctx context.Context) error {
for _, inter := range feq.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, feq); err != nil {
return err
}
}
}
for _, f := range feq.ctx.Fields {
if !fsevent.ValidColumn(f) {
return &ValidationError{Name: f, err: fmt.Errorf("ent: invalid field %q for query", f)}
}
}
if feq.path != nil {
prev, err := feq.path(ctx)
if err != nil {
return err
}
feq.sql = prev
}
return nil
}
func (feq *FsEventQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*FsEvent, error) {
var (
nodes = []*FsEvent{}
_spec = feq.querySpec()
loadedTypes = [1]bool{
feq.withUser != nil,
}
)
_spec.ScanValues = func(columns []string) ([]any, error) {
return (*FsEvent).scanValues(nil, columns)
}
_spec.Assign = func(columns []string, values []any) error {
node := &FsEvent{config: feq.config}
nodes = append(nodes, node)
node.Edges.loadedTypes = loadedTypes
return node.assignValues(columns, values)
}
for i := range hooks {
hooks[i](ctx, _spec)
}
if err := sqlgraph.QueryNodes(ctx, feq.driver, _spec); err != nil {
return nil, err
}
if len(nodes) == 0 {
return nodes, nil
}
if query := feq.withUser; query != nil {
if err := feq.loadUser(ctx, query, nodes, nil,
func(n *FsEvent, e *User) { n.Edges.User = e }); err != nil {
return nil, err
}
}
return nodes, nil
}
func (feq *FsEventQuery) loadUser(ctx context.Context, query *UserQuery, nodes []*FsEvent, init func(*FsEvent), assign func(*FsEvent, *User)) error {
ids := make([]int, 0, len(nodes))
nodeids := make(map[int][]*FsEvent)
for i := range nodes {
fk := nodes[i].UserFsevent
if _, ok := nodeids[fk]; !ok {
ids = append(ids, fk)
}
nodeids[fk] = append(nodeids[fk], nodes[i])
}
if len(ids) == 0 {
return nil
}
query.Where(user.IDIn(ids...))
neighbors, err := query.All(ctx)
if err != nil {
return err
}
for _, n := range neighbors {
nodes, ok := nodeids[n.ID]
if !ok {
return fmt.Errorf(`unexpected foreign-key "user_fsevent" returned %v`, n.ID)
}
for i := range nodes {
assign(nodes[i], n)
}
}
return nil
}
func (feq *FsEventQuery) sqlCount(ctx context.Context) (int, error) {
_spec := feq.querySpec()
_spec.Node.Columns = feq.ctx.Fields
if len(feq.ctx.Fields) > 0 {
_spec.Unique = feq.ctx.Unique != nil && *feq.ctx.Unique
}
return sqlgraph.CountNodes(ctx, feq.driver, _spec)
}
func (feq *FsEventQuery) querySpec() *sqlgraph.QuerySpec {
_spec := sqlgraph.NewQuerySpec(fsevent.Table, fsevent.Columns, sqlgraph.NewFieldSpec(fsevent.FieldID, field.TypeInt))
_spec.From = feq.sql
if unique := feq.ctx.Unique; unique != nil {
_spec.Unique = *unique
} else if feq.path != nil {
_spec.Unique = true
}
if fields := feq.ctx.Fields; len(fields) > 0 {
_spec.Node.Columns = make([]string, 0, len(fields))
_spec.Node.Columns = append(_spec.Node.Columns, fsevent.FieldID)
for i := range fields {
if fields[i] != fsevent.FieldID {
_spec.Node.Columns = append(_spec.Node.Columns, fields[i])
}
}
if feq.withUser != nil {
_spec.Node.AddColumnOnce(fsevent.FieldUserFsevent)
}
}
if ps := feq.predicates; len(ps) > 0 {
_spec.Predicate = func(selector *sql.Selector) {
for i := range ps {
ps[i](selector)
}
}
}
if limit := feq.ctx.Limit; limit != nil {
_spec.Limit = *limit
}
if offset := feq.ctx.Offset; offset != nil {
_spec.Offset = *offset
}
if ps := feq.order; len(ps) > 0 {
_spec.Order = func(selector *sql.Selector) {
for i := range ps {
ps[i](selector)
}
}
}
return _spec
}
func (feq *FsEventQuery) sqlQuery(ctx context.Context) *sql.Selector {
builder := sql.Dialect(feq.driver.Dialect())
t1 := builder.Table(fsevent.Table)
columns := feq.ctx.Fields
if len(columns) == 0 {
columns = fsevent.Columns
}
selector := builder.Select(t1.Columns(columns...)...).From(t1)
if feq.sql != nil {
selector = feq.sql
selector.Select(selector.Columns(columns...)...)
}
if feq.ctx.Unique != nil && *feq.ctx.Unique {
selector.Distinct()
}
for _, p := range feq.predicates {
p(selector)
}
for _, p := range feq.order {
p(selector)
}
if offset := feq.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 := feq.ctx.Limit; limit != nil {
selector.Limit(*limit)
}
return selector
}
// FsEventGroupBy is the group-by builder for FsEvent entities.
type FsEventGroupBy struct {
selector
build *FsEventQuery
}
// Aggregate adds the given aggregation functions to the group-by query.
func (fegb *FsEventGroupBy) Aggregate(fns ...AggregateFunc) *FsEventGroupBy {
fegb.fns = append(fegb.fns, fns...)
return fegb
}
// Scan applies the selector query and scans the result into the given value.
func (fegb *FsEventGroupBy) Scan(ctx context.Context, v any) error {
ctx = setContextOp(ctx, fegb.build.ctx, "GroupBy")
if err := fegb.build.prepareQuery(ctx); err != nil {
return err
}
return scanWithInterceptors[*FsEventQuery, *FsEventGroupBy](ctx, fegb.build, fegb, fegb.build.inters, v)
}
func (fegb *FsEventGroupBy) sqlScan(ctx context.Context, root *FsEventQuery, v any) error {
selector := root.sqlQuery(ctx).Select()
aggregation := make([]string, 0, len(fegb.fns))
for _, fn := range fegb.fns {
aggregation = append(aggregation, fn(selector))
}
if len(selector.SelectedColumns()) == 0 {
columns := make([]string, 0, len(*fegb.flds)+len(fegb.fns))
for _, f := range *fegb.flds {
columns = append(columns, selector.C(f))
}
columns = append(columns, aggregation...)
selector.Select(columns...)
}
selector.GroupBy(selector.Columns(*fegb.flds...)...)
if err := selector.Err(); err != nil {
return err
}
rows := &sql.Rows{}
query, args := selector.Query()
if err := fegb.build.driver.Query(ctx, query, args, rows); err != nil {
return err
}
defer rows.Close()
return sql.ScanSlice(rows, v)
}
// FsEventSelect is the builder for selecting fields of FsEvent entities.
type FsEventSelect struct {
*FsEventQuery
selector
}
// Aggregate adds the given aggregation functions to the selector query.
func (fes *FsEventSelect) Aggregate(fns ...AggregateFunc) *FsEventSelect {
fes.fns = append(fes.fns, fns...)
return fes
}
// Scan applies the selector query and scans the result into the given value.
func (fes *FsEventSelect) Scan(ctx context.Context, v any) error {
ctx = setContextOp(ctx, fes.ctx, "Select")
if err := fes.prepareQuery(ctx); err != nil {
return err
}
return scanWithInterceptors[*FsEventQuery, *FsEventSelect](ctx, fes.FsEventQuery, fes, fes.inters, v)
}
func (fes *FsEventSelect) sqlScan(ctx context.Context, root *FsEventQuery, v any) error {
selector := root.sqlQuery(ctx)
aggregation := make([]string, 0, len(fes.fns))
for _, fn := range fes.fns {
aggregation = append(aggregation, fn(selector))
}
switch n := len(*fes.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 := fes.driver.Query(ctx, query, args, rows); err != nil {
return err
}
defer rows.Close()
return sql.ScanSlice(rows, v)
}

494
ent/fsevent_update.go Normal file
View File

@ -0,0 +1,494 @@
// 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/fsevent"
"github.com/cloudreve/Cloudreve/v4/ent/predicate"
"github.com/cloudreve/Cloudreve/v4/ent/user"
"github.com/gofrs/uuid"
)
// FsEventUpdate is the builder for updating FsEvent entities.
type FsEventUpdate struct {
config
hooks []Hook
mutation *FsEventMutation
}
// Where appends a list predicates to the FsEventUpdate builder.
func (feu *FsEventUpdate) Where(ps ...predicate.FsEvent) *FsEventUpdate {
feu.mutation.Where(ps...)
return feu
}
// SetUpdatedAt sets the "updated_at" field.
func (feu *FsEventUpdate) SetUpdatedAt(t time.Time) *FsEventUpdate {
feu.mutation.SetUpdatedAt(t)
return feu
}
// SetDeletedAt sets the "deleted_at" field.
func (feu *FsEventUpdate) SetDeletedAt(t time.Time) *FsEventUpdate {
feu.mutation.SetDeletedAt(t)
return feu
}
// SetNillableDeletedAt sets the "deleted_at" field if the given value is not nil.
func (feu *FsEventUpdate) SetNillableDeletedAt(t *time.Time) *FsEventUpdate {
if t != nil {
feu.SetDeletedAt(*t)
}
return feu
}
// ClearDeletedAt clears the value of the "deleted_at" field.
func (feu *FsEventUpdate) ClearDeletedAt() *FsEventUpdate {
feu.mutation.ClearDeletedAt()
return feu
}
// SetEvent sets the "event" field.
func (feu *FsEventUpdate) SetEvent(s string) *FsEventUpdate {
feu.mutation.SetEvent(s)
return feu
}
// SetNillableEvent sets the "event" field if the given value is not nil.
func (feu *FsEventUpdate) SetNillableEvent(s *string) *FsEventUpdate {
if s != nil {
feu.SetEvent(*s)
}
return feu
}
// SetSubscriber sets the "subscriber" field.
func (feu *FsEventUpdate) SetSubscriber(u uuid.UUID) *FsEventUpdate {
feu.mutation.SetSubscriber(u)
return feu
}
// SetNillableSubscriber sets the "subscriber" field if the given value is not nil.
func (feu *FsEventUpdate) SetNillableSubscriber(u *uuid.UUID) *FsEventUpdate {
if u != nil {
feu.SetSubscriber(*u)
}
return feu
}
// SetUserFsevent sets the "user_fsevent" field.
func (feu *FsEventUpdate) SetUserFsevent(i int) *FsEventUpdate {
feu.mutation.SetUserFsevent(i)
return feu
}
// SetNillableUserFsevent sets the "user_fsevent" field if the given value is not nil.
func (feu *FsEventUpdate) SetNillableUserFsevent(i *int) *FsEventUpdate {
if i != nil {
feu.SetUserFsevent(*i)
}
return feu
}
// ClearUserFsevent clears the value of the "user_fsevent" field.
func (feu *FsEventUpdate) ClearUserFsevent() *FsEventUpdate {
feu.mutation.ClearUserFsevent()
return feu
}
// SetUserID sets the "user" edge to the User entity by ID.
func (feu *FsEventUpdate) SetUserID(id int) *FsEventUpdate {
feu.mutation.SetUserID(id)
return feu
}
// SetNillableUserID sets the "user" edge to the User entity by ID if the given value is not nil.
func (feu *FsEventUpdate) SetNillableUserID(id *int) *FsEventUpdate {
if id != nil {
feu = feu.SetUserID(*id)
}
return feu
}
// SetUser sets the "user" edge to the User entity.
func (feu *FsEventUpdate) SetUser(u *User) *FsEventUpdate {
return feu.SetUserID(u.ID)
}
// Mutation returns the FsEventMutation object of the builder.
func (feu *FsEventUpdate) Mutation() *FsEventMutation {
return feu.mutation
}
// ClearUser clears the "user" edge to the User entity.
func (feu *FsEventUpdate) ClearUser() *FsEventUpdate {
feu.mutation.ClearUser()
return feu
}
// Save executes the query and returns the number of nodes affected by the update operation.
func (feu *FsEventUpdate) Save(ctx context.Context) (int, error) {
if err := feu.defaults(); err != nil {
return 0, err
}
return withHooks(ctx, feu.sqlSave, feu.mutation, feu.hooks)
}
// SaveX is like Save, but panics if an error occurs.
func (feu *FsEventUpdate) SaveX(ctx context.Context) int {
affected, err := feu.Save(ctx)
if err != nil {
panic(err)
}
return affected
}
// Exec executes the query.
func (feu *FsEventUpdate) Exec(ctx context.Context) error {
_, err := feu.Save(ctx)
return err
}
// ExecX is like Exec, but panics if an error occurs.
func (feu *FsEventUpdate) ExecX(ctx context.Context) {
if err := feu.Exec(ctx); err != nil {
panic(err)
}
}
// defaults sets the default values of the builder before save.
func (feu *FsEventUpdate) defaults() error {
if _, ok := feu.mutation.UpdatedAt(); !ok {
if fsevent.UpdateDefaultUpdatedAt == nil {
return fmt.Errorf("ent: uninitialized fsevent.UpdateDefaultUpdatedAt (forgotten import ent/runtime?)")
}
v := fsevent.UpdateDefaultUpdatedAt()
feu.mutation.SetUpdatedAt(v)
}
return nil
}
func (feu *FsEventUpdate) sqlSave(ctx context.Context) (n int, err error) {
_spec := sqlgraph.NewUpdateSpec(fsevent.Table, fsevent.Columns, sqlgraph.NewFieldSpec(fsevent.FieldID, field.TypeInt))
if ps := feu.mutation.predicates; len(ps) > 0 {
_spec.Predicate = func(selector *sql.Selector) {
for i := range ps {
ps[i](selector)
}
}
}
if value, ok := feu.mutation.UpdatedAt(); ok {
_spec.SetField(fsevent.FieldUpdatedAt, field.TypeTime, value)
}
if value, ok := feu.mutation.DeletedAt(); ok {
_spec.SetField(fsevent.FieldDeletedAt, field.TypeTime, value)
}
if feu.mutation.DeletedAtCleared() {
_spec.ClearField(fsevent.FieldDeletedAt, field.TypeTime)
}
if value, ok := feu.mutation.Event(); ok {
_spec.SetField(fsevent.FieldEvent, field.TypeString, value)
}
if value, ok := feu.mutation.Subscriber(); ok {
_spec.SetField(fsevent.FieldSubscriber, field.TypeUUID, value)
}
if feu.mutation.UserCleared() {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.M2O,
Inverse: true,
Table: fsevent.UserTable,
Columns: []string{fsevent.UserColumn},
Bidi: false,
Target: &sqlgraph.EdgeTarget{
IDSpec: sqlgraph.NewFieldSpec(user.FieldID, field.TypeInt),
},
}
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
}
if nodes := feu.mutation.UserIDs(); len(nodes) > 0 {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.M2O,
Inverse: true,
Table: fsevent.UserTable,
Columns: []string{fsevent.UserColumn},
Bidi: false,
Target: &sqlgraph.EdgeTarget{
IDSpec: sqlgraph.NewFieldSpec(user.FieldID, field.TypeInt),
},
}
for _, k := range nodes {
edge.Target.Nodes = append(edge.Target.Nodes, k)
}
_spec.Edges.Add = append(_spec.Edges.Add, edge)
}
if n, err = sqlgraph.UpdateNodes(ctx, feu.driver, _spec); err != nil {
if _, ok := err.(*sqlgraph.NotFoundError); ok {
err = &NotFoundError{fsevent.Label}
} else if sqlgraph.IsConstraintError(err) {
err = &ConstraintError{msg: err.Error(), wrap: err}
}
return 0, err
}
feu.mutation.done = true
return n, nil
}
// FsEventUpdateOne is the builder for updating a single FsEvent entity.
type FsEventUpdateOne struct {
config
fields []string
hooks []Hook
mutation *FsEventMutation
}
// SetUpdatedAt sets the "updated_at" field.
func (feuo *FsEventUpdateOne) SetUpdatedAt(t time.Time) *FsEventUpdateOne {
feuo.mutation.SetUpdatedAt(t)
return feuo
}
// SetDeletedAt sets the "deleted_at" field.
func (feuo *FsEventUpdateOne) SetDeletedAt(t time.Time) *FsEventUpdateOne {
feuo.mutation.SetDeletedAt(t)
return feuo
}
// SetNillableDeletedAt sets the "deleted_at" field if the given value is not nil.
func (feuo *FsEventUpdateOne) SetNillableDeletedAt(t *time.Time) *FsEventUpdateOne {
if t != nil {
feuo.SetDeletedAt(*t)
}
return feuo
}
// ClearDeletedAt clears the value of the "deleted_at" field.
func (feuo *FsEventUpdateOne) ClearDeletedAt() *FsEventUpdateOne {
feuo.mutation.ClearDeletedAt()
return feuo
}
// SetEvent sets the "event" field.
func (feuo *FsEventUpdateOne) SetEvent(s string) *FsEventUpdateOne {
feuo.mutation.SetEvent(s)
return feuo
}
// SetNillableEvent sets the "event" field if the given value is not nil.
func (feuo *FsEventUpdateOne) SetNillableEvent(s *string) *FsEventUpdateOne {
if s != nil {
feuo.SetEvent(*s)
}
return feuo
}
// SetSubscriber sets the "subscriber" field.
func (feuo *FsEventUpdateOne) SetSubscriber(u uuid.UUID) *FsEventUpdateOne {
feuo.mutation.SetSubscriber(u)
return feuo
}
// SetNillableSubscriber sets the "subscriber" field if the given value is not nil.
func (feuo *FsEventUpdateOne) SetNillableSubscriber(u *uuid.UUID) *FsEventUpdateOne {
if u != nil {
feuo.SetSubscriber(*u)
}
return feuo
}
// SetUserFsevent sets the "user_fsevent" field.
func (feuo *FsEventUpdateOne) SetUserFsevent(i int) *FsEventUpdateOne {
feuo.mutation.SetUserFsevent(i)
return feuo
}
// SetNillableUserFsevent sets the "user_fsevent" field if the given value is not nil.
func (feuo *FsEventUpdateOne) SetNillableUserFsevent(i *int) *FsEventUpdateOne {
if i != nil {
feuo.SetUserFsevent(*i)
}
return feuo
}
// ClearUserFsevent clears the value of the "user_fsevent" field.
func (feuo *FsEventUpdateOne) ClearUserFsevent() *FsEventUpdateOne {
feuo.mutation.ClearUserFsevent()
return feuo
}
// SetUserID sets the "user" edge to the User entity by ID.
func (feuo *FsEventUpdateOne) SetUserID(id int) *FsEventUpdateOne {
feuo.mutation.SetUserID(id)
return feuo
}
// SetNillableUserID sets the "user" edge to the User entity by ID if the given value is not nil.
func (feuo *FsEventUpdateOne) SetNillableUserID(id *int) *FsEventUpdateOne {
if id != nil {
feuo = feuo.SetUserID(*id)
}
return feuo
}
// SetUser sets the "user" edge to the User entity.
func (feuo *FsEventUpdateOne) SetUser(u *User) *FsEventUpdateOne {
return feuo.SetUserID(u.ID)
}
// Mutation returns the FsEventMutation object of the builder.
func (feuo *FsEventUpdateOne) Mutation() *FsEventMutation {
return feuo.mutation
}
// ClearUser clears the "user" edge to the User entity.
func (feuo *FsEventUpdateOne) ClearUser() *FsEventUpdateOne {
feuo.mutation.ClearUser()
return feuo
}
// Where appends a list predicates to the FsEventUpdate builder.
func (feuo *FsEventUpdateOne) Where(ps ...predicate.FsEvent) *FsEventUpdateOne {
feuo.mutation.Where(ps...)
return feuo
}
// Select allows selecting one or more fields (columns) of the returned entity.
// The default is selecting all fields defined in the entity schema.
func (feuo *FsEventUpdateOne) Select(field string, fields ...string) *FsEventUpdateOne {
feuo.fields = append([]string{field}, fields...)
return feuo
}
// Save executes the query and returns the updated FsEvent entity.
func (feuo *FsEventUpdateOne) Save(ctx context.Context) (*FsEvent, error) {
if err := feuo.defaults(); err != nil {
return nil, err
}
return withHooks(ctx, feuo.sqlSave, feuo.mutation, feuo.hooks)
}
// SaveX is like Save, but panics if an error occurs.
func (feuo *FsEventUpdateOne) SaveX(ctx context.Context) *FsEvent {
node, err := feuo.Save(ctx)
if err != nil {
panic(err)
}
return node
}
// Exec executes the query on the entity.
func (feuo *FsEventUpdateOne) Exec(ctx context.Context) error {
_, err := feuo.Save(ctx)
return err
}
// ExecX is like Exec, but panics if an error occurs.
func (feuo *FsEventUpdateOne) ExecX(ctx context.Context) {
if err := feuo.Exec(ctx); err != nil {
panic(err)
}
}
// defaults sets the default values of the builder before save.
func (feuo *FsEventUpdateOne) defaults() error {
if _, ok := feuo.mutation.UpdatedAt(); !ok {
if fsevent.UpdateDefaultUpdatedAt == nil {
return fmt.Errorf("ent: uninitialized fsevent.UpdateDefaultUpdatedAt (forgotten import ent/runtime?)")
}
v := fsevent.UpdateDefaultUpdatedAt()
feuo.mutation.SetUpdatedAt(v)
}
return nil
}
func (feuo *FsEventUpdateOne) sqlSave(ctx context.Context) (_node *FsEvent, err error) {
_spec := sqlgraph.NewUpdateSpec(fsevent.Table, fsevent.Columns, sqlgraph.NewFieldSpec(fsevent.FieldID, field.TypeInt))
id, ok := feuo.mutation.ID()
if !ok {
return nil, &ValidationError{Name: "id", err: errors.New(`ent: missing "FsEvent.id" for update`)}
}
_spec.Node.ID.Value = id
if fields := feuo.fields; len(fields) > 0 {
_spec.Node.Columns = make([]string, 0, len(fields))
_spec.Node.Columns = append(_spec.Node.Columns, fsevent.FieldID)
for _, f := range fields {
if !fsevent.ValidColumn(f) {
return nil, &ValidationError{Name: f, err: fmt.Errorf("ent: invalid field %q for query", f)}
}
if f != fsevent.FieldID {
_spec.Node.Columns = append(_spec.Node.Columns, f)
}
}
}
if ps := feuo.mutation.predicates; len(ps) > 0 {
_spec.Predicate = func(selector *sql.Selector) {
for i := range ps {
ps[i](selector)
}
}
}
if value, ok := feuo.mutation.UpdatedAt(); ok {
_spec.SetField(fsevent.FieldUpdatedAt, field.TypeTime, value)
}
if value, ok := feuo.mutation.DeletedAt(); ok {
_spec.SetField(fsevent.FieldDeletedAt, field.TypeTime, value)
}
if feuo.mutation.DeletedAtCleared() {
_spec.ClearField(fsevent.FieldDeletedAt, field.TypeTime)
}
if value, ok := feuo.mutation.Event(); ok {
_spec.SetField(fsevent.FieldEvent, field.TypeString, value)
}
if value, ok := feuo.mutation.Subscriber(); ok {
_spec.SetField(fsevent.FieldSubscriber, field.TypeUUID, value)
}
if feuo.mutation.UserCleared() {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.M2O,
Inverse: true,
Table: fsevent.UserTable,
Columns: []string{fsevent.UserColumn},
Bidi: false,
Target: &sqlgraph.EdgeTarget{
IDSpec: sqlgraph.NewFieldSpec(user.FieldID, field.TypeInt),
},
}
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
}
if nodes := feuo.mutation.UserIDs(); len(nodes) > 0 {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.M2O,
Inverse: true,
Table: fsevent.UserTable,
Columns: []string{fsevent.UserColumn},
Bidi: false,
Target: &sqlgraph.EdgeTarget{
IDSpec: sqlgraph.NewFieldSpec(user.FieldID, field.TypeInt),
},
}
for _, k := range nodes {
edge.Target.Nodes = append(edge.Target.Nodes, k)
}
_spec.Edges.Add = append(_spec.Edges.Add, edge)
}
_node = &FsEvent{config: feuo.config}
_spec.Assign = _node.assignValues
_spec.ScanValues = _node.scanValues
if err = sqlgraph.UpdateNode(ctx, feuo.driver, _spec); err != nil {
if _, ok := err.(*sqlgraph.NotFoundError); ok {
err = &NotFoundError{fsevent.Label}
} else if sqlgraph.IsConstraintError(err) {
err = &ConstraintError{msg: err.Error(), wrap: err}
}
return nil, err
}
feuo.mutation.done = true
return _node, nil
}

View File

@ -57,6 +57,18 @@ func (f FileFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, error)
return nil, fmt.Errorf("unexpected mutation type %T. expect *ent.FileMutation", m) return nil, fmt.Errorf("unexpected mutation type %T. expect *ent.FileMutation", m)
} }
// The FsEventFunc type is an adapter to allow the use of ordinary
// function as FsEvent mutator.
type FsEventFunc func(context.Context, *ent.FsEventMutation) (ent.Value, error)
// Mutate calls f(ctx, m).
func (f FsEventFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, error) {
if mv, ok := m.(*ent.FsEventMutation); ok {
return f(ctx, mv)
}
return nil, fmt.Errorf("unexpected mutation type %T. expect *ent.FsEventMutation", m)
}
// The GroupFunc type is an adapter to allow the use of ordinary // The GroupFunc type is an adapter to allow the use of ordinary
// function as Group mutator. // function as Group mutator.
type GroupFunc func(context.Context, *ent.GroupMutation) (ent.Value, error) type GroupFunc func(context.Context, *ent.GroupMutation) (ent.Value, error)

View File

@ -12,6 +12,7 @@ import (
"github.com/cloudreve/Cloudreve/v4/ent/directlink" "github.com/cloudreve/Cloudreve/v4/ent/directlink"
"github.com/cloudreve/Cloudreve/v4/ent/entity" "github.com/cloudreve/Cloudreve/v4/ent/entity"
"github.com/cloudreve/Cloudreve/v4/ent/file" "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/group"
"github.com/cloudreve/Cloudreve/v4/ent/metadata" "github.com/cloudreve/Cloudreve/v4/ent/metadata"
"github.com/cloudreve/Cloudreve/v4/ent/node" "github.com/cloudreve/Cloudreve/v4/ent/node"
@ -188,6 +189,33 @@ func (f TraverseFile) Traverse(ctx context.Context, q ent.Query) error {
return fmt.Errorf("unexpected query type %T. expect *ent.FileQuery", q) return fmt.Errorf("unexpected query type %T. expect *ent.FileQuery", q)
} }
// The FsEventFunc type is an adapter to allow the use of ordinary function as a Querier.
type FsEventFunc func(context.Context, *ent.FsEventQuery) (ent.Value, error)
// Query calls f(ctx, q).
func (f FsEventFunc) Query(ctx context.Context, q ent.Query) (ent.Value, error) {
if q, ok := q.(*ent.FsEventQuery); ok {
return f(ctx, q)
}
return nil, fmt.Errorf("unexpected query type %T. expect *ent.FsEventQuery", q)
}
// The TraverseFsEvent type is an adapter to allow the use of ordinary function as Traverser.
type TraverseFsEvent func(context.Context, *ent.FsEventQuery) error
// Intercept is a dummy implementation of Intercept that returns the next Querier in the pipeline.
func (f TraverseFsEvent) Intercept(next ent.Querier) ent.Querier {
return next
}
// Traverse calls f(ctx, q).
func (f TraverseFsEvent) Traverse(ctx context.Context, q ent.Query) error {
if q, ok := q.(*ent.FsEventQuery); ok {
return f(ctx, q)
}
return fmt.Errorf("unexpected query type %T. expect *ent.FsEventQuery", q)
}
// The GroupFunc type is an adapter to allow the use of ordinary function as a Querier. // The GroupFunc type is an adapter to allow the use of ordinary function as a Querier.
type GroupFunc func(context.Context, *ent.GroupQuery) (ent.Value, error) type GroupFunc func(context.Context, *ent.GroupQuery) (ent.Value, error)
@ -442,6 +470,8 @@ func NewQuery(q ent.Query) (Query, error) {
return &query[*ent.EntityQuery, predicate.Entity, entity.OrderOption]{typ: ent.TypeEntity, tq: q}, nil return &query[*ent.EntityQuery, predicate.Entity, entity.OrderOption]{typ: ent.TypeEntity, tq: q}, nil
case *ent.FileQuery: case *ent.FileQuery:
return &query[*ent.FileQuery, predicate.File, file.OrderOption]{typ: ent.TypeFile, tq: q}, nil return &query[*ent.FileQuery, predicate.File, file.OrderOption]{typ: ent.TypeFile, tq: q}, nil
case *ent.FsEventQuery:
return &query[*ent.FsEventQuery, predicate.FsEvent, fsevent.OrderOption]{typ: ent.TypeFsEvent, tq: q}, nil
case *ent.GroupQuery: case *ent.GroupQuery:
return &query[*ent.GroupQuery, predicate.Group, group.OrderOption]{typ: ent.TypeGroup, tq: q}, nil return &query[*ent.GroupQuery, predicate.Group, group.OrderOption]{typ: ent.TypeGroup, tq: q}, nil
case *ent.MetadataQuery: case *ent.MetadataQuery:

File diff suppressed because one or more lines are too long

View File

@ -160,6 +160,30 @@ var (
}, },
}, },
} }
// FsEventsColumns holds the columns for the "fs_events" table.
FsEventsColumns = []*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: "event", Type: field.TypeString, Size: 2147483647},
{Name: "subscriber", Type: field.TypeUUID},
{Name: "user_fsevent", Type: field.TypeInt, Nullable: true},
}
// FsEventsTable holds the schema information for the "fs_events" table.
FsEventsTable = &schema.Table{
Name: "fs_events",
Columns: FsEventsColumns,
PrimaryKey: []*schema.Column{FsEventsColumns[0]},
ForeignKeys: []*schema.ForeignKey{
{
Symbol: "fs_events_users_fsevents",
Columns: []*schema.Column{FsEventsColumns[6]},
RefColumns: []*schema.Column{UsersColumns[0]},
OnDelete: schema.SetNull,
},
},
}
// GroupsColumns holds the columns for the "groups" table. // GroupsColumns holds the columns for the "groups" table.
GroupsColumns = []*schema.Column{ GroupsColumns = []*schema.Column{
{Name: "id", Type: field.TypeInt, Increment: true}, {Name: "id", Type: field.TypeInt, Increment: true},
@ -444,6 +468,7 @@ var (
DirectLinksTable, DirectLinksTable,
EntitiesTable, EntitiesTable,
FilesTable, FilesTable,
FsEventsTable,
GroupsTable, GroupsTable,
MetadataTable, MetadataTable,
NodesTable, NodesTable,
@ -465,6 +490,7 @@ func init() {
FilesTable.ForeignKeys[0].RefTable = FilesTable FilesTable.ForeignKeys[0].RefTable = FilesTable
FilesTable.ForeignKeys[1].RefTable = StoragePoliciesTable FilesTable.ForeignKeys[1].RefTable = StoragePoliciesTable
FilesTable.ForeignKeys[2].RefTable = UsersTable FilesTable.ForeignKeys[2].RefTable = UsersTable
FsEventsTable.ForeignKeys[0].RefTable = UsersTable
GroupsTable.ForeignKeys[0].RefTable = StoragePoliciesTable GroupsTable.ForeignKeys[0].RefTable = StoragePoliciesTable
MetadataTable.ForeignKeys[0].RefTable = FilesTable MetadataTable.ForeignKeys[0].RefTable = FilesTable
PasskeysTable.ForeignKeys[0].RefTable = UsersTable PasskeysTable.ForeignKeys[0].RefTable = UsersTable

View File

@ -15,6 +15,7 @@ import (
"github.com/cloudreve/Cloudreve/v4/ent/directlink" "github.com/cloudreve/Cloudreve/v4/ent/directlink"
"github.com/cloudreve/Cloudreve/v4/ent/entity" "github.com/cloudreve/Cloudreve/v4/ent/entity"
"github.com/cloudreve/Cloudreve/v4/ent/file" "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/group"
"github.com/cloudreve/Cloudreve/v4/ent/metadata" "github.com/cloudreve/Cloudreve/v4/ent/metadata"
"github.com/cloudreve/Cloudreve/v4/ent/node" "github.com/cloudreve/Cloudreve/v4/ent/node"
@ -44,6 +45,7 @@ const (
TypeDirectLink = "DirectLink" TypeDirectLink = "DirectLink"
TypeEntity = "Entity" TypeEntity = "Entity"
TypeFile = "File" TypeFile = "File"
TypeFsEvent = "FsEvent"
TypeGroup = "Group" TypeGroup = "Group"
TypeMetadata = "Metadata" TypeMetadata = "Metadata"
TypeNode = "Node" TypeNode = "Node"
@ -4601,6 +4603,713 @@ func (m *FileMutation) ResetEdge(name string) error {
return fmt.Errorf("unknown File edge %s", name) return fmt.Errorf("unknown File edge %s", name)
} }
// FsEventMutation represents an operation that mutates the FsEvent nodes in the graph.
type FsEventMutation struct {
config
op Op
typ string
id *int
created_at *time.Time
updated_at *time.Time
deleted_at *time.Time
event *string
subscriber *uuid.UUID
clearedFields map[string]struct{}
user *int
cleareduser bool
done bool
oldValue func(context.Context) (*FsEvent, error)
predicates []predicate.FsEvent
}
var _ ent.Mutation = (*FsEventMutation)(nil)
// fseventOption allows management of the mutation configuration using functional options.
type fseventOption func(*FsEventMutation)
// newFsEventMutation creates new mutation for the FsEvent entity.
func newFsEventMutation(c config, op Op, opts ...fseventOption) *FsEventMutation {
m := &FsEventMutation{
config: c,
op: op,
typ: TypeFsEvent,
clearedFields: make(map[string]struct{}),
}
for _, opt := range opts {
opt(m)
}
return m
}
// withFsEventID sets the ID field of the mutation.
func withFsEventID(id int) fseventOption {
return func(m *FsEventMutation) {
var (
err error
once sync.Once
value *FsEvent
)
m.oldValue = func(ctx context.Context) (*FsEvent, error) {
once.Do(func() {
if m.done {
err = errors.New("querying old values post mutation is not allowed")
} else {
value, err = m.Client().FsEvent.Get(ctx, id)
}
})
return value, err
}
m.id = &id
}
}
// withFsEvent sets the old FsEvent of the mutation.
func withFsEvent(node *FsEvent) fseventOption {
return func(m *FsEventMutation) {
m.oldValue = func(context.Context) (*FsEvent, 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 FsEventMutation) 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 FsEventMutation) 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 *FsEventMutation) 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 *FsEventMutation) 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().FsEvent.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 *FsEventMutation) SetCreatedAt(t time.Time) {
m.created_at = &t
}
// CreatedAt returns the value of the "created_at" field in the mutation.
func (m *FsEventMutation) 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 FsEvent entity.
// If the FsEvent 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 *FsEventMutation) 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 *FsEventMutation) ResetCreatedAt() {
m.created_at = nil
}
// SetUpdatedAt sets the "updated_at" field.
func (m *FsEventMutation) SetUpdatedAt(t time.Time) {
m.updated_at = &t
}
// UpdatedAt returns the value of the "updated_at" field in the mutation.
func (m *FsEventMutation) 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 FsEvent entity.
// If the FsEvent 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 *FsEventMutation) 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 *FsEventMutation) ResetUpdatedAt() {
m.updated_at = nil
}
// SetDeletedAt sets the "deleted_at" field.
func (m *FsEventMutation) SetDeletedAt(t time.Time) {
m.deleted_at = &t
}
// DeletedAt returns the value of the "deleted_at" field in the mutation.
func (m *FsEventMutation) 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 FsEvent entity.
// If the FsEvent 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 *FsEventMutation) 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 *FsEventMutation) ClearDeletedAt() {
m.deleted_at = nil
m.clearedFields[fsevent.FieldDeletedAt] = struct{}{}
}
// DeletedAtCleared returns if the "deleted_at" field was cleared in this mutation.
func (m *FsEventMutation) DeletedAtCleared() bool {
_, ok := m.clearedFields[fsevent.FieldDeletedAt]
return ok
}
// ResetDeletedAt resets all changes to the "deleted_at" field.
func (m *FsEventMutation) ResetDeletedAt() {
m.deleted_at = nil
delete(m.clearedFields, fsevent.FieldDeletedAt)
}
// SetEvent sets the "event" field.
func (m *FsEventMutation) SetEvent(s string) {
m.event = &s
}
// Event returns the value of the "event" field in the mutation.
func (m *FsEventMutation) Event() (r string, exists bool) {
v := m.event
if v == nil {
return
}
return *v, true
}
// OldEvent returns the old "event" field's value of the FsEvent entity.
// If the FsEvent 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 *FsEventMutation) OldEvent(ctx context.Context) (v string, err error) {
if !m.op.Is(OpUpdateOne) {
return v, errors.New("OldEvent is only allowed on UpdateOne operations")
}
if m.id == nil || m.oldValue == nil {
return v, errors.New("OldEvent requires an ID field in the mutation")
}
oldValue, err := m.oldValue(ctx)
if err != nil {
return v, fmt.Errorf("querying old value for OldEvent: %w", err)
}
return oldValue.Event, nil
}
// ResetEvent resets all changes to the "event" field.
func (m *FsEventMutation) ResetEvent() {
m.event = nil
}
// SetSubscriber sets the "subscriber" field.
func (m *FsEventMutation) SetSubscriber(u uuid.UUID) {
m.subscriber = &u
}
// Subscriber returns the value of the "subscriber" field in the mutation.
func (m *FsEventMutation) Subscriber() (r uuid.UUID, exists bool) {
v := m.subscriber
if v == nil {
return
}
return *v, true
}
// OldSubscriber returns the old "subscriber" field's value of the FsEvent entity.
// If the FsEvent 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 *FsEventMutation) OldSubscriber(ctx context.Context) (v uuid.UUID, err error) {
if !m.op.Is(OpUpdateOne) {
return v, errors.New("OldSubscriber is only allowed on UpdateOne operations")
}
if m.id == nil || m.oldValue == nil {
return v, errors.New("OldSubscriber requires an ID field in the mutation")
}
oldValue, err := m.oldValue(ctx)
if err != nil {
return v, fmt.Errorf("querying old value for OldSubscriber: %w", err)
}
return oldValue.Subscriber, nil
}
// ResetSubscriber resets all changes to the "subscriber" field.
func (m *FsEventMutation) ResetSubscriber() {
m.subscriber = nil
}
// SetUserFsevent sets the "user_fsevent" field.
func (m *FsEventMutation) SetUserFsevent(i int) {
m.user = &i
}
// UserFsevent returns the value of the "user_fsevent" field in the mutation.
func (m *FsEventMutation) UserFsevent() (r int, exists bool) {
v := m.user
if v == nil {
return
}
return *v, true
}
// OldUserFsevent returns the old "user_fsevent" field's value of the FsEvent entity.
// If the FsEvent 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 *FsEventMutation) OldUserFsevent(ctx context.Context) (v int, err error) {
if !m.op.Is(OpUpdateOne) {
return v, errors.New("OldUserFsevent is only allowed on UpdateOne operations")
}
if m.id == nil || m.oldValue == nil {
return v, errors.New("OldUserFsevent requires an ID field in the mutation")
}
oldValue, err := m.oldValue(ctx)
if err != nil {
return v, fmt.Errorf("querying old value for OldUserFsevent: %w", err)
}
return oldValue.UserFsevent, nil
}
// ClearUserFsevent clears the value of the "user_fsevent" field.
func (m *FsEventMutation) ClearUserFsevent() {
m.user = nil
m.clearedFields[fsevent.FieldUserFsevent] = struct{}{}
}
// UserFseventCleared returns if the "user_fsevent" field was cleared in this mutation.
func (m *FsEventMutation) UserFseventCleared() bool {
_, ok := m.clearedFields[fsevent.FieldUserFsevent]
return ok
}
// ResetUserFsevent resets all changes to the "user_fsevent" field.
func (m *FsEventMutation) ResetUserFsevent() {
m.user = nil
delete(m.clearedFields, fsevent.FieldUserFsevent)
}
// SetUserID sets the "user" edge to the User entity by id.
func (m *FsEventMutation) SetUserID(id int) {
m.user = &id
}
// ClearUser clears the "user" edge to the User entity.
func (m *FsEventMutation) ClearUser() {
m.cleareduser = true
m.clearedFields[fsevent.FieldUserFsevent] = struct{}{}
}
// UserCleared reports if the "user" edge to the User entity was cleared.
func (m *FsEventMutation) UserCleared() bool {
return m.UserFseventCleared() || m.cleareduser
}
// UserID returns the "user" edge ID in the mutation.
func (m *FsEventMutation) UserID() (id int, exists bool) {
if m.user != nil {
return *m.user, true
}
return
}
// UserIDs returns the "user" edge IDs in the mutation.
// Note that IDs always returns len(IDs) <= 1 for unique edges, and you should use
// UserID instead. It exists only for internal usage by the builders.
func (m *FsEventMutation) UserIDs() (ids []int) {
if id := m.user; id != nil {
ids = append(ids, *id)
}
return
}
// ResetUser resets all changes to the "user" edge.
func (m *FsEventMutation) ResetUser() {
m.user = nil
m.cleareduser = false
}
// Where appends a list predicates to the FsEventMutation builder.
func (m *FsEventMutation) Where(ps ...predicate.FsEvent) {
m.predicates = append(m.predicates, ps...)
}
// WhereP appends storage-level predicates to the FsEventMutation builder. Using this method,
// users can use type-assertion to append predicates that do not depend on any generated package.
func (m *FsEventMutation) WhereP(ps ...func(*sql.Selector)) {
p := make([]predicate.FsEvent, len(ps))
for i := range ps {
p[i] = ps[i]
}
m.Where(p...)
}
// Op returns the operation name.
func (m *FsEventMutation) Op() Op {
return m.op
}
// SetOp allows setting the mutation operation.
func (m *FsEventMutation) SetOp(op Op) {
m.op = op
}
// Type returns the node type of this mutation (FsEvent).
func (m *FsEventMutation) 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 *FsEventMutation) Fields() []string {
fields := make([]string, 0, 6)
if m.created_at != nil {
fields = append(fields, fsevent.FieldCreatedAt)
}
if m.updated_at != nil {
fields = append(fields, fsevent.FieldUpdatedAt)
}
if m.deleted_at != nil {
fields = append(fields, fsevent.FieldDeletedAt)
}
if m.event != nil {
fields = append(fields, fsevent.FieldEvent)
}
if m.subscriber != nil {
fields = append(fields, fsevent.FieldSubscriber)
}
if m.user != nil {
fields = append(fields, fsevent.FieldUserFsevent)
}
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 *FsEventMutation) Field(name string) (ent.Value, bool) {
switch name {
case fsevent.FieldCreatedAt:
return m.CreatedAt()
case fsevent.FieldUpdatedAt:
return m.UpdatedAt()
case fsevent.FieldDeletedAt:
return m.DeletedAt()
case fsevent.FieldEvent:
return m.Event()
case fsevent.FieldSubscriber:
return m.Subscriber()
case fsevent.FieldUserFsevent:
return m.UserFsevent()
}
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 *FsEventMutation) OldField(ctx context.Context, name string) (ent.Value, error) {
switch name {
case fsevent.FieldCreatedAt:
return m.OldCreatedAt(ctx)
case fsevent.FieldUpdatedAt:
return m.OldUpdatedAt(ctx)
case fsevent.FieldDeletedAt:
return m.OldDeletedAt(ctx)
case fsevent.FieldEvent:
return m.OldEvent(ctx)
case fsevent.FieldSubscriber:
return m.OldSubscriber(ctx)
case fsevent.FieldUserFsevent:
return m.OldUserFsevent(ctx)
}
return nil, fmt.Errorf("unknown FsEvent 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 *FsEventMutation) SetField(name string, value ent.Value) error {
switch name {
case fsevent.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 fsevent.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 fsevent.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 fsevent.FieldEvent:
v, ok := value.(string)
if !ok {
return fmt.Errorf("unexpected type %T for field %s", value, name)
}
m.SetEvent(v)
return nil
case fsevent.FieldSubscriber:
v, ok := value.(uuid.UUID)
if !ok {
return fmt.Errorf("unexpected type %T for field %s", value, name)
}
m.SetSubscriber(v)
return nil
case fsevent.FieldUserFsevent:
v, ok := value.(int)
if !ok {
return fmt.Errorf("unexpected type %T for field %s", value, name)
}
m.SetUserFsevent(v)
return nil
}
return fmt.Errorf("unknown FsEvent field %s", name)
}
// AddedFields returns all numeric fields that were incremented/decremented during
// this mutation.
func (m *FsEventMutation) AddedFields() []string {
var fields []string
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 *FsEventMutation) AddedField(name string) (ent.Value, bool) {
switch name {
}
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 *FsEventMutation) AddField(name string, value ent.Value) error {
switch name {
}
return fmt.Errorf("unknown FsEvent numeric field %s", name)
}
// ClearedFields returns all nullable fields that were cleared during this
// mutation.
func (m *FsEventMutation) ClearedFields() []string {
var fields []string
if m.FieldCleared(fsevent.FieldDeletedAt) {
fields = append(fields, fsevent.FieldDeletedAt)
}
if m.FieldCleared(fsevent.FieldUserFsevent) {
fields = append(fields, fsevent.FieldUserFsevent)
}
return fields
}
// FieldCleared returns a boolean indicating if a field with the given name was
// cleared in this mutation.
func (m *FsEventMutation) 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 *FsEventMutation) ClearField(name string) error {
switch name {
case fsevent.FieldDeletedAt:
m.ClearDeletedAt()
return nil
case fsevent.FieldUserFsevent:
m.ClearUserFsevent()
return nil
}
return fmt.Errorf("unknown FsEvent 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 *FsEventMutation) ResetField(name string) error {
switch name {
case fsevent.FieldCreatedAt:
m.ResetCreatedAt()
return nil
case fsevent.FieldUpdatedAt:
m.ResetUpdatedAt()
return nil
case fsevent.FieldDeletedAt:
m.ResetDeletedAt()
return nil
case fsevent.FieldEvent:
m.ResetEvent()
return nil
case fsevent.FieldSubscriber:
m.ResetSubscriber()
return nil
case fsevent.FieldUserFsevent:
m.ResetUserFsevent()
return nil
}
return fmt.Errorf("unknown FsEvent field %s", name)
}
// AddedEdges returns all edge names that were set/added in this mutation.
func (m *FsEventMutation) AddedEdges() []string {
edges := make([]string, 0, 1)
if m.user != nil {
edges = append(edges, fsevent.EdgeUser)
}
return edges
}
// AddedIDs returns all IDs (to other nodes) that were added for the given edge
// name in this mutation.
func (m *FsEventMutation) AddedIDs(name string) []ent.Value {
switch name {
case fsevent.EdgeUser:
if id := m.user; id != nil {
return []ent.Value{*id}
}
}
return nil
}
// RemovedEdges returns all edge names that were removed in this mutation.
func (m *FsEventMutation) RemovedEdges() []string {
edges := make([]string, 0, 1)
return edges
}
// RemovedIDs returns all IDs (to other nodes) that were removed for the edge with
// the given name in this mutation.
func (m *FsEventMutation) RemovedIDs(name string) []ent.Value {
return nil
}
// ClearedEdges returns all edge names that were cleared in this mutation.
func (m *FsEventMutation) ClearedEdges() []string {
edges := make([]string, 0, 1)
if m.cleareduser {
edges = append(edges, fsevent.EdgeUser)
}
return edges
}
// EdgeCleared returns a boolean which indicates if the edge with the given name
// was cleared in this mutation.
func (m *FsEventMutation) EdgeCleared(name string) bool {
switch name {
case fsevent.EdgeUser:
return m.cleareduser
}
return false
}
// ClearEdge clears the value of the edge with the given name. It returns an error
// if that edge is not defined in the schema.
func (m *FsEventMutation) ClearEdge(name string) error {
switch name {
case fsevent.EdgeUser:
m.ClearUser()
return nil
}
return fmt.Errorf("unknown FsEvent 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 *FsEventMutation) ResetEdge(name string) error {
switch name {
case fsevent.EdgeUser:
m.ResetUser()
return nil
}
return fmt.Errorf("unknown FsEvent edge %s", name)
}
// GroupMutation represents an operation that mutates the Group nodes in the graph. // GroupMutation represents an operation that mutates the Group nodes in the graph.
type GroupMutation struct { type GroupMutation struct {
config config
@ -12532,6 +13241,9 @@ type UserMutation struct {
tasks map[int]struct{} tasks map[int]struct{}
removedtasks map[int]struct{} removedtasks map[int]struct{}
clearedtasks bool clearedtasks bool
fsevents map[int]struct{}
removedfsevents map[int]struct{}
clearedfsevents bool
entities map[int]struct{} entities map[int]struct{}
removedentities map[int]struct{} removedentities map[int]struct{}
clearedentities bool clearedentities bool
@ -13465,6 +14177,60 @@ func (m *UserMutation) ResetTasks() {
m.removedtasks = nil m.removedtasks = nil
} }
// AddFseventIDs adds the "fsevents" edge to the FsEvent entity by ids.
func (m *UserMutation) AddFseventIDs(ids ...int) {
if m.fsevents == nil {
m.fsevents = make(map[int]struct{})
}
for i := range ids {
m.fsevents[ids[i]] = struct{}{}
}
}
// ClearFsevents clears the "fsevents" edge to the FsEvent entity.
func (m *UserMutation) ClearFsevents() {
m.clearedfsevents = true
}
// FseventsCleared reports if the "fsevents" edge to the FsEvent entity was cleared.
func (m *UserMutation) FseventsCleared() bool {
return m.clearedfsevents
}
// RemoveFseventIDs removes the "fsevents" edge to the FsEvent entity by IDs.
func (m *UserMutation) RemoveFseventIDs(ids ...int) {
if m.removedfsevents == nil {
m.removedfsevents = make(map[int]struct{})
}
for i := range ids {
delete(m.fsevents, ids[i])
m.removedfsevents[ids[i]] = struct{}{}
}
}
// RemovedFsevents returns the removed IDs of the "fsevents" edge to the FsEvent entity.
func (m *UserMutation) RemovedFseventsIDs() (ids []int) {
for id := range m.removedfsevents {
ids = append(ids, id)
}
return
}
// FseventsIDs returns the "fsevents" edge IDs in the mutation.
func (m *UserMutation) FseventsIDs() (ids []int) {
for id := range m.fsevents {
ids = append(ids, id)
}
return
}
// ResetFsevents resets all changes to the "fsevents" edge.
func (m *UserMutation) ResetFsevents() {
m.fsevents = nil
m.clearedfsevents = false
m.removedfsevents = nil
}
// AddEntityIDs adds the "entities" edge to the Entity entity by ids. // AddEntityIDs adds the "entities" edge to the Entity entity by ids.
func (m *UserMutation) AddEntityIDs(ids ...int) { func (m *UserMutation) AddEntityIDs(ids ...int) {
if m.entities == nil { if m.entities == nil {
@ -13887,7 +14653,7 @@ func (m *UserMutation) ResetField(name string) error {
// AddedEdges returns all edge names that were set/added in this mutation. // AddedEdges returns all edge names that were set/added in this mutation.
func (m *UserMutation) AddedEdges() []string { func (m *UserMutation) AddedEdges() []string {
edges := make([]string, 0, 7) edges := make([]string, 0, 8)
if m.group != nil { if m.group != nil {
edges = append(edges, user.EdgeGroup) edges = append(edges, user.EdgeGroup)
} }
@ -13906,6 +14672,9 @@ func (m *UserMutation) AddedEdges() []string {
if m.tasks != nil { if m.tasks != nil {
edges = append(edges, user.EdgeTasks) edges = append(edges, user.EdgeTasks)
} }
if m.fsevents != nil {
edges = append(edges, user.EdgeFsevents)
}
if m.entities != nil { if m.entities != nil {
edges = append(edges, user.EdgeEntities) edges = append(edges, user.EdgeEntities)
} }
@ -13950,6 +14719,12 @@ func (m *UserMutation) AddedIDs(name string) []ent.Value {
ids = append(ids, id) ids = append(ids, id)
} }
return ids return ids
case user.EdgeFsevents:
ids := make([]ent.Value, 0, len(m.fsevents))
for id := range m.fsevents {
ids = append(ids, id)
}
return ids
case user.EdgeEntities: case user.EdgeEntities:
ids := make([]ent.Value, 0, len(m.entities)) ids := make([]ent.Value, 0, len(m.entities))
for id := range m.entities { for id := range m.entities {
@ -13962,7 +14737,7 @@ func (m *UserMutation) AddedIDs(name string) []ent.Value {
// RemovedEdges returns all edge names that were removed in this mutation. // RemovedEdges returns all edge names that were removed in this mutation.
func (m *UserMutation) RemovedEdges() []string { func (m *UserMutation) RemovedEdges() []string {
edges := make([]string, 0, 7) edges := make([]string, 0, 8)
if m.removedfiles != nil { if m.removedfiles != nil {
edges = append(edges, user.EdgeFiles) edges = append(edges, user.EdgeFiles)
} }
@ -13978,6 +14753,9 @@ func (m *UserMutation) RemovedEdges() []string {
if m.removedtasks != nil { if m.removedtasks != nil {
edges = append(edges, user.EdgeTasks) edges = append(edges, user.EdgeTasks)
} }
if m.removedfsevents != nil {
edges = append(edges, user.EdgeFsevents)
}
if m.removedentities != nil { if m.removedentities != nil {
edges = append(edges, user.EdgeEntities) edges = append(edges, user.EdgeEntities)
} }
@ -14018,6 +14796,12 @@ func (m *UserMutation) RemovedIDs(name string) []ent.Value {
ids = append(ids, id) ids = append(ids, id)
} }
return ids return ids
case user.EdgeFsevents:
ids := make([]ent.Value, 0, len(m.removedfsevents))
for id := range m.removedfsevents {
ids = append(ids, id)
}
return ids
case user.EdgeEntities: case user.EdgeEntities:
ids := make([]ent.Value, 0, len(m.removedentities)) ids := make([]ent.Value, 0, len(m.removedentities))
for id := range m.removedentities { for id := range m.removedentities {
@ -14030,7 +14814,7 @@ func (m *UserMutation) RemovedIDs(name string) []ent.Value {
// ClearedEdges returns all edge names that were cleared in this mutation. // ClearedEdges returns all edge names that were cleared in this mutation.
func (m *UserMutation) ClearedEdges() []string { func (m *UserMutation) ClearedEdges() []string {
edges := make([]string, 0, 7) edges := make([]string, 0, 8)
if m.clearedgroup { if m.clearedgroup {
edges = append(edges, user.EdgeGroup) edges = append(edges, user.EdgeGroup)
} }
@ -14049,6 +14833,9 @@ func (m *UserMutation) ClearedEdges() []string {
if m.clearedtasks { if m.clearedtasks {
edges = append(edges, user.EdgeTasks) edges = append(edges, user.EdgeTasks)
} }
if m.clearedfsevents {
edges = append(edges, user.EdgeFsevents)
}
if m.clearedentities { if m.clearedentities {
edges = append(edges, user.EdgeEntities) edges = append(edges, user.EdgeEntities)
} }
@ -14071,6 +14858,8 @@ func (m *UserMutation) EdgeCleared(name string) bool {
return m.clearedpasskey return m.clearedpasskey
case user.EdgeTasks: case user.EdgeTasks:
return m.clearedtasks return m.clearedtasks
case user.EdgeFsevents:
return m.clearedfsevents
case user.EdgeEntities: case user.EdgeEntities:
return m.clearedentities return m.clearedentities
} }
@ -14110,6 +14899,9 @@ func (m *UserMutation) ResetEdge(name string) error {
case user.EdgeTasks: case user.EdgeTasks:
m.ResetTasks() m.ResetTasks()
return nil return nil
case user.EdgeFsevents:
m.ResetFsevents()
return nil
case user.EdgeEntities: case user.EdgeEntities:
m.ResetEntities() m.ResetEntities()
return nil return nil

View File

@ -28,6 +28,12 @@ func (m *FileMutation) SetRawID(t int) {
// SetUpdatedAt sets the "updated_at" field. // SetUpdatedAt sets the "updated_at" field.
func (m *FsEventMutation) SetRawID(t int) {
m.id = &t
}
// SetUpdatedAt sets the "updated_at" field.
func (m *GroupMutation) SetRawID(t int) { func (m *GroupMutation) SetRawID(t int) {
m.id = &t m.id = &t
} }

View File

@ -18,6 +18,9 @@ type Entity func(*sql.Selector)
// File is the predicate function for file builders. // File is the predicate function for file builders.
type File func(*sql.Selector) type File func(*sql.Selector)
// FsEvent is the predicate function for fsevent builders.
type FsEvent func(*sql.Selector)
// Group is the predicate function for group builders. // Group is the predicate function for group builders.
type Group func(*sql.Selector) type Group func(*sql.Selector)

View File

@ -9,6 +9,7 @@ import (
"github.com/cloudreve/Cloudreve/v4/ent/directlink" "github.com/cloudreve/Cloudreve/v4/ent/directlink"
"github.com/cloudreve/Cloudreve/v4/ent/entity" "github.com/cloudreve/Cloudreve/v4/ent/entity"
"github.com/cloudreve/Cloudreve/v4/ent/file" "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/group"
"github.com/cloudreve/Cloudreve/v4/ent/metadata" "github.com/cloudreve/Cloudreve/v4/ent/metadata"
"github.com/cloudreve/Cloudreve/v4/ent/node" "github.com/cloudreve/Cloudreve/v4/ent/node"
@ -107,6 +108,25 @@ func init() {
fileDescIsSymbolic := fileFields[8].Descriptor() fileDescIsSymbolic := fileFields[8].Descriptor()
// file.DefaultIsSymbolic holds the default value on creation for the is_symbolic field. // file.DefaultIsSymbolic holds the default value on creation for the is_symbolic field.
file.DefaultIsSymbolic = fileDescIsSymbolic.Default.(bool) file.DefaultIsSymbolic = fileDescIsSymbolic.Default.(bool)
fseventMixin := schema.FsEvent{}.Mixin()
fseventMixinHooks0 := fseventMixin[0].Hooks()
fsevent.Hooks[0] = fseventMixinHooks0[0]
fseventMixinInters0 := fseventMixin[0].Interceptors()
fsevent.Interceptors[0] = fseventMixinInters0[0]
fseventMixinFields0 := fseventMixin[0].Fields()
_ = fseventMixinFields0
fseventFields := schema.FsEvent{}.Fields()
_ = fseventFields
// fseventDescCreatedAt is the schema descriptor for created_at field.
fseventDescCreatedAt := fseventMixinFields0[0].Descriptor()
// fsevent.DefaultCreatedAt holds the default value on creation for the created_at field.
fsevent.DefaultCreatedAt = fseventDescCreatedAt.Default.(func() time.Time)
// fseventDescUpdatedAt is the schema descriptor for updated_at field.
fseventDescUpdatedAt := fseventMixinFields0[1].Descriptor()
// fsevent.DefaultUpdatedAt holds the default value on creation for the updated_at field.
fsevent.DefaultUpdatedAt = fseventDescUpdatedAt.Default.(func() time.Time)
// fsevent.UpdateDefaultUpdatedAt holds the default value on update for the updated_at field.
fsevent.UpdateDefaultUpdatedAt = fseventDescUpdatedAt.UpdateDefault.(func() time.Time)
groupMixin := schema.Group{}.Mixin() groupMixin := schema.Group{}.Mixin()
groupMixinHooks0 := groupMixin[0].Hooks() groupMixinHooks0 := groupMixin[0].Hooks()
group.Hooks[0] = groupMixinHooks0[0] group.Hooks[0] = groupMixinHooks0[0]

38
ent/schema/fsevent.go Normal file
View File

@ -0,0 +1,38 @@
package schema
import (
"entgo.io/ent"
"entgo.io/ent/schema/edge"
"entgo.io/ent/schema/field"
"github.com/gofrs/uuid"
)
// FsEvent holds the schema definition for the FsEvent entity.
type FsEvent struct {
ent.Schema
}
// Fields of the FsEvent.
func (FsEvent) Fields() []ent.Field {
return []ent.Field{
field.Text("event"),
field.UUID("subscriber", uuid.Must(uuid.NewV4())),
field.Int("user_fsevent").Optional(),
}
}
// Edges of the Task.
func (FsEvent) Edges() []ent.Edge {
return []ent.Edge{
edge.From("user", User.Type).
Ref("fsevents").
Field("user_fsevent").
Unique(),
}
}
func (FsEvent) Mixin() []ent.Mixin {
return []ent.Mixin{
CommonMixin{},
}
}

View File

@ -51,6 +51,7 @@ func (User) Edges() []ent.Edge {
edge.To("shares", Share.Type), edge.To("shares", Share.Type),
edge.To("passkey", Passkey.Type), edge.To("passkey", Passkey.Type),
edge.To("tasks", Task.Type), edge.To("tasks", Task.Type),
edge.To("fsevents", FsEvent.Type),
edge.To("entities", Entity.Type), edge.To("entities", Entity.Type),
} }
} }

View File

@ -22,6 +22,8 @@ type Tx struct {
Entity *EntityClient Entity *EntityClient
// File is the client for interacting with the File builders. // File is the client for interacting with the File builders.
File *FileClient File *FileClient
// FsEvent is the client for interacting with the FsEvent builders.
FsEvent *FsEventClient
// Group is the client for interacting with the Group builders. // Group is the client for interacting with the Group builders.
Group *GroupClient Group *GroupClient
// Metadata is the client for interacting with the Metadata builders. // Metadata is the client for interacting with the Metadata builders.
@ -175,6 +177,7 @@ func (tx *Tx) init() {
tx.DirectLink = NewDirectLinkClient(tx.config) tx.DirectLink = NewDirectLinkClient(tx.config)
tx.Entity = NewEntityClient(tx.config) tx.Entity = NewEntityClient(tx.config)
tx.File = NewFileClient(tx.config) tx.File = NewFileClient(tx.config)
tx.FsEvent = NewFsEventClient(tx.config)
tx.Group = NewGroupClient(tx.config) tx.Group = NewGroupClient(tx.config)
tx.Metadata = NewMetadataClient(tx.config) tx.Metadata = NewMetadataClient(tx.config)
tx.Node = NewNodeClient(tx.config) tx.Node = NewNodeClient(tx.config)

View File

@ -64,11 +64,13 @@ type UserEdges struct {
Passkey []*Passkey `json:"passkey,omitempty"` Passkey []*Passkey `json:"passkey,omitempty"`
// Tasks holds the value of the tasks edge. // Tasks holds the value of the tasks edge.
Tasks []*Task `json:"tasks,omitempty"` Tasks []*Task `json:"tasks,omitempty"`
// Fsevents holds the value of the fsevents edge.
Fsevents []*FsEvent `json:"fsevents,omitempty"`
// Entities holds the value of the entities edge. // Entities holds the value of the entities edge.
Entities []*Entity `json:"entities,omitempty"` Entities []*Entity `json:"entities,omitempty"`
// loadedTypes holds the information for reporting if a // loadedTypes holds the information for reporting if a
// type was loaded (or requested) in eager-loading or not. // type was loaded (or requested) in eager-loading or not.
loadedTypes [7]bool loadedTypes [8]bool
} }
// GroupOrErr returns the Group value or an error if the edge // GroupOrErr returns the Group value or an error if the edge
@ -129,10 +131,19 @@ func (e UserEdges) TasksOrErr() ([]*Task, error) {
return nil, &NotLoadedError{edge: "tasks"} return nil, &NotLoadedError{edge: "tasks"}
} }
// FseventsOrErr returns the Fsevents value or an error if the edge
// was not loaded in eager-loading.
func (e UserEdges) FseventsOrErr() ([]*FsEvent, error) {
if e.loadedTypes[6] {
return e.Fsevents, nil
}
return nil, &NotLoadedError{edge: "fsevents"}
}
// EntitiesOrErr returns the Entities value or an error if the edge // EntitiesOrErr returns the Entities value or an error if the edge
// was not loaded in eager-loading. // was not loaded in eager-loading.
func (e UserEdges) EntitiesOrErr() ([]*Entity, error) { func (e UserEdges) EntitiesOrErr() ([]*Entity, error) {
if e.loadedTypes[6] { if e.loadedTypes[7] {
return e.Entities, nil return e.Entities, nil
} }
return nil, &NotLoadedError{edge: "entities"} return nil, &NotLoadedError{edge: "entities"}
@ -290,6 +301,11 @@ func (u *User) QueryTasks() *TaskQuery {
return NewUserClient(u.config).QueryTasks(u) return NewUserClient(u.config).QueryTasks(u)
} }
// QueryFsevents queries the "fsevents" edge of the User entity.
func (u *User) QueryFsevents() *FsEventQuery {
return NewUserClient(u.config).QueryFsevents(u)
}
// QueryEntities queries the "entities" edge of the User entity. // QueryEntities queries the "entities" edge of the User entity.
func (u *User) QueryEntities() *EntityQuery { func (u *User) QueryEntities() *EntityQuery {
return NewUserClient(u.config).QueryEntities(u) return NewUserClient(u.config).QueryEntities(u)
@ -393,10 +409,16 @@ func (e *User) SetTasks(v []*Task) {
e.Edges.loadedTypes[5] = true e.Edges.loadedTypes[5] = true
} }
// SetFsevents manually set the edge as loaded state.
func (e *User) SetFsevents(v []*FsEvent) {
e.Edges.Fsevents = v
e.Edges.loadedTypes[6] = true
}
// SetEntities manually set the edge as loaded state. // SetEntities manually set the edge as loaded state.
func (e *User) SetEntities(v []*Entity) { func (e *User) SetEntities(v []*Entity) {
e.Edges.Entities = v e.Edges.Entities = v
e.Edges.loadedTypes[6] = true e.Edges.loadedTypes[7] = true
} }
// Users is a parsable slice of User. // Users is a parsable slice of User.

View File

@ -53,6 +53,8 @@ const (
EdgePasskey = "passkey" EdgePasskey = "passkey"
// EdgeTasks holds the string denoting the tasks edge name in mutations. // EdgeTasks holds the string denoting the tasks edge name in mutations.
EdgeTasks = "tasks" EdgeTasks = "tasks"
// EdgeFsevents holds the string denoting the fsevents edge name in mutations.
EdgeFsevents = "fsevents"
// EdgeEntities holds the string denoting the entities edge name in mutations. // EdgeEntities holds the string denoting the entities edge name in mutations.
EdgeEntities = "entities" EdgeEntities = "entities"
// Table holds the table name of the user in the database. // Table holds the table name of the user in the database.
@ -99,6 +101,13 @@ const (
TasksInverseTable = "tasks" TasksInverseTable = "tasks"
// TasksColumn is the table column denoting the tasks relation/edge. // TasksColumn is the table column denoting the tasks relation/edge.
TasksColumn = "user_tasks" TasksColumn = "user_tasks"
// FseventsTable is the table that holds the fsevents relation/edge.
FseventsTable = "fs_events"
// FseventsInverseTable is the table name for the FsEvent entity.
// It exists in this package in order to avoid circular dependency with the "fsevent" package.
FseventsInverseTable = "fs_events"
// FseventsColumn is the table column denoting the fsevents relation/edge.
FseventsColumn = "user_fsevent"
// EntitiesTable is the table that holds the entities relation/edge. // EntitiesTable is the table that holds the entities relation/edge.
EntitiesTable = "entities" EntitiesTable = "entities"
// EntitiesInverseTable is the table name for the Entity entity. // EntitiesInverseTable is the table name for the Entity entity.
@ -327,6 +336,20 @@ func ByTasks(term sql.OrderTerm, terms ...sql.OrderTerm) OrderOption {
} }
} }
// ByFseventsCount orders the results by fsevents count.
func ByFseventsCount(opts ...sql.OrderTermOption) OrderOption {
return func(s *sql.Selector) {
sqlgraph.OrderByNeighborsCount(s, newFseventsStep(), opts...)
}
}
// ByFsevents orders the results by fsevents terms.
func ByFsevents(term sql.OrderTerm, terms ...sql.OrderTerm) OrderOption {
return func(s *sql.Selector) {
sqlgraph.OrderByNeighborTerms(s, newFseventsStep(), append([]sql.OrderTerm{term}, terms...)...)
}
}
// ByEntitiesCount orders the results by entities count. // ByEntitiesCount orders the results by entities count.
func ByEntitiesCount(opts ...sql.OrderTermOption) OrderOption { func ByEntitiesCount(opts ...sql.OrderTermOption) OrderOption {
return func(s *sql.Selector) { return func(s *sql.Selector) {
@ -382,6 +405,13 @@ func newTasksStep() *sqlgraph.Step {
sqlgraph.Edge(sqlgraph.O2M, false, TasksTable, TasksColumn), sqlgraph.Edge(sqlgraph.O2M, false, TasksTable, TasksColumn),
) )
} }
func newFseventsStep() *sqlgraph.Step {
return sqlgraph.NewStep(
sqlgraph.From(Table, FieldID),
sqlgraph.To(FseventsInverseTable, FieldID),
sqlgraph.Edge(sqlgraph.O2M, false, FseventsTable, FseventsColumn),
)
}
func newEntitiesStep() *sqlgraph.Step { func newEntitiesStep() *sqlgraph.Step {
return sqlgraph.NewStep( return sqlgraph.NewStep(
sqlgraph.From(Table, FieldID), sqlgraph.From(Table, FieldID),

View File

@ -818,6 +818,29 @@ func HasTasksWith(preds ...predicate.Task) predicate.User {
}) })
} }
// HasFsevents applies the HasEdge predicate on the "fsevents" edge.
func HasFsevents() predicate.User {
return predicate.User(func(s *sql.Selector) {
step := sqlgraph.NewStep(
sqlgraph.From(Table, FieldID),
sqlgraph.Edge(sqlgraph.O2M, false, FseventsTable, FseventsColumn),
)
sqlgraph.HasNeighbors(s, step)
})
}
// HasFseventsWith applies the HasEdge predicate on the "fsevents" edge with a given conditions (other predicates).
func HasFseventsWith(preds ...predicate.FsEvent) predicate.User {
return predicate.User(func(s *sql.Selector) {
step := newFseventsStep()
sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) {
for _, p := range preds {
p(s)
}
})
})
}
// HasEntities applies the HasEdge predicate on the "entities" edge. // HasEntities applies the HasEdge predicate on the "entities" edge.
func HasEntities() predicate.User { func HasEntities() predicate.User {
return predicate.User(func(s *sql.Selector) { return predicate.User(func(s *sql.Selector) {

View File

@ -14,6 +14,7 @@ import (
"github.com/cloudreve/Cloudreve/v4/ent/davaccount" "github.com/cloudreve/Cloudreve/v4/ent/davaccount"
"github.com/cloudreve/Cloudreve/v4/ent/entity" "github.com/cloudreve/Cloudreve/v4/ent/entity"
"github.com/cloudreve/Cloudreve/v4/ent/file" "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/group"
"github.com/cloudreve/Cloudreve/v4/ent/passkey" "github.com/cloudreve/Cloudreve/v4/ent/passkey"
"github.com/cloudreve/Cloudreve/v4/ent/share" "github.com/cloudreve/Cloudreve/v4/ent/share"
@ -252,6 +253,21 @@ func (uc *UserCreate) AddTasks(t ...*Task) *UserCreate {
return uc.AddTaskIDs(ids...) return uc.AddTaskIDs(ids...)
} }
// AddFseventIDs adds the "fsevents" edge to the FsEvent entity by IDs.
func (uc *UserCreate) AddFseventIDs(ids ...int) *UserCreate {
uc.mutation.AddFseventIDs(ids...)
return uc
}
// AddFsevents adds the "fsevents" edges to the FsEvent entity.
func (uc *UserCreate) AddFsevents(f ...*FsEvent) *UserCreate {
ids := make([]int, len(f))
for i := range f {
ids[i] = f[i].ID
}
return uc.AddFseventIDs(ids...)
}
// AddEntityIDs adds the "entities" edge to the Entity entity by IDs. // AddEntityIDs adds the "entities" edge to the Entity entity by IDs.
func (uc *UserCreate) AddEntityIDs(ids ...int) *UserCreate { func (uc *UserCreate) AddEntityIDs(ids ...int) *UserCreate {
uc.mutation.AddEntityIDs(ids...) uc.mutation.AddEntityIDs(ids...)
@ -549,6 +565,22 @@ func (uc *UserCreate) createSpec() (*User, *sqlgraph.CreateSpec) {
} }
_spec.Edges = append(_spec.Edges, edge) _spec.Edges = append(_spec.Edges, edge)
} }
if nodes := uc.mutation.FseventsIDs(); len(nodes) > 0 {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.O2M,
Inverse: false,
Table: user.FseventsTable,
Columns: []string{user.FseventsColumn},
Bidi: false,
Target: &sqlgraph.EdgeTarget{
IDSpec: sqlgraph.NewFieldSpec(fsevent.FieldID, field.TypeInt),
},
}
for _, k := range nodes {
edge.Target.Nodes = append(edge.Target.Nodes, k)
}
_spec.Edges = append(_spec.Edges, edge)
}
if nodes := uc.mutation.EntitiesIDs(); len(nodes) > 0 { if nodes := uc.mutation.EntitiesIDs(); len(nodes) > 0 {
edge := &sqlgraph.EdgeSpec{ edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.O2M, Rel: sqlgraph.O2M,

View File

@ -14,6 +14,7 @@ import (
"github.com/cloudreve/Cloudreve/v4/ent/davaccount" "github.com/cloudreve/Cloudreve/v4/ent/davaccount"
"github.com/cloudreve/Cloudreve/v4/ent/entity" "github.com/cloudreve/Cloudreve/v4/ent/entity"
"github.com/cloudreve/Cloudreve/v4/ent/file" "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/group"
"github.com/cloudreve/Cloudreve/v4/ent/passkey" "github.com/cloudreve/Cloudreve/v4/ent/passkey"
"github.com/cloudreve/Cloudreve/v4/ent/predicate" "github.com/cloudreve/Cloudreve/v4/ent/predicate"
@ -35,6 +36,7 @@ type UserQuery struct {
withShares *ShareQuery withShares *ShareQuery
withPasskey *PasskeyQuery withPasskey *PasskeyQuery
withTasks *TaskQuery withTasks *TaskQuery
withFsevents *FsEventQuery
withEntities *EntityQuery withEntities *EntityQuery
// intermediate query (i.e. traversal path). // intermediate query (i.e. traversal path).
sql *sql.Selector sql *sql.Selector
@ -204,6 +206,28 @@ func (uq *UserQuery) QueryTasks() *TaskQuery {
return query return query
} }
// QueryFsevents chains the current query on the "fsevents" edge.
func (uq *UserQuery) QueryFsevents() *FsEventQuery {
query := (&FsEventClient{config: uq.config}).Query()
query.path = func(ctx context.Context) (fromU *sql.Selector, err error) {
if err := uq.prepareQuery(ctx); err != nil {
return nil, err
}
selector := uq.sqlQuery(ctx)
if err := selector.Err(); err != nil {
return nil, err
}
step := sqlgraph.NewStep(
sqlgraph.From(user.Table, user.FieldID, selector),
sqlgraph.To(fsevent.Table, fsevent.FieldID),
sqlgraph.Edge(sqlgraph.O2M, false, user.FseventsTable, user.FseventsColumn),
)
fromU = sqlgraph.SetNeighbors(uq.driver.Dialect(), step)
return fromU, nil
}
return query
}
// QueryEntities chains the current query on the "entities" edge. // QueryEntities chains the current query on the "entities" edge.
func (uq *UserQuery) QueryEntities() *EntityQuery { func (uq *UserQuery) QueryEntities() *EntityQuery {
query := (&EntityClient{config: uq.config}).Query() query := (&EntityClient{config: uq.config}).Query()
@ -424,6 +448,7 @@ func (uq *UserQuery) Clone() *UserQuery {
withShares: uq.withShares.Clone(), withShares: uq.withShares.Clone(),
withPasskey: uq.withPasskey.Clone(), withPasskey: uq.withPasskey.Clone(),
withTasks: uq.withTasks.Clone(), withTasks: uq.withTasks.Clone(),
withFsevents: uq.withFsevents.Clone(),
withEntities: uq.withEntities.Clone(), withEntities: uq.withEntities.Clone(),
// clone intermediate query. // clone intermediate query.
sql: uq.sql.Clone(), sql: uq.sql.Clone(),
@ -497,6 +522,17 @@ func (uq *UserQuery) WithTasks(opts ...func(*TaskQuery)) *UserQuery {
return uq return uq
} }
// WithFsevents tells the query-builder to eager-load the nodes that are connected to
// the "fsevents" edge. The optional arguments are used to configure the query builder of the edge.
func (uq *UserQuery) WithFsevents(opts ...func(*FsEventQuery)) *UserQuery {
query := (&FsEventClient{config: uq.config}).Query()
for _, opt := range opts {
opt(query)
}
uq.withFsevents = query
return uq
}
// WithEntities tells the query-builder to eager-load the nodes that are connected to // WithEntities tells the query-builder to eager-load the nodes that are connected to
// the "entities" edge. The optional arguments are used to configure the query builder of the edge. // the "entities" edge. The optional arguments are used to configure the query builder of the edge.
func (uq *UserQuery) WithEntities(opts ...func(*EntityQuery)) *UserQuery { func (uq *UserQuery) WithEntities(opts ...func(*EntityQuery)) *UserQuery {
@ -586,13 +622,14 @@ func (uq *UserQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*User, e
var ( var (
nodes = []*User{} nodes = []*User{}
_spec = uq.querySpec() _spec = uq.querySpec()
loadedTypes = [7]bool{ loadedTypes = [8]bool{
uq.withGroup != nil, uq.withGroup != nil,
uq.withFiles != nil, uq.withFiles != nil,
uq.withDavAccounts != nil, uq.withDavAccounts != nil,
uq.withShares != nil, uq.withShares != nil,
uq.withPasskey != nil, uq.withPasskey != nil,
uq.withTasks != nil, uq.withTasks != nil,
uq.withFsevents != nil,
uq.withEntities != nil, uq.withEntities != nil,
} }
) )
@ -655,6 +692,13 @@ func (uq *UserQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*User, e
return nil, err return nil, err
} }
} }
if query := uq.withFsevents; query != nil {
if err := uq.loadFsevents(ctx, query, nodes,
func(n *User) { n.Edges.Fsevents = []*FsEvent{} },
func(n *User, e *FsEvent) { n.Edges.Fsevents = append(n.Edges.Fsevents, e) }); err != nil {
return nil, err
}
}
if query := uq.withEntities; query != nil { if query := uq.withEntities; query != nil {
if err := uq.loadEntities(ctx, query, nodes, if err := uq.loadEntities(ctx, query, nodes,
func(n *User) { n.Edges.Entities = []*Entity{} }, func(n *User) { n.Edges.Entities = []*Entity{} },
@ -845,6 +889,36 @@ func (uq *UserQuery) loadTasks(ctx context.Context, query *TaskQuery, nodes []*U
} }
return nil return nil
} }
func (uq *UserQuery) loadFsevents(ctx context.Context, query *FsEventQuery, nodes []*User, init func(*User), assign func(*User, *FsEvent)) error {
fks := make([]driver.Value, 0, len(nodes))
nodeids := make(map[int]*User)
for i := range nodes {
fks = append(fks, nodes[i].ID)
nodeids[nodes[i].ID] = nodes[i]
if init != nil {
init(nodes[i])
}
}
if len(query.ctx.Fields) > 0 {
query.ctx.AppendFieldOnce(fsevent.FieldUserFsevent)
}
query.Where(predicate.FsEvent(func(s *sql.Selector) {
s.Where(sql.InValues(s.C(user.FseventsColumn), fks...))
}))
neighbors, err := query.All(ctx)
if err != nil {
return err
}
for _, n := range neighbors {
fk := n.UserFsevent
node, ok := nodeids[fk]
if !ok {
return fmt.Errorf(`unexpected referenced foreign-key "user_fsevent" returned %v for node %v`, fk, n.ID)
}
assign(node, n)
}
return nil
}
func (uq *UserQuery) loadEntities(ctx context.Context, query *EntityQuery, nodes []*User, init func(*User), assign func(*User, *Entity)) error { func (uq *UserQuery) loadEntities(ctx context.Context, query *EntityQuery, nodes []*User, init func(*User), assign func(*User, *Entity)) error {
fks := make([]driver.Value, 0, len(nodes)) fks := make([]driver.Value, 0, len(nodes))
nodeids := make(map[int]*User) nodeids := make(map[int]*User)

View File

@ -14,6 +14,7 @@ import (
"github.com/cloudreve/Cloudreve/v4/ent/davaccount" "github.com/cloudreve/Cloudreve/v4/ent/davaccount"
"github.com/cloudreve/Cloudreve/v4/ent/entity" "github.com/cloudreve/Cloudreve/v4/ent/entity"
"github.com/cloudreve/Cloudreve/v4/ent/file" "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/group"
"github.com/cloudreve/Cloudreve/v4/ent/passkey" "github.com/cloudreve/Cloudreve/v4/ent/passkey"
"github.com/cloudreve/Cloudreve/v4/ent/predicate" "github.com/cloudreve/Cloudreve/v4/ent/predicate"
@ -297,6 +298,21 @@ func (uu *UserUpdate) AddTasks(t ...*Task) *UserUpdate {
return uu.AddTaskIDs(ids...) return uu.AddTaskIDs(ids...)
} }
// AddFseventIDs adds the "fsevents" edge to the FsEvent entity by IDs.
func (uu *UserUpdate) AddFseventIDs(ids ...int) *UserUpdate {
uu.mutation.AddFseventIDs(ids...)
return uu
}
// AddFsevents adds the "fsevents" edges to the FsEvent entity.
func (uu *UserUpdate) AddFsevents(f ...*FsEvent) *UserUpdate {
ids := make([]int, len(f))
for i := range f {
ids[i] = f[i].ID
}
return uu.AddFseventIDs(ids...)
}
// AddEntityIDs adds the "entities" edge to the Entity entity by IDs. // AddEntityIDs adds the "entities" edge to the Entity entity by IDs.
func (uu *UserUpdate) AddEntityIDs(ids ...int) *UserUpdate { func (uu *UserUpdate) AddEntityIDs(ids ...int) *UserUpdate {
uu.mutation.AddEntityIDs(ids...) uu.mutation.AddEntityIDs(ids...)
@ -428,6 +444,27 @@ func (uu *UserUpdate) RemoveTasks(t ...*Task) *UserUpdate {
return uu.RemoveTaskIDs(ids...) return uu.RemoveTaskIDs(ids...)
} }
// ClearFsevents clears all "fsevents" edges to the FsEvent entity.
func (uu *UserUpdate) ClearFsevents() *UserUpdate {
uu.mutation.ClearFsevents()
return uu
}
// RemoveFseventIDs removes the "fsevents" edge to FsEvent entities by IDs.
func (uu *UserUpdate) RemoveFseventIDs(ids ...int) *UserUpdate {
uu.mutation.RemoveFseventIDs(ids...)
return uu
}
// RemoveFsevents removes "fsevents" edges to FsEvent entities.
func (uu *UserUpdate) RemoveFsevents(f ...*FsEvent) *UserUpdate {
ids := make([]int, len(f))
for i := range f {
ids[i] = f[i].ID
}
return uu.RemoveFseventIDs(ids...)
}
// ClearEntities clears all "entities" edges to the Entity entity. // ClearEntities clears all "entities" edges to the Entity entity.
func (uu *UserUpdate) ClearEntities() *UserUpdate { func (uu *UserUpdate) ClearEntities() *UserUpdate {
uu.mutation.ClearEntities() uu.mutation.ClearEntities()
@ -828,6 +865,51 @@ func (uu *UserUpdate) sqlSave(ctx context.Context) (n int, err error) {
} }
_spec.Edges.Add = append(_spec.Edges.Add, edge) _spec.Edges.Add = append(_spec.Edges.Add, edge)
} }
if uu.mutation.FseventsCleared() {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.O2M,
Inverse: false,
Table: user.FseventsTable,
Columns: []string{user.FseventsColumn},
Bidi: false,
Target: &sqlgraph.EdgeTarget{
IDSpec: sqlgraph.NewFieldSpec(fsevent.FieldID, field.TypeInt),
},
}
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
}
if nodes := uu.mutation.RemovedFseventsIDs(); len(nodes) > 0 && !uu.mutation.FseventsCleared() {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.O2M,
Inverse: false,
Table: user.FseventsTable,
Columns: []string{user.FseventsColumn},
Bidi: false,
Target: &sqlgraph.EdgeTarget{
IDSpec: sqlgraph.NewFieldSpec(fsevent.FieldID, field.TypeInt),
},
}
for _, k := range nodes {
edge.Target.Nodes = append(edge.Target.Nodes, k)
}
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
}
if nodes := uu.mutation.FseventsIDs(); len(nodes) > 0 {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.O2M,
Inverse: false,
Table: user.FseventsTable,
Columns: []string{user.FseventsColumn},
Bidi: false,
Target: &sqlgraph.EdgeTarget{
IDSpec: sqlgraph.NewFieldSpec(fsevent.FieldID, field.TypeInt),
},
}
for _, k := range nodes {
edge.Target.Nodes = append(edge.Target.Nodes, k)
}
_spec.Edges.Add = append(_spec.Edges.Add, edge)
}
if uu.mutation.EntitiesCleared() { if uu.mutation.EntitiesCleared() {
edge := &sqlgraph.EdgeSpec{ edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.O2M, Rel: sqlgraph.O2M,
@ -1154,6 +1236,21 @@ func (uuo *UserUpdateOne) AddTasks(t ...*Task) *UserUpdateOne {
return uuo.AddTaskIDs(ids...) return uuo.AddTaskIDs(ids...)
} }
// AddFseventIDs adds the "fsevents" edge to the FsEvent entity by IDs.
func (uuo *UserUpdateOne) AddFseventIDs(ids ...int) *UserUpdateOne {
uuo.mutation.AddFseventIDs(ids...)
return uuo
}
// AddFsevents adds the "fsevents" edges to the FsEvent entity.
func (uuo *UserUpdateOne) AddFsevents(f ...*FsEvent) *UserUpdateOne {
ids := make([]int, len(f))
for i := range f {
ids[i] = f[i].ID
}
return uuo.AddFseventIDs(ids...)
}
// AddEntityIDs adds the "entities" edge to the Entity entity by IDs. // AddEntityIDs adds the "entities" edge to the Entity entity by IDs.
func (uuo *UserUpdateOne) AddEntityIDs(ids ...int) *UserUpdateOne { func (uuo *UserUpdateOne) AddEntityIDs(ids ...int) *UserUpdateOne {
uuo.mutation.AddEntityIDs(ids...) uuo.mutation.AddEntityIDs(ids...)
@ -1285,6 +1382,27 @@ func (uuo *UserUpdateOne) RemoveTasks(t ...*Task) *UserUpdateOne {
return uuo.RemoveTaskIDs(ids...) return uuo.RemoveTaskIDs(ids...)
} }
// ClearFsevents clears all "fsevents" edges to the FsEvent entity.
func (uuo *UserUpdateOne) ClearFsevents() *UserUpdateOne {
uuo.mutation.ClearFsevents()
return uuo
}
// RemoveFseventIDs removes the "fsevents" edge to FsEvent entities by IDs.
func (uuo *UserUpdateOne) RemoveFseventIDs(ids ...int) *UserUpdateOne {
uuo.mutation.RemoveFseventIDs(ids...)
return uuo
}
// RemoveFsevents removes "fsevents" edges to FsEvent entities.
func (uuo *UserUpdateOne) RemoveFsevents(f ...*FsEvent) *UserUpdateOne {
ids := make([]int, len(f))
for i := range f {
ids[i] = f[i].ID
}
return uuo.RemoveFseventIDs(ids...)
}
// ClearEntities clears all "entities" edges to the Entity entity. // ClearEntities clears all "entities" edges to the Entity entity.
func (uuo *UserUpdateOne) ClearEntities() *UserUpdateOne { func (uuo *UserUpdateOne) ClearEntities() *UserUpdateOne {
uuo.mutation.ClearEntities() uuo.mutation.ClearEntities()
@ -1715,6 +1833,51 @@ func (uuo *UserUpdateOne) sqlSave(ctx context.Context) (_node *User, err error)
} }
_spec.Edges.Add = append(_spec.Edges.Add, edge) _spec.Edges.Add = append(_spec.Edges.Add, edge)
} }
if uuo.mutation.FseventsCleared() {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.O2M,
Inverse: false,
Table: user.FseventsTable,
Columns: []string{user.FseventsColumn},
Bidi: false,
Target: &sqlgraph.EdgeTarget{
IDSpec: sqlgraph.NewFieldSpec(fsevent.FieldID, field.TypeInt),
},
}
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
}
if nodes := uuo.mutation.RemovedFseventsIDs(); len(nodes) > 0 && !uuo.mutation.FseventsCleared() {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.O2M,
Inverse: false,
Table: user.FseventsTable,
Columns: []string{user.FseventsColumn},
Bidi: false,
Target: &sqlgraph.EdgeTarget{
IDSpec: sqlgraph.NewFieldSpec(fsevent.FieldID, field.TypeInt),
},
}
for _, k := range nodes {
edge.Target.Nodes = append(edge.Target.Nodes, k)
}
_spec.Edges.Clear = append(_spec.Edges.Clear, edge)
}
if nodes := uuo.mutation.FseventsIDs(); len(nodes) > 0 {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.O2M,
Inverse: false,
Table: user.FseventsTable,
Columns: []string{user.FseventsColumn},
Bidi: false,
Target: &sqlgraph.EdgeTarget{
IDSpec: sqlgraph.NewFieldSpec(fsevent.FieldID, field.TypeInt),
},
}
for _, k := range nodes {
edge.Target.Nodes = append(edge.Target.Nodes, k)
}
_spec.Edges.Add = append(_spec.Edges.Add, edge)
}
if uuo.mutation.EntitiesCleared() { if uuo.mutation.EntitiesCleared() {
edge := &sqlgraph.EdgeSpec{ edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.O2M, Rel: sqlgraph.O2M,

81
inventory/fs_event.go Normal file
View File

@ -0,0 +1,81 @@
package inventory
import (
"context"
"github.com/cloudreve/Cloudreve/v4/ent"
"github.com/cloudreve/Cloudreve/v4/ent/fsevent"
"github.com/cloudreve/Cloudreve/v4/ent/schema"
"github.com/cloudreve/Cloudreve/v4/pkg/conf"
"github.com/gofrs/uuid"
"github.com/samber/lo"
)
type FsEventClient interface {
TxOperator
// Create a new FsEvent
Create(ctx context.Context, uid int, subscriberId uuid.UUID, events ...string) error
// Delete all FsEvents by subscriber
DeleteBySubscriber(ctx context.Context, subscriberId uuid.UUID) error
// Delete all FsEvents
DeleteAll(ctx context.Context) error
// Get all FsEvents by subscriber and user
TakeBySubscriber(ctx context.Context, subscriberId uuid.UUID, userId int) ([]*ent.FsEvent, error)
}
func NewFsEventClient(client *ent.Client, dbType conf.DBType) FsEventClient {
return &fsEventClient{client: client, maxSQlParam: sqlParamLimit(dbType)}
}
type fsEventClient struct {
maxSQlParam int
client *ent.Client
}
func (c *fsEventClient) SetClient(newClient *ent.Client) TxOperator {
return &fsEventClient{client: newClient, maxSQlParam: c.maxSQlParam}
}
func (c *fsEventClient) GetClient() *ent.Client {
return c.client
}
func (c *fsEventClient) Create(ctx context.Context, uid int, subscriberId uuid.UUID, events ...string) error {
stms := lo.Map(events, func(event string, index int) *ent.FsEventCreate {
res := c.client.FsEvent.
Create().
SetUserFsevent(uid).
SetEvent(event).
SetSubscriber(subscriberId).SetEvent(event)
return res
})
_, err := c.client.FsEvent.CreateBulk(stms...).Save(ctx)
return err
}
func (c *fsEventClient) DeleteBySubscriber(ctx context.Context, subscriberId uuid.UUID) error {
_, err := c.client.FsEvent.Delete().Where(fsevent.Subscriber(subscriberId)).Exec(schema.SkipSoftDelete(ctx))
return err
}
func (c *fsEventClient) DeleteAll(ctx context.Context) error {
_, err := c.client.FsEvent.Delete().Exec(schema.SkipSoftDelete(ctx))
return err
}
func (c *fsEventClient) TakeBySubscriber(ctx context.Context, subscriberId uuid.UUID, userId int) ([]*ent.FsEvent, error) {
res, err := c.client.FsEvent.Query().Where(fsevent.Subscriber(subscriberId), fsevent.UserFsevent(userId)).All(ctx)
if err != nil {
return nil, err
}
// Delete the FsEvents
_, err = c.client.FsEvent.Delete().Where(fsevent.Subscriber(subscriberId), fsevent.UserFsevent(userId)).Exec(schema.SkipSoftDelete(ctx))
if err != nil {
return nil, err
}
return res, nil
}

View File

@ -103,6 +103,7 @@ func InitializeHandling(dep dependency.Dep) gin.HandlerFunc {
IP: clientIp, IP: clientIp,
Host: c.Request.Host, Host: c.Request.Host,
UserAgent: c.Request.UserAgent(), UserAgent: c.Request.UserAgent(),
ClientID: c.GetHeader(request.ClientIDHeader),
} }
cid := uuid.FromStringOrNil(c.GetHeader(request.CorrelationHeader)) cid := uuid.FromStringOrNil(c.GetHeader(request.CorrelationHeader))
if cid == uuid.Nil { if cid == uuid.Nil {

View File

@ -22,4 +22,6 @@ type RequestInfo struct {
Host string Host string
IP string IP string
UserAgent string UserAgent string
// ID of sync client
ClientID string
} }

View File

@ -347,7 +347,7 @@ func (handler *Driver) Source(ctx context.Context, e fs.Entity, args *driver.Get
var contentDescription *string var contentDescription *string
if args.IsDownload { if args.IsDownload {
encodedFilename := url.PathEscape(args.DisplayName) encodedFilename := url.PathEscape(args.DisplayName)
contentDescription = aws.String(fmt.Sprintf(`attachment; filename="%s"`, encodedFilename)) contentDescription = aws.String(fmt.Sprintf(`attachment; filename=%s`, encodedFilename))
} }
// 确保过期时间不小于 0 ,如果小于则设置为 7 天 // 确保过期时间不小于 0 ,如果小于则设置为 7 天

View File

@ -0,0 +1,193 @@
package eventhub
import "errors"
type (
Event struct {
Type EventType `json:"type"`
FileID string `json:"file_id"`
From string `json:"from"`
To string `json:"to"`
}
EventType string
)
const (
EventTypeCreate = "create"
EventTypeModify = "modify"
EventTypeRename = "rename"
EventTypeDelete = "delete"
)
var (
// ErrEventHubClosed is returned when operations are attempted on a closed EventHub.
ErrEventHubClosed = errors.New("event hub is closed")
)
// eventState tracks the accumulated state for each file
type eventState struct {
baseType EventType // The base event type (Create, Delete, or first event type)
originalSrc string // Original source path (for Create or first Rename)
currentDst string // Current destination path
}
/*
Modify + Modify keep only the last Modify;
Create + Modify fold into a single Create with final metadata/content.
Create + Rename(ab) Create at b.
Create + Delete drop both (ephemeral object never needs to reach clients).
Modify + Delete Delete (intermediate Modify is irrelevant to final state).
Rename(ab) + Rename(bc) Rename(ac).
Rename(ab) + Modify emit Rename(ab) then a single Modify at b (or fold Modify into Create if the chain starts with Create).
Rename(ab) + Delete emit only Delete(object_id);
Rename(ab) + Rename(ba) with no intervening Modify drop both (rename there-and-back is a no-op).
Delete + Create might be a valid case, e.g. user restore same file from trash bin.
*/
// DebounceEvents takes time-ordered events and returns debounced/merged events.
func DebounceEvents(in []*Event) []*Event {
if len(in) == 0 {
return nil
}
states := make(map[string]*eventState) // keyed by FileID
order := make([]string, 0) // to preserve order of first appearance
for _, e := range in {
state, exists := states[e.FileID]
if !exists {
// First event for this file
order = append(order, e.FileID)
states[e.FileID] = &eventState{
baseType: e.Type,
originalSrc: e.From,
currentDst: e.To,
}
continue
}
switch e.Type {
case EventTypeCreate:
// Delete + Create → keep as Create (e.g. restore from trash)
if state.baseType == EventTypeDelete {
state.baseType = EventTypeCreate
state.originalSrc = e.From
state.currentDst = ""
}
case EventTypeModify:
switch state.baseType {
case EventTypeCreate:
// Create + Modify → fold into Create (no change needed, Create already implies content)
case EventTypeModify:
// Modify + Modify → keep only last Modify (state already correct)
case EventTypeRename:
// Rename + Modify → fold into first Rename
case EventTypeDelete:
// Delete + Modify → should not happen, but ignore Modify
}
case EventTypeRename:
switch state.baseType {
case EventTypeCreate:
// Create + Rename(a→b) → Create at b
state.originalSrc = e.To
state.currentDst = ""
case EventTypeModify:
// Modify + Rename → emit Rename only
state.baseType = EventTypeRename
state.currentDst = e.To
state.originalSrc = e.From
case EventTypeRename:
// Rename(a→b) + Rename(b→c) → Rename(a→c)
// Check for no-op: Rename(a→b) + Rename(b→a) → drop both
if state.originalSrc == e.To {
// Rename there-and-back, drop both
delete(states, e.FileID)
// Remove from order
for i, id := range order {
if id == e.FileID {
order = append(order[:i], order[i+1:]...)
break
}
}
} else {
state.currentDst = e.To
}
case EventTypeDelete:
// Delete + Rename → should not happen, ignore
}
case EventTypeDelete:
switch state.baseType {
case EventTypeCreate:
// Create + Delete → drop both (ephemeral object)
delete(states, e.FileID)
// Remove from order
for i, id := range order {
if id == e.FileID {
order = append(order[:i], order[i+1:]...)
break
}
}
case EventTypeModify:
// Modify + Delete → Delete
state.baseType = EventTypeDelete
state.originalSrc = e.From
state.currentDst = ""
case EventTypeRename:
// Rename + Delete → Delete only
state.baseType = EventTypeDelete
state.originalSrc = e.From
state.currentDst = ""
case EventTypeDelete:
// Delete + Delete → keep Delete (should not happen normally)
}
}
}
// Build output events in order
result := make([]*Event, 0, len(order))
for _, fileID := range order {
state, exists := states[fileID]
if !exists {
continue
}
switch state.baseType {
case EventTypeCreate:
result = append(result, &Event{
Type: EventTypeCreate,
FileID: fileID,
From: state.originalSrc,
})
case EventTypeModify:
result = append(result, &Event{
Type: EventTypeModify,
FileID: fileID,
From: state.originalSrc,
})
case EventTypeRename:
// If hasModify and base was originally Modify (converted to Rename),
// we need to emit Modify first at original location
// But in our current logic, Modify+Rename sets hasModify=true
// We emit Rename, then Modify if needed
result = append(result, &Event{
Type: EventTypeRename,
FileID: fileID,
From: state.originalSrc,
To: state.currentDst,
})
case EventTypeDelete:
result = append(result, &Event{
Type: EventTypeDelete,
FileID: fileID,
From: state.originalSrc,
})
}
}
return result
}

View File

@ -0,0 +1,199 @@
package eventhub
import (
"context"
"sync"
"time"
"github.com/cloudreve/Cloudreve/v4/inventory"
"github.com/cloudreve/Cloudreve/v4/pkg/logging"
)
type (
EventHub interface {
// Subscribe to a topic and return a channel to receive events.
// If a subscriber with the same ID already exists and is offline,
// it will be reactivated and any buffered events will be flushed.
Subscribe(ctx context.Context, topic int, id string) (chan *Event, bool, error)
// Unsubscribe marks the subscriber as offline instead of removing it.
// Buffered events will be kept for when the subscriber reconnects.
// Subscribers that remain offline for more than 14 days will be permanently removed.
Unsubscribe(ctx context.Context, topic int, id string)
// Get subscribers of a topic.
GetSubscribers(ctx context.Context, topic int) []Subscriber
// Close shuts down the event hub and disconnects all subscribers.
Close()
}
)
const (
bufSize = 16
cleanupPeriod = 1 * time.Hour
)
type eventHub struct {
mu sync.RWMutex
topics map[int]map[string]*subscriber
userClient inventory.UserClient
fsEventClient inventory.FsEventClient
closed bool
closeCh chan struct{}
wg sync.WaitGroup
}
func NewEventHub(userClient inventory.UserClient, fsEventClient inventory.FsEventClient) EventHub {
e := &eventHub{
topics: make(map[int]map[string]*subscriber),
userClient: userClient,
fsEventClient: fsEventClient,
closeCh: make(chan struct{}),
}
// Remove all existing FsEvents
fsEventClient.DeleteAll(context.Background())
// Start background cleanup goroutine
e.wg.Add(1)
go e.cleanupLoop()
return e
}
// cleanupLoop periodically removes subscribers that have been offline for too long.
func (e *eventHub) cleanupLoop() {
defer e.wg.Done()
ticker := time.NewTicker(cleanupPeriod)
defer ticker.Stop()
for {
select {
case <-e.closeCh:
return
case <-ticker.C:
e.cleanupExpiredSubscribers()
}
}
}
// cleanupExpiredSubscribers removes subscribers that have been offline for more than 14 days.
func (e *eventHub) cleanupExpiredSubscribers() {
e.mu.Lock()
defer e.mu.Unlock()
if e.closed {
return
}
for topic, subs := range e.topics {
for id, sub := range subs {
if sub.shouldExpire() {
sub.close()
delete(subs, id)
}
}
if len(subs) == 0 {
delete(e.topics, topic)
}
}
}
func (e *eventHub) GetSubscribers(ctx context.Context, topic int) []Subscriber {
e.mu.RLock()
defer e.mu.RUnlock()
subs := make([]Subscriber, 0, len(e.topics[topic]))
for _, v := range e.topics[topic] {
subs = append(subs, v)
}
return subs
}
func (e *eventHub) Subscribe(ctx context.Context, topic int, id string) (chan *Event, bool, error) {
l := logging.FromContext(ctx)
l.Info("Subscribing to event hub for topic %d with id %s", topic, id)
e.mu.Lock()
defer e.mu.Unlock()
if e.closed {
return nil, false, ErrEventHubClosed
}
subs, ok := e.topics[topic]
if !ok {
subs = make(map[string]*subscriber)
e.topics[topic] = subs
}
// Check if subscriber already exists
if existingSub, ok := subs[id]; ok {
if existingSub.isClosed() {
// Subscriber was closed, create a new one
delete(subs, id)
} else {
// Reactivate the offline subscriber
l.Info("Reactivating offline subscriber %s for topic %d", id, topic)
existingSub.setOnline(ctx)
return existingSub.ch, true, nil
}
}
sub, err := newSubscriber(ctx, id, e.userClient, e.fsEventClient)
if err != nil {
return nil, false, err
}
e.topics[topic][id] = sub
return sub.ch, false, nil
}
func (e *eventHub) Unsubscribe(ctx context.Context, topic int, id string) {
l := logging.FromContext(ctx)
l.Info("Marking subscriber offline for topic %d with id %s", topic, id)
e.mu.Lock()
defer e.mu.Unlock()
if e.closed {
return
}
subs, ok := e.topics[topic]
if !ok {
return
}
if sub, ok := subs[id]; ok {
// Stop debounce timer but keep events in buffer
sub.Stop()
// Mark as offline instead of deleting
sub.setOffline()
}
}
// Close shuts down the event hub and disconnects all subscribers.
func (e *eventHub) Close() {
e.mu.Lock()
if e.closed {
e.mu.Unlock()
return
}
e.closed = true
close(e.closeCh)
// Close all subscribers
for _, subs := range e.topics {
for _, sub := range subs {
sub.close()
}
}
e.topics = nil
e.mu.Unlock()
// Wait for cleanup goroutine to finish
e.wg.Wait()
}

View File

@ -0,0 +1,317 @@
package eventhub
import (
"context"
"encoding/json"
"errors"
"fmt"
"sync"
"time"
"github.com/cloudreve/Cloudreve/v4/ent"
"github.com/cloudreve/Cloudreve/v4/inventory"
"github.com/cloudreve/Cloudreve/v4/pkg/logging"
"github.com/gofrs/uuid"
"github.com/samber/lo"
)
type Subscriber interface {
ID() string
Ch() chan *Event
Publish(evt Event)
Stop()
Buffer() []*Event
// Owner returns the owner of the subscriber.
Owner() (*ent.User, error)
// Online returns whether the subscriber is online.
Online() bool
// OfflineSince returns when the subscriber went offline.
// Returns zero time if the subscriber is online.
OfflineSince() time.Time
}
const (
debounceDelay = 5 * time.Second
userCacheTTL = 1 * time.Hour
offlineMaxAge = 14 * 24 * time.Hour // 14 days
)
type subscriber struct {
mu sync.Mutex
userClient inventory.UserClient
fsEventClient inventory.FsEventClient
id string
uid int
ch chan *Event
// Online status
online bool
offlineSince time.Time
// Debounce buffer for pending events
buffer []*Event
timer *time.Timer
// Owner info
ownerCached *ent.User
cachedAt time.Time
// Close signal
closed bool
closedCh chan struct{}
}
func newSubscriber(ctx context.Context, id string, userClient inventory.UserClient, fsEventClient inventory.FsEventClient) (*subscriber, error) {
user := inventory.UserFromContext(ctx)
if user == nil || inventory.IsAnonymousUser(user) {
return nil, errors.New("user not found")
}
return &subscriber{
id: id,
ch: make(chan *Event, bufSize),
userClient: userClient,
fsEventClient: fsEventClient,
ownerCached: user,
uid: user.ID,
cachedAt: time.Now(),
online: true,
closedCh: make(chan struct{}),
}, nil
}
func (s *subscriber) ID() string {
return s.id
}
func (s *subscriber) Ch() chan *Event {
return s.ch
}
func (s *subscriber) Online() bool {
s.mu.Lock()
defer s.mu.Unlock()
return s.online
}
func (s *subscriber) OfflineSince() time.Time {
s.mu.Lock()
defer s.mu.Unlock()
return s.offlineSince
}
func (s *subscriber) Owner() (*ent.User, error) {
s.mu.Lock()
defer s.mu.Unlock()
if time.Since(s.cachedAt) > userCacheTTL || s.ownerCached == nil {
user, err := s.userClient.GetLoginUserByID(context.Background(), s.uid)
if err != nil {
return nil, fmt.Errorf("failed to get login user: %w", err)
}
s.ownerCached = user
s.cachedAt = time.Now()
}
return s.ownerCached, nil
}
// Publish adds an event to the buffer and starts/resets the debounce timer.
// Events will be flushed to the channel after the debounce delay.
// If the subscriber is offline, events are kept in the buffer only.
func (s *subscriber) Publish(evt Event) {
s.mu.Lock()
defer s.mu.Unlock()
if s.closed {
return
}
s.publishLocked(evt)
}
// publishLocked adds an event to the buffer and manages the debounce timer.
// Caller must hold s.mu.
func (s *subscriber) publishLocked(evt Event) {
// Add event to buffer
s.buffer = append(s.buffer, &evt)
// Reset or start the debounce timer
if s.timer != nil {
s.timer.Stop()
}
s.timer = time.AfterFunc(debounceDelay, s.flush)
}
// flush sends all buffered events to the channel.
// Called by the debounce timer.
func (s *subscriber) flush() {
s.mu.Lock()
defer s.mu.Unlock()
s.flushLocked(context.Background())
}
// flushLocked sends all buffered events to the channel.
// Caller must hold s.mu.
func (s *subscriber) flushLocked(ctx context.Context) {
if len(s.buffer) == 0 || s.closed {
return
}
if !s.online {
_ = s.fsEventClient.Create(ctx, s.ownerCached.ID, uuid.FromStringOrNil(s.id), lo.Map(s.buffer, func(item *Event, index int) string {
res, _ := json.Marshal(item)
return string(res)
})...)
} else {
// TODO: implement event merging logic here
// For now, send all buffered events individually
debouncedEvents := DebounceEvents(s.buffer)
for _, evt := range debouncedEvents {
select {
case s.ch <- evt:
default:
// Non-blocking send; drop if subscriber is slow
}
}
}
// Clear the buffer
s.buffer = nil
s.timer = nil
}
// Stop cancels any pending debounce timer and flushes remaining events.
// Should be called before closing the subscriber.
func (s *subscriber) Stop() {
s.mu.Lock()
defer s.mu.Unlock()
if s.timer != nil {
s.timer.Stop()
s.timer = nil
}
// Flush any remaining events before stopping
s.flushLocked(context.Background())
}
// setOnline marks the subscriber as online and flushes any buffered events.
func (s *subscriber) setOnline(ctx context.Context) {
l := logging.FromContext(ctx)
s.mu.Lock()
defer s.mu.Unlock()
if s.closed {
return
}
s.online = true
s.ownerCached = nil
s.offlineSince = time.Time{}
// Retrieve events from inventory
events, err := s.fsEventClient.TakeBySubscriber(ctx, uuid.FromStringOrNil(s.id), s.uid)
if err != nil {
l.Error("Failed to get events from inventory: %s", err)
return
}
// Append events to buffer
for _, event := range events {
var eventParsed Event
err := json.Unmarshal([]byte(event.Event), &eventParsed)
if err != nil {
l.Error("Failed to unmarshal event: %s", err)
continue
}
s.buffer = append(s.buffer, &eventParsed)
}
// Flush buffered events if any
if len(s.buffer) > 0 {
if s.timer != nil {
s.timer.Stop()
}
s.timer = time.AfterFunc(debounceDelay, s.flush)
}
}
// setOffline marks the subscriber as offline.
func (s *subscriber) setOffline() {
s.mu.Lock()
defer s.mu.Unlock()
if s.closed {
return
}
s.online = false
s.offlineSince = time.Now()
// Stop the timer, events will be kept in buffer
if s.timer != nil {
s.timer.Stop()
s.timer = nil
}
// flush the buffer
s.flushLocked(context.Background())
}
// close permanently closes the subscriber.
func (s *subscriber) close() {
s.mu.Lock()
defer s.mu.Unlock()
if s.closed {
return
}
s.closed = true
if s.timer != nil {
s.timer.Stop()
s.timer = nil
}
// Delete the FsEvent
s.fsEventClient.DeleteBySubscriber(context.Background(), uuid.FromStringOrNil(s.id))
// Signal close and close the channel
close(s.closedCh)
close(s.ch)
s.buffer = nil
}
// isClosed returns whether the subscriber is closed.
func (s *subscriber) isClosed() bool {
s.mu.Lock()
defer s.mu.Unlock()
return s.closed
}
// shouldExpire returns whether the subscriber should be expired (offline for too long).
func (s *subscriber) shouldExpire() bool {
s.mu.Lock()
defer s.mu.Unlock()
return !s.online && !s.offlineSince.IsZero() && time.Since(s.offlineSince) > offlineMaxAge
}
// Buffer returns a copy of the current buffered events.
// Useful for debugging or implementing custom merging logic.
func (s *subscriber) Buffer() []*Event {
s.mu.Lock()
defer s.mu.Unlock()
if len(s.buffer) == 0 {
return nil
}
// Return a copy to avoid data races
buf := make([]*Event, len(s.buffer))
copy(buf, s.buffer)
return buf
}

View File

@ -15,6 +15,7 @@ import (
"github.com/cloudreve/Cloudreve/v4/inventory/types" "github.com/cloudreve/Cloudreve/v4/inventory/types"
"github.com/cloudreve/Cloudreve/v4/pkg/cache" "github.com/cloudreve/Cloudreve/v4/pkg/cache"
"github.com/cloudreve/Cloudreve/v4/pkg/filemanager/encrypt" "github.com/cloudreve/Cloudreve/v4/pkg/filemanager/encrypt"
"github.com/cloudreve/Cloudreve/v4/pkg/filemanager/eventhub"
"github.com/cloudreve/Cloudreve/v4/pkg/filemanager/fs" "github.com/cloudreve/Cloudreve/v4/pkg/filemanager/fs"
"github.com/cloudreve/Cloudreve/v4/pkg/filemanager/lock" "github.com/cloudreve/Cloudreve/v4/pkg/filemanager/lock"
"github.com/cloudreve/Cloudreve/v4/pkg/hashid" "github.com/cloudreve/Cloudreve/v4/pkg/hashid"
@ -44,7 +45,7 @@ type (
func NewDatabaseFS(u *ent.User, fileClient inventory.FileClient, shareClient inventory.ShareClient, func NewDatabaseFS(u *ent.User, fileClient inventory.FileClient, shareClient inventory.ShareClient,
l logging.Logger, ls lock.LockSystem, settingClient setting.Provider, l logging.Logger, ls lock.LockSystem, settingClient setting.Provider,
storagePolicyClient inventory.StoragePolicyClient, hasher hashid.Encoder, userClient inventory.UserClient, storagePolicyClient inventory.StoragePolicyClient, hasher hashid.Encoder, userClient inventory.UserClient,
cache, stateKv cache.Driver, directLinkClient inventory.DirectLinkClient, encryptorFactory encrypt.CryptorFactory) fs.FileSystem { cache, stateKv cache.Driver, directLinkClient inventory.DirectLinkClient, encryptorFactory encrypt.CryptorFactory, eventHub eventhub.EventHub) fs.FileSystem {
return &DBFS{ return &DBFS{
user: u, user: u,
navigators: make(map[string]Navigator), navigators: make(map[string]Navigator),
@ -60,6 +61,7 @@ func NewDatabaseFS(u *ent.User, fileClient inventory.FileClient, shareClient inv
stateKv: stateKv, stateKv: stateKv,
directLinkClient: directLinkClient, directLinkClient: directLinkClient,
encryptorFactory: encryptorFactory, encryptorFactory: encryptorFactory,
eventHub: eventHub,
} }
} }
@ -79,6 +81,7 @@ type DBFS struct {
stateKv cache.Driver stateKv cache.Driver
mu sync.Mutex mu sync.Mutex
encryptorFactory encrypt.CryptorFactory encryptorFactory encrypt.CryptorFactory
eventHub eventhub.EventHub
} }
func (f *DBFS) Recycle() { func (f *DBFS) Recycle() {
@ -643,7 +646,9 @@ func (f *DBFS) createFile(ctx context.Context, parent *File, name string, fileTy
} }
file.SetEntities([]*ent.Entity{entity}) file.SetEntities([]*ent.Entity{entity})
return newFile(parent, file), nil newFile := newFile(parent, file)
f.emitFileCreated(ctx, newFile)
return newFile, nil
} }
func (f *DBFS) generateEncryptMetadata(ctx context.Context, uploadRequest *fs.UploadRequest, policy *ent.StoragePolicy) (*types.EncryptMetadata, error) { func (f *DBFS) generateEncryptMetadata(ctx context.Context, uploadRequest *fs.UploadRequest, policy *ent.StoragePolicy) (*types.EncryptMetadata, error) {

View File

@ -0,0 +1,150 @@
package dbfs
import (
"context"
"path"
"strings"
"github.com/cloudreve/Cloudreve/v4/pkg/auth/requestinfo"
"github.com/cloudreve/Cloudreve/v4/pkg/filemanager/eventhub"
"github.com/cloudreve/Cloudreve/v4/pkg/filemanager/fs"
"github.com/cloudreve/Cloudreve/v4/pkg/hashid"
"github.com/samber/lo"
)
func (f *DBFS) emitFileCreated(ctx context.Context, file *File) {
subscribers := f.getEligibleSubscriber(ctx, file, true)
for _, subscriber := range subscribers {
subscriber.Publish(eventhub.Event{
Type: eventhub.EventTypeCreate,
FileID: hashid.EncodeFileID(f.hasher, file.Model.ID),
From: subscriber.relativePath(file),
})
}
}
func (f *DBFS) emitFileModified(ctx context.Context, file *File) {
subscribers := f.getEligibleSubscriber(ctx, file, true)
for _, subscriber := range subscribers {
subscriber.Publish(eventhub.Event{
Type: eventhub.EventTypeModify,
FileID: hashid.EncodeFileID(f.hasher, file.Model.ID),
From: subscriber.relativePath(file),
})
}
}
func (f *DBFS) emitFileRenamed(ctx context.Context, file *File, newName string) {
subscribers := f.getEligibleSubscriber(ctx, file, true)
for _, subscriber := range subscribers {
from := subscriber.relativePath(file)
to := strings.TrimSuffix(from, file.Name()) + newName
subscriber.Publish(eventhub.Event{
Type: eventhub.EventTypeRename,
FileID: hashid.EncodeFileID(f.hasher, file.Model.ID),
From: subscriber.relativePath(file),
To: to,
})
}
}
func (f *DBFS) emitFileDeleted(ctx context.Context, files ...*File) {
for _, file := range files {
subscribers := f.getEligibleSubscriber(ctx, file, true)
for _, subscriber := range subscribers {
subscriber.Publish(eventhub.Event{
Type: eventhub.EventTypeDelete,
FileID: hashid.EncodeFileID(f.hasher, file.Model.ID),
From: subscriber.relativePath(file),
})
}
}
}
func (f *DBFS) emitFileMoved(ctx context.Context, src, dst *File) {
srcSubMap := lo.SliceToMap(f.getEligibleSubscriber(ctx, src, true), func(subscriber foundSubscriber) (string, *foundSubscriber) {
return subscriber.ID(), &subscriber
})
dstSubMap := lo.SliceToMap(f.getEligibleSubscriber(ctx, dst, false), func(subscriber foundSubscriber) (string, *foundSubscriber) {
return subscriber.ID(), &subscriber
})
for _, subscriber := range srcSubMap {
subId := subscriber.ID()
if dstSub, ok := dstSubMap[subId]; ok {
// Src and Dst subscribed by the same subscriber
subscriber.Publish(eventhub.Event{
Type: eventhub.EventTypeRename,
FileID: hashid.EncodeFileID(f.hasher, src.Model.ID),
From: subscriber.relativePath(src),
To: path.Join(dstSub.relativePath(dst), src.Name()),
})
delete(dstSubMap, subId)
} else {
// Only Src is subscribed by the subscriber
subscriber.Publish(eventhub.Event{
Type: eventhub.EventTypeDelete,
FileID: hashid.EncodeFileID(f.hasher, src.Model.ID),
From: subscriber.relativePath(src),
})
}
}
for _, subscriber := range dstSubMap {
// Only Dst is subscribed by the subscriber
subscriber.Publish(eventhub.Event{
Type: eventhub.EventTypeCreate,
FileID: hashid.EncodeFileID(f.hasher, src.Model.ID),
From: path.Join(subscriber.relativePath(dst), src.Name()),
})
}
}
func (f *DBFS) getEligibleSubscriber(ctx context.Context, file *File, checkParentPerm bool) []foundSubscriber {
roots := file.Ancestors()
if !checkParentPerm {
// Include file itself
roots = file.AncestorsChain()
}
requestInfo := requestinfo.RequestInfoFromContext(ctx)
eligibleSubscribers := make([]foundSubscriber, 0)
for _, root := range roots {
subscribers := f.eventHub.GetSubscribers(ctx, root.Model.ID)
subscribers = lo.Filter(subscribers, func(subscriber eventhub.Subscriber, index int) bool {
// Exlucde self from subscribers
if requestInfo != nil && subscriber.ID() == requestInfo.ClientID {
return false
}
return true
})
eligibleSubscribers = append(eligibleSubscribers, lo.Map(subscribers, func(subscriber eventhub.Subscriber, index int) foundSubscriber {
return foundSubscriber{
Subscriber: subscriber,
root: root,
}
})...)
}
return eligibleSubscribers
}
type foundSubscriber struct {
eventhub.Subscriber
root *File
}
func (s *foundSubscriber) relativePath(file *File) string {
res := strings.TrimPrefix(file.Uri(true).Path(), s.root.Uri(true).Path())
if res == "" {
res = fs.Separator
}
if res[0] != fs.Separator[0] {
res = fs.Separator + res
}
return res
}

View File

@ -119,6 +119,7 @@ func (f *DBFS) Create(ctx context.Context, path *fs.URI, fileType types.FileType
} }
ancestor = newFile(ancestor, newFolder) ancestor = newFile(ancestor, newFolder)
f.emitFileCreated(ctx, ancestor)
} else { } else {
// valide file name // valide file name
policy, err := f.getPreferredPolicy(ctx, ancestor) policy, err := f.getPreferredPolicy(ctx, ancestor)
@ -225,6 +226,8 @@ func (f *DBFS) Rename(ctx context.Context, path *fs.URI, newName string) (fs.Fil
return nil, serializer.NewError(serializer.CodeDBError, "Failed to commit rename change", err) return nil, serializer.NewError(serializer.CodeDBError, "Failed to commit rename change", err)
} }
f.emitFileRenamed(ctx, target, newName)
return target.Replace(updated), nil return target.Replace(updated), nil
} }
@ -303,6 +306,8 @@ func (f *DBFS) SoftDelete(ctx context.Context, path ...*fs.URI) error {
return serializer.NewError(serializer.CodeDBError, "Failed to commit soft-delete change", err) return serializer.NewError(serializer.CodeDBError, "Failed to commit soft-delete change", err)
} }
f.emitFileDeleted(ctx, targets...)
return ae.Aggregate() return ae.Aggregate()
} }
@ -385,7 +390,7 @@ func (f *DBFS) Delete(ctx context.Context, path []*fs.URI, opts ...fs.Option) ([
if err := inventory.CommitWithStorageDiff(ctx, tx, f.l, f.userClient); err != nil { if err := inventory.CommitWithStorageDiff(ctx, tx, f.l, f.userClient); err != nil {
return nil, serializer.NewError(serializer.CodeDBError, "Failed to commit delete change", err) return nil, serializer.NewError(serializer.CodeDBError, "Failed to commit delete change", err)
} }
f.emitFileDeleted(ctx, targets...)
return newStaleEntities, ae.Aggregate() return newStaleEntities, ae.Aggregate()
} }
@ -603,10 +608,11 @@ func (f *DBFS) MoveOrCopy(ctx context.Context, path []*fs.URI, dst *fs.URI, isCo
} }
var ( var (
storageDiff inventory.StorageDiff copiedNewTargetsMap map[int]*ent.File
storageDiff inventory.StorageDiff
) )
if isCopy { if isCopy {
_, storageDiff, err = f.copyFiles(ctx, fileNavGroup, destination, fc) copiedNewTargetsMap, storageDiff, err = f.copyFiles(ctx, fileNavGroup, destination, fc)
} else { } else {
storageDiff, err = f.moveFiles(ctx, targets, destination, fc, dstNavigator) storageDiff, err = f.moveFiles(ctx, targets, destination, fc, dstNavigator)
} }
@ -621,6 +627,14 @@ func (f *DBFS) MoveOrCopy(ctx context.Context, path []*fs.URI, dst *fs.URI, isCo
return serializer.NewError(serializer.CodeDBError, "Failed to commit move change", err) return serializer.NewError(serializer.CodeDBError, "Failed to commit move change", err)
} }
for _, target := range targets {
if isCopy {
f.emitFileCreated(ctx, newFile(destination, copiedNewTargetsMap[target.ID()]))
} else {
f.emitFileMoved(ctx, target, destination)
}
}
// TODO: after move, dbfs cache should be cleared // TODO: after move, dbfs cache should be cleared
} }
@ -716,6 +730,8 @@ func (f *DBFS) deleteEntity(ctx context.Context, target *File, entityId int) (in
return nil, serializer.NewError(serializer.CodeDBError, "Failed to remove upload session metadata", err) return nil, serializer.NewError(serializer.CodeDBError, "Failed to remove upload session metadata", err)
} }
} }
f.emitFileModified(ctx, target)
return diff, nil return diff, nil
} }
@ -753,6 +769,7 @@ func (f *DBFS) setCurrentVersion(ctx context.Context, target *File, versionId in
return serializer.NewError(serializer.CodeDBError, "Failed to commit set current version", err) return serializer.NewError(serializer.CodeDBError, "Failed to commit set current version", err)
} }
f.emitFileModified(ctx, target)
return nil return nil
} }

View File

@ -355,6 +355,8 @@ func (f *DBFS) CompleteUpload(ctx context.Context, session *fs.UploadSession) (f
} }
} }
f.emitFileModified(ctx, filePrivate)
file, err = f.Get(ctx, session.Props.Uri, WithFileEntities(), WithNotRoot()) file, err = f.Get(ctx, session.Props.Uri, WithFileEntities(), WithNotRoot())
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to get updated file: %w", err) return nil, fmt.Errorf("failed to get updated file: %w", err)

View File

@ -148,7 +148,7 @@ func NewFileManager(dep dependency.Dep, u *ent.User) FileManager {
settings: dep.SettingProvider(), settings: dep.SettingProvider(),
fs: dbfs.NewDatabaseFS(u, dep.FileClient(), dep.ShareClient(), dep.Logger(), dep.LockSystem(), fs: dbfs.NewDatabaseFS(u, dep.FileClient(), dep.ShareClient(), dep.Logger(), dep.LockSystem(),
dep.SettingProvider(), dep.StoragePolicyClient(), dep.HashIDEncoder(), dep.UserClient(), dep.KV(), dep.NavigatorStateKV(), dep.SettingProvider(), dep.StoragePolicyClient(), dep.HashIDEncoder(), dep.UserClient(), dep.KV(), dep.NavigatorStateKV(),
dep.DirectLinkClient(), dep.EncryptorFactory(context.TODO())), dep.DirectLinkClient(), dep.EncryptorFactory(context.TODO()), dep.EventHub()),
kv: dep.KV(), kv: dep.KV(),
config: config, config: config,
auth: dep.GeneralAuth(), auth: dep.GeneralAuth(),

View File

@ -4,6 +4,7 @@ import (
"context" "context"
"errors" "errors"
"fmt" "fmt"
"runtime/debug"
"sync" "sync"
"sync/atomic" "sync/atomic"
"time" "time"
@ -284,6 +285,7 @@ func (q *queue) run(ctx context.Context, t Task) (task.Status, error) {
// handle panic issue // handle panic issue
defer func() { defer func() {
if p := recover(); p != nil { if p := recover(); p != nil {
q.logger.Error("panic in queue %q: %s", q.name, debug.Stack())
panicChan <- p panicChan <- p
} }
}() }()

View File

@ -30,6 +30,7 @@ const (
SiteVersionHeader = constants.CrHeaderPrefix + "Version" SiteVersionHeader = constants.CrHeaderPrefix + "Version"
SiteIDHeader = constants.CrHeaderPrefix + "Site-Id" SiteIDHeader = constants.CrHeaderPrefix + "Site-Id"
SlaveNodeIDHeader = constants.CrHeaderPrefix + "Node-Id" SlaveNodeIDHeader = constants.CrHeaderPrefix + "Node-Id"
ClientIDHeader = constants.CrHeaderPrefix + "Client-Id"
LocalIP = "localhost" LocalIP = "localhost"
) )

View File

@ -4,6 +4,7 @@ import (
"context" "context"
"fmt" "fmt"
"math/rand" "math/rand"
"path"
"path/filepath" "path/filepath"
"regexp" "regexp"
"strconv" "strconv"
@ -101,7 +102,7 @@ func Replace(table map[string]string, s string) string {
// ReplaceMagicVar 动态替换字符串中的魔法变量 // ReplaceMagicVar 动态替换字符串中的魔法变量
func ReplaceMagicVar(rawString string, fsSeparator string, pathAvailable bool, blobAvailable bool, func ReplaceMagicVar(rawString string, fsSeparator string, pathAvailable bool, blobAvailable bool,
timeConst time.Time, userId int, originName string, originPath string, completeBlobPath string) string { timeConst time.Time, userId int, originName string, originPath string, completeBlobPath string) string {
re := regexp.MustCompile(`\{[^{}]+\}`) re := regexp.MustCompile(`\{[^{}]+\}`)
return re.ReplaceAllStringFunc(rawString, func(match string) string { return re.ReplaceAllStringFunc(rawString, func(match string) string {
switch match { switch match {
@ -164,7 +165,7 @@ func ReplaceMagicVar(rawString string, fsSeparator string, pathAvailable bool, b
return match return match
case "{blob_path}": case "{blob_path}":
if blobAvailable { if blobAvailable {
return filepath.Dir(completeBlobPath) + fsSeparator return path.Dir(completeBlobPath) + fsSeparator
} }
return match return match
default: default:

View File

@ -426,3 +426,13 @@ func ListArchiveFiles(c *gin.Context) {
Data: resp, Data: resp,
}) })
} }
func HandleExplorerEventsPush(c *gin.Context) {
service := ParametersFromContext[*explorer.ExplorerEventService](c, explorer.ExplorerEventParamCtx{})
err := service.HandleExplorerEventsPush(c)
if err != nil {
c.JSON(200, serializer.Err(c, err))
c.Abort()
return
}
}

View File

@ -727,6 +727,13 @@ func initMasterRouter(dep dependency.Dep) *gin.Engine {
controllers.FromJSON[explorer.PatchViewService](explorer.PatchViewParameterCtx{}), controllers.FromJSON[explorer.PatchViewService](explorer.PatchViewParameterCtx{}),
controllers.PatchView, controllers.PatchView,
) )
// Server event push
file.GET("events",
middleware.LoginRequired(),
controllers.FromQuery[explorer.ExplorerEventService](explorer.ExplorerEventParamCtx{}),
controllers.HandleExplorerEventsPush,
)
} }
// 分享相关 // 分享相关

105
service/explorer/events.go Normal file
View File

@ -0,0 +1,105 @@
package explorer
import (
"time"
"github.com/cloudreve/Cloudreve/v4/application/dependency"
"github.com/cloudreve/Cloudreve/v4/inventory"
"github.com/cloudreve/Cloudreve/v4/pkg/auth/requestinfo"
"github.com/cloudreve/Cloudreve/v4/pkg/filemanager/fs"
"github.com/cloudreve/Cloudreve/v4/pkg/filemanager/manager"
"github.com/cloudreve/Cloudreve/v4/pkg/logging"
"github.com/cloudreve/Cloudreve/v4/pkg/serializer"
"github.com/gin-gonic/gin"
"github.com/gofrs/uuid"
)
type (
ExplorerEventService struct {
Uri string `form:"uri" binding:"required"`
}
ExplorerEventParamCtx struct{}
)
func (s *ExplorerEventService) HandleExplorerEventsPush(c *gin.Context) error {
dep := dependency.FromContext(c)
user := inventory.UserFromContext(c)
m := manager.NewFileManager(dep, user)
l := logging.FromContext(c)
defer m.Recycle()
uri, err := fs.NewUriFromString(s.Uri)
if err != nil {
return serializer.NewError(serializer.CodeParamErr, "Unknown uri", err)
}
// Make sure target is a valid folder that the user can listen to
parent, _, err := m.List(c, uri, &manager.ListArgs{
Page: 0,
PageSize: 1,
})
if err != nil {
return serializer.NewError(serializer.CodeParamErr, "Requested uri not available", err)
}
requestInfo := requestinfo.RequestInfoFromContext(c)
if requestInfo.ClientID == "" {
return serializer.NewError(serializer.CodeParamErr, "Client ID is required", nil)
}
// Client ID must be a valid UUID
if _, err := uuid.FromString(requestInfo.ClientID); err != nil {
return serializer.NewError(serializer.CodeParamErr, "Invalid client ID", err)
}
// Subscribe
eventHub := dep.EventHub()
rx, resumed, err := eventHub.Subscribe(c, parent.ID(), requestInfo.ClientID)
if err != nil {
return serializer.NewError(serializer.CodeInternalSetting, "Failed to subscribe to events", err)
}
// SSE Headers
c.Writer.Header().Set("Content-Type", "text/event-stream")
c.Writer.Header().Set("Cache-Control", "no-cache")
c.Writer.Header().Set("Connection", "keep-alive")
c.Writer.Header().Set("X-Accel-Buffering", "no")
keepAliveTicker := time.NewTicker(30 * time.Second)
defer keepAliveTicker.Stop()
if resumed {
c.SSEvent("resumed", nil)
c.Writer.Flush()
} else {
c.SSEvent("subscribed", nil)
c.Writer.Flush()
}
for {
select {
// TODO: close connection after access token expired
case <-c.Request.Context().Done():
// Server shutdown or request cancelled
eventHub.Unsubscribe(c, parent.ID(), requestInfo.ClientID)
l.Debug("Request context done, unsubscribed from event hub")
return nil
case <-c.Writer.CloseNotify():
eventHub.Unsubscribe(c, parent.ID(), requestInfo.ClientID)
l.Debug("Unsubscribed from event hub")
return nil
case evt, ok := <-rx:
if !ok {
// Channel closed, EventHub is shutting down
l.Debug("Event hub closed, disconnecting client")
return nil
}
c.SSEvent("event", evt)
l.Debug("Event sent: %+v", evt)
c.Writer.Flush()
case <-keepAliveTicker.C:
c.SSEvent("keep-alive", nil)
c.Writer.Flush()
}
}
}

View File

@ -30,6 +30,7 @@ type (
Metadata map[string]string `json:"metadata" binding:"max=256"` Metadata map[string]string `json:"metadata" binding:"max=256"`
EntityType string `json:"entity_type" binding:"eq=|eq=live_photo|eq=version"` EntityType string `json:"entity_type" binding:"eq=|eq=live_photo|eq=version"`
EncryptionSupported []types.Cipher `json:"encryption_supported"` EncryptionSupported []types.Cipher `json:"encryption_supported"`
Previous string `form:"previous"`
} }
) )
@ -56,9 +57,12 @@ func (service *CreateUploadSessionService) Create(c context.Context) (*UploadSes
} }
hasher := dep.HashIDEncoder() hasher := dep.HashIDEncoder()
policyId, err := hasher.Decode(service.PolicyID, hashid.PolicyID) policyId := 0
if err != nil { if service.PolicyID != "" {
return nil, serializer.NewError(serializer.CodeParamErr, "unknown policy id", err) policyId, err = hasher.Decode(service.PolicyID, hashid.PolicyID)
if err != nil {
return nil, serializer.NewError(serializer.CodeParamErr, "unknown policy id", err)
}
} }
uploadRequest := &fs.UploadRequest{ uploadRequest := &fs.UploadRequest{
@ -66,6 +70,7 @@ func (service *CreateUploadSessionService) Create(c context.Context) (*UploadSes
Uri: uri, Uri: uri,
Size: service.Size, Size: service.Size,
PreviousVersion: service.Previous,
MimeType: service.MimeType, MimeType: service.MimeType,
Metadata: service.Metadata, Metadata: service.Metadata,
EntityType: entityType, EntityType: entityType,