From 84a97c95cada3fa66b17186177c3ff2258849c10 Mon Sep 17 00:00:00 2001 From: hyrhyrh Date: Sat, 30 May 2026 00:11:34 +0000 Subject: [PATCH 01/10] feat(email-broadcast): introduce EmailBroadcast schema and migration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 新增 `email_broadcasts` 表用于持久化管理员批量公告邮件的发送记录, 包含主题、正文、收件人模式、聚合计数与状态字段,索引按 status / created_at / created_by 建立。配套生成 ent client 代码与 domain 常量/错误。 Adds a new `email_broadcasts` table to persist admin-issued bulk announcement emails (subject, body, recipients mode, aggregate counters and lifecycle status), with indexes on status, created_at and created_by. Includes the regenerated ent client and matching domain constants/errors. --- backend/ent/client.go | 177 +- backend/ent/emailbroadcast.go | 277 ++++ backend/ent/emailbroadcast/emailbroadcast.go | 193 +++ backend/ent/emailbroadcast/where.go | 900 +++++++++++ backend/ent/emailbroadcast_create.go | 1508 ++++++++++++++++++ backend/ent/emailbroadcast_delete.go | 88 + backend/ent/emailbroadcast_query.go | 564 +++++++ backend/ent/emailbroadcast_update.go | 927 +++++++++++ backend/ent/ent.go | 2 + backend/ent/hook/hook.go | 12 + backend/ent/intercept/intercept.go | 30 + backend/ent/migrate/schema.go | 46 + backend/ent/mutation.go | 1335 ++++++++++++++++ backend/ent/predicate/predicate.go | 3 + backend/ent/runtime/runtime.go | 71 + backend/ent/schema/email_broadcast.go | 102 ++ backend/ent/tx.go | 3 + backend/internal/domain/email_broadcast.go | 47 + backend/migrations/145_email_broadcasts.sql | 35 + 19 files changed, 6302 insertions(+), 18 deletions(-) create mode 100644 backend/ent/emailbroadcast.go create mode 100644 backend/ent/emailbroadcast/emailbroadcast.go create mode 100644 backend/ent/emailbroadcast/where.go create mode 100644 backend/ent/emailbroadcast_create.go create mode 100644 backend/ent/emailbroadcast_delete.go create mode 100644 backend/ent/emailbroadcast_query.go create mode 100644 backend/ent/emailbroadcast_update.go create mode 100644 backend/ent/schema/email_broadcast.go create mode 100644 backend/internal/domain/email_broadcast.go create mode 100644 backend/migrations/145_email_broadcasts.sql diff --git a/backend/ent/client.go b/backend/ent/client.go index 06b53c781a9..3d6d80a0598 100644 --- a/backend/ent/client.go +++ b/backend/ent/client.go @@ -26,6 +26,7 @@ import ( "github.com/Wei-Shaw/sub2api/ent/channelmonitordailyrollup" "github.com/Wei-Shaw/sub2api/ent/channelmonitorhistory" "github.com/Wei-Shaw/sub2api/ent/channelmonitorrequesttemplate" + "github.com/Wei-Shaw/sub2api/ent/emailbroadcast" "github.com/Wei-Shaw/sub2api/ent/errorpassthroughrule" "github.com/Wei-Shaw/sub2api/ent/group" "github.com/Wei-Shaw/sub2api/ent/idempotencyrecord" @@ -81,6 +82,8 @@ type Client struct { ChannelMonitorHistory *ChannelMonitorHistoryClient // ChannelMonitorRequestTemplate is the client for interacting with the ChannelMonitorRequestTemplate builders. ChannelMonitorRequestTemplate *ChannelMonitorRequestTemplateClient + // EmailBroadcast is the client for interacting with the EmailBroadcast builders. + EmailBroadcast *EmailBroadcastClient // ErrorPassthroughRule is the client for interacting with the ErrorPassthroughRule builders. ErrorPassthroughRule *ErrorPassthroughRuleClient // Group is the client for interacting with the Group builders. @@ -151,6 +154,7 @@ func (c *Client) init() { c.ChannelMonitorDailyRollup = NewChannelMonitorDailyRollupClient(c.config) c.ChannelMonitorHistory = NewChannelMonitorHistoryClient(c.config) c.ChannelMonitorRequestTemplate = NewChannelMonitorRequestTemplateClient(c.config) + c.EmailBroadcast = NewEmailBroadcastClient(c.config) c.ErrorPassthroughRule = NewErrorPassthroughRuleClient(c.config) c.Group = NewGroupClient(c.config) c.IdempotencyRecord = NewIdempotencyRecordClient(c.config) @@ -278,6 +282,7 @@ func (c *Client) Tx(ctx context.Context) (*Tx, error) { ChannelMonitorDailyRollup: NewChannelMonitorDailyRollupClient(cfg), ChannelMonitorHistory: NewChannelMonitorHistoryClient(cfg), ChannelMonitorRequestTemplate: NewChannelMonitorRequestTemplateClient(cfg), + EmailBroadcast: NewEmailBroadcastClient(cfg), ErrorPassthroughRule: NewErrorPassthroughRuleClient(cfg), Group: NewGroupClient(cfg), IdempotencyRecord: NewIdempotencyRecordClient(cfg), @@ -332,6 +337,7 @@ func (c *Client) BeginTx(ctx context.Context, opts *sql.TxOptions) (*Tx, error) ChannelMonitorDailyRollup: NewChannelMonitorDailyRollupClient(cfg), ChannelMonitorHistory: NewChannelMonitorHistoryClient(cfg), ChannelMonitorRequestTemplate: NewChannelMonitorRequestTemplateClient(cfg), + EmailBroadcast: NewEmailBroadcastClient(cfg), ErrorPassthroughRule: NewErrorPassthroughRuleClient(cfg), Group: NewGroupClient(cfg), IdempotencyRecord: NewIdempotencyRecordClient(cfg), @@ -388,8 +394,8 @@ func (c *Client) Use(hooks ...Hook) { c.APIKey, c.Account, c.AccountGroup, c.Announcement, c.AnnouncementRead, c.AuthIdentity, c.AuthIdentityChannel, c.ChannelMonitor, c.ChannelMonitorDailyRollup, c.ChannelMonitorHistory, - c.ChannelMonitorRequestTemplate, c.ErrorPassthroughRule, c.Group, - c.IdempotencyRecord, c.IdentityAdoptionDecision, c.PaymentAuditLog, + c.ChannelMonitorRequestTemplate, c.EmailBroadcast, c.ErrorPassthroughRule, + c.Group, c.IdempotencyRecord, c.IdentityAdoptionDecision, c.PaymentAuditLog, c.PaymentOrder, c.PaymentProviderInstance, c.PendingAuthSession, c.PromoCode, c.PromoCodeUsage, c.Proxy, c.RedeemCode, c.SecuritySecret, c.Setting, c.SubscriptionPlan, c.TLSFingerprintProfile, c.UsageCleanupTask, c.UsageLog, @@ -407,8 +413,8 @@ func (c *Client) Intercept(interceptors ...Interceptor) { c.APIKey, c.Account, c.AccountGroup, c.Announcement, c.AnnouncementRead, c.AuthIdentity, c.AuthIdentityChannel, c.ChannelMonitor, c.ChannelMonitorDailyRollup, c.ChannelMonitorHistory, - c.ChannelMonitorRequestTemplate, c.ErrorPassthroughRule, c.Group, - c.IdempotencyRecord, c.IdentityAdoptionDecision, c.PaymentAuditLog, + c.ChannelMonitorRequestTemplate, c.EmailBroadcast, c.ErrorPassthroughRule, + c.Group, c.IdempotencyRecord, c.IdentityAdoptionDecision, c.PaymentAuditLog, c.PaymentOrder, c.PaymentProviderInstance, c.PendingAuthSession, c.PromoCode, c.PromoCodeUsage, c.Proxy, c.RedeemCode, c.SecuritySecret, c.Setting, c.SubscriptionPlan, c.TLSFingerprintProfile, c.UsageCleanupTask, c.UsageLog, @@ -444,6 +450,8 @@ func (c *Client) Mutate(ctx context.Context, m Mutation) (Value, error) { return c.ChannelMonitorHistory.mutate(ctx, m) case *ChannelMonitorRequestTemplateMutation: return c.ChannelMonitorRequestTemplate.mutate(ctx, m) + case *EmailBroadcastMutation: + return c.EmailBroadcast.mutate(ctx, m) case *ErrorPassthroughRuleMutation: return c.ErrorPassthroughRule.mutate(ctx, m) case *GroupMutation: @@ -2267,6 +2275,139 @@ func (c *ChannelMonitorRequestTemplateClient) mutate(ctx context.Context, m *Cha } } +// EmailBroadcastClient is a client for the EmailBroadcast schema. +type EmailBroadcastClient struct { + config +} + +// NewEmailBroadcastClient returns a client for the EmailBroadcast from the given config. +func NewEmailBroadcastClient(c config) *EmailBroadcastClient { + return &EmailBroadcastClient{config: c} +} + +// Use adds a list of mutation hooks to the hooks stack. +// A call to `Use(f, g, h)` equals to `emailbroadcast.Hooks(f(g(h())))`. +func (c *EmailBroadcastClient) Use(hooks ...Hook) { + c.hooks.EmailBroadcast = append(c.hooks.EmailBroadcast, hooks...) +} + +// Intercept adds a list of query interceptors to the interceptors stack. +// A call to `Intercept(f, g, h)` equals to `emailbroadcast.Intercept(f(g(h())))`. +func (c *EmailBroadcastClient) Intercept(interceptors ...Interceptor) { + c.inters.EmailBroadcast = append(c.inters.EmailBroadcast, interceptors...) +} + +// Create returns a builder for creating a EmailBroadcast entity. +func (c *EmailBroadcastClient) Create() *EmailBroadcastCreate { + mutation := newEmailBroadcastMutation(c.config, OpCreate) + return &EmailBroadcastCreate{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// CreateBulk returns a builder for creating a bulk of EmailBroadcast entities. +func (c *EmailBroadcastClient) CreateBulk(builders ...*EmailBroadcastCreate) *EmailBroadcastCreateBulk { + return &EmailBroadcastCreateBulk{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 *EmailBroadcastClient) MapCreateBulk(slice any, setFunc func(*EmailBroadcastCreate, int)) *EmailBroadcastCreateBulk { + rv := reflect.ValueOf(slice) + if rv.Kind() != reflect.Slice { + return &EmailBroadcastCreateBulk{err: fmt.Errorf("calling to EmailBroadcastClient.MapCreateBulk with wrong type %T, need slice", slice)} + } + builders := make([]*EmailBroadcastCreate, rv.Len()) + for i := 0; i < rv.Len(); i++ { + builders[i] = c.Create() + setFunc(builders[i], i) + } + return &EmailBroadcastCreateBulk{config: c.config, builders: builders} +} + +// Update returns an update builder for EmailBroadcast. +func (c *EmailBroadcastClient) Update() *EmailBroadcastUpdate { + mutation := newEmailBroadcastMutation(c.config, OpUpdate) + return &EmailBroadcastUpdate{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// UpdateOne returns an update builder for the given entity. +func (c *EmailBroadcastClient) UpdateOne(_m *EmailBroadcast) *EmailBroadcastUpdateOne { + mutation := newEmailBroadcastMutation(c.config, OpUpdateOne, withEmailBroadcast(_m)) + return &EmailBroadcastUpdateOne{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// UpdateOneID returns an update builder for the given id. +func (c *EmailBroadcastClient) UpdateOneID(id int64) *EmailBroadcastUpdateOne { + mutation := newEmailBroadcastMutation(c.config, OpUpdateOne, withEmailBroadcastID(id)) + return &EmailBroadcastUpdateOne{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// Delete returns a delete builder for EmailBroadcast. +func (c *EmailBroadcastClient) Delete() *EmailBroadcastDelete { + mutation := newEmailBroadcastMutation(c.config, OpDelete) + return &EmailBroadcastDelete{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// DeleteOne returns a builder for deleting the given entity. +func (c *EmailBroadcastClient) DeleteOne(_m *EmailBroadcast) *EmailBroadcastDeleteOne { + return c.DeleteOneID(_m.ID) +} + +// DeleteOneID returns a builder for deleting the given entity by its id. +func (c *EmailBroadcastClient) DeleteOneID(id int64) *EmailBroadcastDeleteOne { + builder := c.Delete().Where(emailbroadcast.ID(id)) + builder.mutation.id = &id + builder.mutation.op = OpDeleteOne + return &EmailBroadcastDeleteOne{builder} +} + +// Query returns a query builder for EmailBroadcast. +func (c *EmailBroadcastClient) Query() *EmailBroadcastQuery { + return &EmailBroadcastQuery{ + config: c.config, + ctx: &QueryContext{Type: TypeEmailBroadcast}, + inters: c.Interceptors(), + } +} + +// Get returns a EmailBroadcast entity by its id. +func (c *EmailBroadcastClient) Get(ctx context.Context, id int64) (*EmailBroadcast, error) { + return c.Query().Where(emailbroadcast.ID(id)).Only(ctx) +} + +// GetX is like Get, but panics if an error occurs. +func (c *EmailBroadcastClient) GetX(ctx context.Context, id int64) *EmailBroadcast { + obj, err := c.Get(ctx, id) + if err != nil { + panic(err) + } + return obj +} + +// Hooks returns the client hooks. +func (c *EmailBroadcastClient) Hooks() []Hook { + return c.hooks.EmailBroadcast +} + +// Interceptors returns the client interceptors. +func (c *EmailBroadcastClient) Interceptors() []Interceptor { + return c.inters.EmailBroadcast +} + +func (c *EmailBroadcastClient) mutate(ctx context.Context, m *EmailBroadcastMutation) (Value, error) { + switch m.Op() { + case OpCreate: + return (&EmailBroadcastCreate{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx) + case OpUpdate: + return (&EmailBroadcastUpdate{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx) + case OpUpdateOne: + return (&EmailBroadcastUpdateOne{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx) + case OpDelete, OpDeleteOne: + return (&EmailBroadcastDelete{config: c.config, hooks: c.Hooks(), mutation: m}).Exec(ctx) + default: + return nil, fmt.Errorf("ent: unknown EmailBroadcast mutation op: %q", m.Op()) + } +} + // ErrorPassthroughRuleClient is a client for the ErrorPassthroughRule schema. type ErrorPassthroughRuleClient struct { config @@ -6195,24 +6336,24 @@ type ( hooks struct { APIKey, Account, AccountGroup, Announcement, AnnouncementRead, AuthIdentity, AuthIdentityChannel, ChannelMonitor, ChannelMonitorDailyRollup, - ChannelMonitorHistory, ChannelMonitorRequestTemplate, ErrorPassthroughRule, - Group, IdempotencyRecord, IdentityAdoptionDecision, PaymentAuditLog, - PaymentOrder, PaymentProviderInstance, PendingAuthSession, PromoCode, - PromoCodeUsage, Proxy, RedeemCode, SecuritySecret, Setting, SubscriptionPlan, - TLSFingerprintProfile, UsageCleanupTask, UsageLog, User, UserAllowedGroup, - UserAttributeDefinition, UserAttributeValue, UserPlatformQuota, - UserSubscription []ent.Hook + ChannelMonitorHistory, ChannelMonitorRequestTemplate, EmailBroadcast, + ErrorPassthroughRule, Group, IdempotencyRecord, IdentityAdoptionDecision, + PaymentAuditLog, PaymentOrder, PaymentProviderInstance, PendingAuthSession, + PromoCode, PromoCodeUsage, Proxy, RedeemCode, SecuritySecret, Setting, + SubscriptionPlan, TLSFingerprintProfile, UsageCleanupTask, UsageLog, User, + UserAllowedGroup, UserAttributeDefinition, UserAttributeValue, + UserPlatformQuota, UserSubscription []ent.Hook } inters struct { APIKey, Account, AccountGroup, Announcement, AnnouncementRead, AuthIdentity, AuthIdentityChannel, ChannelMonitor, ChannelMonitorDailyRollup, - ChannelMonitorHistory, ChannelMonitorRequestTemplate, ErrorPassthroughRule, - Group, IdempotencyRecord, IdentityAdoptionDecision, PaymentAuditLog, - PaymentOrder, PaymentProviderInstance, PendingAuthSession, PromoCode, - PromoCodeUsage, Proxy, RedeemCode, SecuritySecret, Setting, SubscriptionPlan, - TLSFingerprintProfile, UsageCleanupTask, UsageLog, User, UserAllowedGroup, - UserAttributeDefinition, UserAttributeValue, UserPlatformQuota, - UserSubscription []ent.Interceptor + ChannelMonitorHistory, ChannelMonitorRequestTemplate, EmailBroadcast, + ErrorPassthroughRule, Group, IdempotencyRecord, IdentityAdoptionDecision, + PaymentAuditLog, PaymentOrder, PaymentProviderInstance, PendingAuthSession, + PromoCode, PromoCodeUsage, Proxy, RedeemCode, SecuritySecret, Setting, + SubscriptionPlan, TLSFingerprintProfile, UsageCleanupTask, UsageLog, User, + UserAllowedGroup, UserAttributeDefinition, UserAttributeValue, + UserPlatformQuota, UserSubscription []ent.Interceptor } ) diff --git a/backend/ent/emailbroadcast.go b/backend/ent/emailbroadcast.go new file mode 100644 index 00000000000..df0235d4eb0 --- /dev/null +++ b/backend/ent/emailbroadcast.go @@ -0,0 +1,277 @@ +// Code generated by ent, DO NOT EDIT. + +package ent + +import ( + "encoding/json" + "fmt" + "strings" + "time" + + "entgo.io/ent" + "entgo.io/ent/dialect/sql" + "github.com/Wei-Shaw/sub2api/ent/emailbroadcast" +) + +// EmailBroadcast is the model entity for the EmailBroadcast schema. +type EmailBroadcast struct { + config `json:"-"` + // ID of the ent. + ID int64 `json:"id,omitempty"` + // 邮件主题 + Subject string `json:"subject,omitempty"` + // 邮件正文 (HTML 或纯文本) + Body string `json:"body,omitempty"` + // 正文格式: html, text + BodyFormat string `json:"body_format,omitempty"` + // 收件人模式: all, selected + RecipientsMode string `json:"recipients_mode,omitempty"` + // 收件人用户 ID 列表 (selected 模式时使用) + RecipientUserIds []int64 `json:"recipient_user_ids,omitempty"` + // 状态: pending, sending, completed, failed + Status string `json:"status,omitempty"` + // 收件人总数 + TotalCount int `json:"total_count,omitempty"` + // 发送成功数 + SuccessCount int `json:"success_count,omitempty"` + // 发送失败数 + FailedCount int `json:"failed_count,omitempty"` + // 整批失败原因 (status=failed 时填充) + ErrorMessage *string `json:"error_message,omitempty"` + // 创建管理员用户 ID + CreatedBy *int64 `json:"created_by,omitempty"` + // 开始发送时间 + StartedAt *time.Time `json:"started_at,omitempty"` + // 发送结束时间 + FinishedAt *time.Time `json:"finished_at,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"` + selectValues sql.SelectValues +} + +// scanValues returns the types for scanning values from sql.Rows. +func (*EmailBroadcast) scanValues(columns []string) ([]any, error) { + values := make([]any, len(columns)) + for i := range columns { + switch columns[i] { + case emailbroadcast.FieldRecipientUserIds: + values[i] = new([]byte) + case emailbroadcast.FieldID, emailbroadcast.FieldTotalCount, emailbroadcast.FieldSuccessCount, emailbroadcast.FieldFailedCount, emailbroadcast.FieldCreatedBy: + values[i] = new(sql.NullInt64) + case emailbroadcast.FieldSubject, emailbroadcast.FieldBody, emailbroadcast.FieldBodyFormat, emailbroadcast.FieldRecipientsMode, emailbroadcast.FieldStatus, emailbroadcast.FieldErrorMessage: + values[i] = new(sql.NullString) + case emailbroadcast.FieldStartedAt, emailbroadcast.FieldFinishedAt, emailbroadcast.FieldCreatedAt, emailbroadcast.FieldUpdatedAt: + values[i] = new(sql.NullTime) + default: + values[i] = new(sql.UnknownType) + } + } + return values, nil +} + +// assignValues assigns the values that were returned from sql.Rows (after scanning) +// to the EmailBroadcast fields. +func (_m *EmailBroadcast) 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 emailbroadcast.FieldID: + value, ok := values[i].(*sql.NullInt64) + if !ok { + return fmt.Errorf("unexpected type %T for field id", value) + } + _m.ID = int64(value.Int64) + case emailbroadcast.FieldSubject: + if value, ok := values[i].(*sql.NullString); !ok { + return fmt.Errorf("unexpected type %T for field subject", values[i]) + } else if value.Valid { + _m.Subject = value.String + } + case emailbroadcast.FieldBody: + if value, ok := values[i].(*sql.NullString); !ok { + return fmt.Errorf("unexpected type %T for field body", values[i]) + } else if value.Valid { + _m.Body = value.String + } + case emailbroadcast.FieldBodyFormat: + if value, ok := values[i].(*sql.NullString); !ok { + return fmt.Errorf("unexpected type %T for field body_format", values[i]) + } else if value.Valid { + _m.BodyFormat = value.String + } + case emailbroadcast.FieldRecipientsMode: + if value, ok := values[i].(*sql.NullString); !ok { + return fmt.Errorf("unexpected type %T for field recipients_mode", values[i]) + } else if value.Valid { + _m.RecipientsMode = value.String + } + case emailbroadcast.FieldRecipientUserIds: + if value, ok := values[i].(*[]byte); !ok { + return fmt.Errorf("unexpected type %T for field recipient_user_ids", values[i]) + } else if value != nil && len(*value) > 0 { + if err := json.Unmarshal(*value, &_m.RecipientUserIds); err != nil { + return fmt.Errorf("unmarshal field recipient_user_ids: %w", err) + } + } + case emailbroadcast.FieldStatus: + if value, ok := values[i].(*sql.NullString); !ok { + return fmt.Errorf("unexpected type %T for field status", values[i]) + } else if value.Valid { + _m.Status = value.String + } + case emailbroadcast.FieldTotalCount: + if value, ok := values[i].(*sql.NullInt64); !ok { + return fmt.Errorf("unexpected type %T for field total_count", values[i]) + } else if value.Valid { + _m.TotalCount = int(value.Int64) + } + case emailbroadcast.FieldSuccessCount: + if value, ok := values[i].(*sql.NullInt64); !ok { + return fmt.Errorf("unexpected type %T for field success_count", values[i]) + } else if value.Valid { + _m.SuccessCount = int(value.Int64) + } + case emailbroadcast.FieldFailedCount: + if value, ok := values[i].(*sql.NullInt64); !ok { + return fmt.Errorf("unexpected type %T for field failed_count", values[i]) + } else if value.Valid { + _m.FailedCount = int(value.Int64) + } + case emailbroadcast.FieldErrorMessage: + if value, ok := values[i].(*sql.NullString); !ok { + return fmt.Errorf("unexpected type %T for field error_message", values[i]) + } else if value.Valid { + _m.ErrorMessage = new(string) + *_m.ErrorMessage = value.String + } + case emailbroadcast.FieldCreatedBy: + if value, ok := values[i].(*sql.NullInt64); !ok { + return fmt.Errorf("unexpected type %T for field created_by", values[i]) + } else if value.Valid { + _m.CreatedBy = new(int64) + *_m.CreatedBy = value.Int64 + } + case emailbroadcast.FieldStartedAt: + if value, ok := values[i].(*sql.NullTime); !ok { + return fmt.Errorf("unexpected type %T for field started_at", values[i]) + } else if value.Valid { + _m.StartedAt = new(time.Time) + *_m.StartedAt = value.Time + } + case emailbroadcast.FieldFinishedAt: + if value, ok := values[i].(*sql.NullTime); !ok { + return fmt.Errorf("unexpected type %T for field finished_at", values[i]) + } else if value.Valid { + _m.FinishedAt = new(time.Time) + *_m.FinishedAt = value.Time + } + case emailbroadcast.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 { + _m.CreatedAt = value.Time + } + case emailbroadcast.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 { + _m.UpdatedAt = value.Time + } + default: + _m.selectValues.Set(columns[i], values[i]) + } + } + return nil +} + +// Value returns the ent.Value that was dynamically selected and assigned to the EmailBroadcast. +// This includes values selected through modifiers, order, etc. +func (_m *EmailBroadcast) Value(name string) (ent.Value, error) { + return _m.selectValues.Get(name) +} + +// Update returns a builder for updating this EmailBroadcast. +// Note that you need to call EmailBroadcast.Unwrap() before calling this method if this EmailBroadcast +// was returned from a transaction, and the transaction was committed or rolled back. +func (_m *EmailBroadcast) Update() *EmailBroadcastUpdateOne { + return NewEmailBroadcastClient(_m.config).UpdateOne(_m) +} + +// Unwrap unwraps the EmailBroadcast 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 (_m *EmailBroadcast) Unwrap() *EmailBroadcast { + _tx, ok := _m.config.driver.(*txDriver) + if !ok { + panic("ent: EmailBroadcast is not a transactional entity") + } + _m.config.driver = _tx.drv + return _m +} + +// String implements the fmt.Stringer. +func (_m *EmailBroadcast) String() string { + var builder strings.Builder + builder.WriteString("EmailBroadcast(") + builder.WriteString(fmt.Sprintf("id=%v, ", _m.ID)) + builder.WriteString("subject=") + builder.WriteString(_m.Subject) + builder.WriteString(", ") + builder.WriteString("body=") + builder.WriteString(_m.Body) + builder.WriteString(", ") + builder.WriteString("body_format=") + builder.WriteString(_m.BodyFormat) + builder.WriteString(", ") + builder.WriteString("recipients_mode=") + builder.WriteString(_m.RecipientsMode) + builder.WriteString(", ") + builder.WriteString("recipient_user_ids=") + builder.WriteString(fmt.Sprintf("%v", _m.RecipientUserIds)) + builder.WriteString(", ") + builder.WriteString("status=") + builder.WriteString(_m.Status) + builder.WriteString(", ") + builder.WriteString("total_count=") + builder.WriteString(fmt.Sprintf("%v", _m.TotalCount)) + builder.WriteString(", ") + builder.WriteString("success_count=") + builder.WriteString(fmt.Sprintf("%v", _m.SuccessCount)) + builder.WriteString(", ") + builder.WriteString("failed_count=") + builder.WriteString(fmt.Sprintf("%v", _m.FailedCount)) + builder.WriteString(", ") + if v := _m.ErrorMessage; v != nil { + builder.WriteString("error_message=") + builder.WriteString(*v) + } + builder.WriteString(", ") + if v := _m.CreatedBy; v != nil { + builder.WriteString("created_by=") + builder.WriteString(fmt.Sprintf("%v", *v)) + } + builder.WriteString(", ") + if v := _m.StartedAt; v != nil { + builder.WriteString("started_at=") + builder.WriteString(v.Format(time.ANSIC)) + } + builder.WriteString(", ") + if v := _m.FinishedAt; v != nil { + builder.WriteString("finished_at=") + builder.WriteString(v.Format(time.ANSIC)) + } + builder.WriteString(", ") + builder.WriteString("created_at=") + builder.WriteString(_m.CreatedAt.Format(time.ANSIC)) + builder.WriteString(", ") + builder.WriteString("updated_at=") + builder.WriteString(_m.UpdatedAt.Format(time.ANSIC)) + builder.WriteByte(')') + return builder.String() +} + +// EmailBroadcasts is a parsable slice of EmailBroadcast. +type EmailBroadcasts []*EmailBroadcast diff --git a/backend/ent/emailbroadcast/emailbroadcast.go b/backend/ent/emailbroadcast/emailbroadcast.go new file mode 100644 index 00000000000..38ce4f05a16 --- /dev/null +++ b/backend/ent/emailbroadcast/emailbroadcast.go @@ -0,0 +1,193 @@ +// Code generated by ent, DO NOT EDIT. + +package emailbroadcast + +import ( + "time" + + "entgo.io/ent/dialect/sql" +) + +const ( + // Label holds the string label denoting the emailbroadcast type in the database. + Label = "email_broadcast" + // FieldID holds the string denoting the id field in the database. + FieldID = "id" + // FieldSubject holds the string denoting the subject field in the database. + FieldSubject = "subject" + // FieldBody holds the string denoting the body field in the database. + FieldBody = "body" + // FieldBodyFormat holds the string denoting the body_format field in the database. + FieldBodyFormat = "body_format" + // FieldRecipientsMode holds the string denoting the recipients_mode field in the database. + FieldRecipientsMode = "recipients_mode" + // FieldRecipientUserIds holds the string denoting the recipient_user_ids field in the database. + FieldRecipientUserIds = "recipient_user_ids" + // FieldStatus holds the string denoting the status field in the database. + FieldStatus = "status" + // FieldTotalCount holds the string denoting the total_count field in the database. + FieldTotalCount = "total_count" + // FieldSuccessCount holds the string denoting the success_count field in the database. + FieldSuccessCount = "success_count" + // FieldFailedCount holds the string denoting the failed_count field in the database. + FieldFailedCount = "failed_count" + // FieldErrorMessage holds the string denoting the error_message field in the database. + FieldErrorMessage = "error_message" + // FieldCreatedBy holds the string denoting the created_by field in the database. + FieldCreatedBy = "created_by" + // FieldStartedAt holds the string denoting the started_at field in the database. + FieldStartedAt = "started_at" + // FieldFinishedAt holds the string denoting the finished_at field in the database. + FieldFinishedAt = "finished_at" + // 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" + // Table holds the table name of the emailbroadcast in the database. + Table = "email_broadcasts" +) + +// Columns holds all SQL columns for emailbroadcast fields. +var Columns = []string{ + FieldID, + FieldSubject, + FieldBody, + FieldBodyFormat, + FieldRecipientsMode, + FieldRecipientUserIds, + FieldStatus, + FieldTotalCount, + FieldSuccessCount, + FieldFailedCount, + FieldErrorMessage, + FieldCreatedBy, + FieldStartedAt, + FieldFinishedAt, + FieldCreatedAt, + FieldUpdatedAt, +} + +// 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 +} + +var ( + // SubjectValidator is a validator for the "subject" field. It is called by the builders before save. + SubjectValidator func(string) error + // BodyValidator is a validator for the "body" field. It is called by the builders before save. + BodyValidator func(string) error + // DefaultBodyFormat holds the default value on creation for the "body_format" field. + DefaultBodyFormat string + // BodyFormatValidator is a validator for the "body_format" field. It is called by the builders before save. + BodyFormatValidator func(string) error + // DefaultRecipientsMode holds the default value on creation for the "recipients_mode" field. + DefaultRecipientsMode string + // RecipientsModeValidator is a validator for the "recipients_mode" field. It is called by the builders before save. + RecipientsModeValidator func(string) error + // DefaultStatus holds the default value on creation for the "status" field. + DefaultStatus string + // StatusValidator is a validator for the "status" field. It is called by the builders before save. + StatusValidator func(string) error + // DefaultTotalCount holds the default value on creation for the "total_count" field. + DefaultTotalCount int + // TotalCountValidator is a validator for the "total_count" field. It is called by the builders before save. + TotalCountValidator func(int) error + // DefaultSuccessCount holds the default value on creation for the "success_count" field. + DefaultSuccessCount int + // SuccessCountValidator is a validator for the "success_count" field. It is called by the builders before save. + SuccessCountValidator func(int) error + // DefaultFailedCount holds the default value on creation for the "failed_count" field. + DefaultFailedCount int + // FailedCountValidator is a validator for the "failed_count" field. It is called by the builders before save. + FailedCountValidator func(int) error + // 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 EmailBroadcast 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() +} + +// BySubject orders the results by the subject field. +func BySubject(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldSubject, opts...).ToFunc() +} + +// ByBody orders the results by the body field. +func ByBody(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldBody, opts...).ToFunc() +} + +// ByBodyFormat orders the results by the body_format field. +func ByBodyFormat(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldBodyFormat, opts...).ToFunc() +} + +// ByRecipientsMode orders the results by the recipients_mode field. +func ByRecipientsMode(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldRecipientsMode, opts...).ToFunc() +} + +// ByStatus orders the results by the status field. +func ByStatus(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldStatus, opts...).ToFunc() +} + +// ByTotalCount orders the results by the total_count field. +func ByTotalCount(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldTotalCount, opts...).ToFunc() +} + +// BySuccessCount orders the results by the success_count field. +func BySuccessCount(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldSuccessCount, opts...).ToFunc() +} + +// ByFailedCount orders the results by the failed_count field. +func ByFailedCount(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldFailedCount, opts...).ToFunc() +} + +// ByErrorMessage orders the results by the error_message field. +func ByErrorMessage(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldErrorMessage, opts...).ToFunc() +} + +// ByCreatedBy orders the results by the created_by field. +func ByCreatedBy(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldCreatedBy, opts...).ToFunc() +} + +// ByStartedAt orders the results by the started_at field. +func ByStartedAt(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldStartedAt, opts...).ToFunc() +} + +// ByFinishedAt orders the results by the finished_at field. +func ByFinishedAt(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldFinishedAt, 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() +} diff --git a/backend/ent/emailbroadcast/where.go b/backend/ent/emailbroadcast/where.go new file mode 100644 index 00000000000..56ffa1a0bf7 --- /dev/null +++ b/backend/ent/emailbroadcast/where.go @@ -0,0 +1,900 @@ +// Code generated by ent, DO NOT EDIT. + +package emailbroadcast + +import ( + "time" + + "entgo.io/ent/dialect/sql" + "github.com/Wei-Shaw/sub2api/ent/predicate" +) + +// ID filters vertices based on their ID field. +func ID(id int64) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldEQ(FieldID, id)) +} + +// IDEQ applies the EQ predicate on the ID field. +func IDEQ(id int64) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldEQ(FieldID, id)) +} + +// IDNEQ applies the NEQ predicate on the ID field. +func IDNEQ(id int64) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldNEQ(FieldID, id)) +} + +// IDIn applies the In predicate on the ID field. +func IDIn(ids ...int64) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldIn(FieldID, ids...)) +} + +// IDNotIn applies the NotIn predicate on the ID field. +func IDNotIn(ids ...int64) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldNotIn(FieldID, ids...)) +} + +// IDGT applies the GT predicate on the ID field. +func IDGT(id int64) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldGT(FieldID, id)) +} + +// IDGTE applies the GTE predicate on the ID field. +func IDGTE(id int64) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldGTE(FieldID, id)) +} + +// IDLT applies the LT predicate on the ID field. +func IDLT(id int64) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldLT(FieldID, id)) +} + +// IDLTE applies the LTE predicate on the ID field. +func IDLTE(id int64) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldLTE(FieldID, id)) +} + +// Subject applies equality check predicate on the "subject" field. It's identical to SubjectEQ. +func Subject(v string) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldEQ(FieldSubject, v)) +} + +// Body applies equality check predicate on the "body" field. It's identical to BodyEQ. +func Body(v string) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldEQ(FieldBody, v)) +} + +// BodyFormat applies equality check predicate on the "body_format" field. It's identical to BodyFormatEQ. +func BodyFormat(v string) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldEQ(FieldBodyFormat, v)) +} + +// RecipientsMode applies equality check predicate on the "recipients_mode" field. It's identical to RecipientsModeEQ. +func RecipientsMode(v string) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldEQ(FieldRecipientsMode, v)) +} + +// Status applies equality check predicate on the "status" field. It's identical to StatusEQ. +func Status(v string) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldEQ(FieldStatus, v)) +} + +// TotalCount applies equality check predicate on the "total_count" field. It's identical to TotalCountEQ. +func TotalCount(v int) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldEQ(FieldTotalCount, v)) +} + +// SuccessCount applies equality check predicate on the "success_count" field. It's identical to SuccessCountEQ. +func SuccessCount(v int) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldEQ(FieldSuccessCount, v)) +} + +// FailedCount applies equality check predicate on the "failed_count" field. It's identical to FailedCountEQ. +func FailedCount(v int) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldEQ(FieldFailedCount, v)) +} + +// ErrorMessage applies equality check predicate on the "error_message" field. It's identical to ErrorMessageEQ. +func ErrorMessage(v string) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldEQ(FieldErrorMessage, v)) +} + +// CreatedBy applies equality check predicate on the "created_by" field. It's identical to CreatedByEQ. +func CreatedBy(v int64) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldEQ(FieldCreatedBy, v)) +} + +// StartedAt applies equality check predicate on the "started_at" field. It's identical to StartedAtEQ. +func StartedAt(v time.Time) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldEQ(FieldStartedAt, v)) +} + +// FinishedAt applies equality check predicate on the "finished_at" field. It's identical to FinishedAtEQ. +func FinishedAt(v time.Time) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldEQ(FieldFinishedAt, v)) +} + +// CreatedAt applies equality check predicate on the "created_at" field. It's identical to CreatedAtEQ. +func CreatedAt(v time.Time) predicate.EmailBroadcast { + return predicate.EmailBroadcast(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.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldEQ(FieldUpdatedAt, v)) +} + +// SubjectEQ applies the EQ predicate on the "subject" field. +func SubjectEQ(v string) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldEQ(FieldSubject, v)) +} + +// SubjectNEQ applies the NEQ predicate on the "subject" field. +func SubjectNEQ(v string) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldNEQ(FieldSubject, v)) +} + +// SubjectIn applies the In predicate on the "subject" field. +func SubjectIn(vs ...string) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldIn(FieldSubject, vs...)) +} + +// SubjectNotIn applies the NotIn predicate on the "subject" field. +func SubjectNotIn(vs ...string) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldNotIn(FieldSubject, vs...)) +} + +// SubjectGT applies the GT predicate on the "subject" field. +func SubjectGT(v string) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldGT(FieldSubject, v)) +} + +// SubjectGTE applies the GTE predicate on the "subject" field. +func SubjectGTE(v string) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldGTE(FieldSubject, v)) +} + +// SubjectLT applies the LT predicate on the "subject" field. +func SubjectLT(v string) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldLT(FieldSubject, v)) +} + +// SubjectLTE applies the LTE predicate on the "subject" field. +func SubjectLTE(v string) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldLTE(FieldSubject, v)) +} + +// SubjectContains applies the Contains predicate on the "subject" field. +func SubjectContains(v string) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldContains(FieldSubject, v)) +} + +// SubjectHasPrefix applies the HasPrefix predicate on the "subject" field. +func SubjectHasPrefix(v string) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldHasPrefix(FieldSubject, v)) +} + +// SubjectHasSuffix applies the HasSuffix predicate on the "subject" field. +func SubjectHasSuffix(v string) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldHasSuffix(FieldSubject, v)) +} + +// SubjectEqualFold applies the EqualFold predicate on the "subject" field. +func SubjectEqualFold(v string) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldEqualFold(FieldSubject, v)) +} + +// SubjectContainsFold applies the ContainsFold predicate on the "subject" field. +func SubjectContainsFold(v string) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldContainsFold(FieldSubject, v)) +} + +// BodyEQ applies the EQ predicate on the "body" field. +func BodyEQ(v string) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldEQ(FieldBody, v)) +} + +// BodyNEQ applies the NEQ predicate on the "body" field. +func BodyNEQ(v string) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldNEQ(FieldBody, v)) +} + +// BodyIn applies the In predicate on the "body" field. +func BodyIn(vs ...string) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldIn(FieldBody, vs...)) +} + +// BodyNotIn applies the NotIn predicate on the "body" field. +func BodyNotIn(vs ...string) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldNotIn(FieldBody, vs...)) +} + +// BodyGT applies the GT predicate on the "body" field. +func BodyGT(v string) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldGT(FieldBody, v)) +} + +// BodyGTE applies the GTE predicate on the "body" field. +func BodyGTE(v string) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldGTE(FieldBody, v)) +} + +// BodyLT applies the LT predicate on the "body" field. +func BodyLT(v string) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldLT(FieldBody, v)) +} + +// BodyLTE applies the LTE predicate on the "body" field. +func BodyLTE(v string) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldLTE(FieldBody, v)) +} + +// BodyContains applies the Contains predicate on the "body" field. +func BodyContains(v string) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldContains(FieldBody, v)) +} + +// BodyHasPrefix applies the HasPrefix predicate on the "body" field. +func BodyHasPrefix(v string) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldHasPrefix(FieldBody, v)) +} + +// BodyHasSuffix applies the HasSuffix predicate on the "body" field. +func BodyHasSuffix(v string) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldHasSuffix(FieldBody, v)) +} + +// BodyEqualFold applies the EqualFold predicate on the "body" field. +func BodyEqualFold(v string) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldEqualFold(FieldBody, v)) +} + +// BodyContainsFold applies the ContainsFold predicate on the "body" field. +func BodyContainsFold(v string) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldContainsFold(FieldBody, v)) +} + +// BodyFormatEQ applies the EQ predicate on the "body_format" field. +func BodyFormatEQ(v string) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldEQ(FieldBodyFormat, v)) +} + +// BodyFormatNEQ applies the NEQ predicate on the "body_format" field. +func BodyFormatNEQ(v string) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldNEQ(FieldBodyFormat, v)) +} + +// BodyFormatIn applies the In predicate on the "body_format" field. +func BodyFormatIn(vs ...string) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldIn(FieldBodyFormat, vs...)) +} + +// BodyFormatNotIn applies the NotIn predicate on the "body_format" field. +func BodyFormatNotIn(vs ...string) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldNotIn(FieldBodyFormat, vs...)) +} + +// BodyFormatGT applies the GT predicate on the "body_format" field. +func BodyFormatGT(v string) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldGT(FieldBodyFormat, v)) +} + +// BodyFormatGTE applies the GTE predicate on the "body_format" field. +func BodyFormatGTE(v string) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldGTE(FieldBodyFormat, v)) +} + +// BodyFormatLT applies the LT predicate on the "body_format" field. +func BodyFormatLT(v string) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldLT(FieldBodyFormat, v)) +} + +// BodyFormatLTE applies the LTE predicate on the "body_format" field. +func BodyFormatLTE(v string) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldLTE(FieldBodyFormat, v)) +} + +// BodyFormatContains applies the Contains predicate on the "body_format" field. +func BodyFormatContains(v string) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldContains(FieldBodyFormat, v)) +} + +// BodyFormatHasPrefix applies the HasPrefix predicate on the "body_format" field. +func BodyFormatHasPrefix(v string) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldHasPrefix(FieldBodyFormat, v)) +} + +// BodyFormatHasSuffix applies the HasSuffix predicate on the "body_format" field. +func BodyFormatHasSuffix(v string) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldHasSuffix(FieldBodyFormat, v)) +} + +// BodyFormatEqualFold applies the EqualFold predicate on the "body_format" field. +func BodyFormatEqualFold(v string) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldEqualFold(FieldBodyFormat, v)) +} + +// BodyFormatContainsFold applies the ContainsFold predicate on the "body_format" field. +func BodyFormatContainsFold(v string) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldContainsFold(FieldBodyFormat, v)) +} + +// RecipientsModeEQ applies the EQ predicate on the "recipients_mode" field. +func RecipientsModeEQ(v string) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldEQ(FieldRecipientsMode, v)) +} + +// RecipientsModeNEQ applies the NEQ predicate on the "recipients_mode" field. +func RecipientsModeNEQ(v string) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldNEQ(FieldRecipientsMode, v)) +} + +// RecipientsModeIn applies the In predicate on the "recipients_mode" field. +func RecipientsModeIn(vs ...string) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldIn(FieldRecipientsMode, vs...)) +} + +// RecipientsModeNotIn applies the NotIn predicate on the "recipients_mode" field. +func RecipientsModeNotIn(vs ...string) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldNotIn(FieldRecipientsMode, vs...)) +} + +// RecipientsModeGT applies the GT predicate on the "recipients_mode" field. +func RecipientsModeGT(v string) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldGT(FieldRecipientsMode, v)) +} + +// RecipientsModeGTE applies the GTE predicate on the "recipients_mode" field. +func RecipientsModeGTE(v string) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldGTE(FieldRecipientsMode, v)) +} + +// RecipientsModeLT applies the LT predicate on the "recipients_mode" field. +func RecipientsModeLT(v string) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldLT(FieldRecipientsMode, v)) +} + +// RecipientsModeLTE applies the LTE predicate on the "recipients_mode" field. +func RecipientsModeLTE(v string) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldLTE(FieldRecipientsMode, v)) +} + +// RecipientsModeContains applies the Contains predicate on the "recipients_mode" field. +func RecipientsModeContains(v string) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldContains(FieldRecipientsMode, v)) +} + +// RecipientsModeHasPrefix applies the HasPrefix predicate on the "recipients_mode" field. +func RecipientsModeHasPrefix(v string) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldHasPrefix(FieldRecipientsMode, v)) +} + +// RecipientsModeHasSuffix applies the HasSuffix predicate on the "recipients_mode" field. +func RecipientsModeHasSuffix(v string) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldHasSuffix(FieldRecipientsMode, v)) +} + +// RecipientsModeEqualFold applies the EqualFold predicate on the "recipients_mode" field. +func RecipientsModeEqualFold(v string) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldEqualFold(FieldRecipientsMode, v)) +} + +// RecipientsModeContainsFold applies the ContainsFold predicate on the "recipients_mode" field. +func RecipientsModeContainsFold(v string) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldContainsFold(FieldRecipientsMode, v)) +} + +// RecipientUserIdsIsNil applies the IsNil predicate on the "recipient_user_ids" field. +func RecipientUserIdsIsNil() predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldIsNull(FieldRecipientUserIds)) +} + +// RecipientUserIdsNotNil applies the NotNil predicate on the "recipient_user_ids" field. +func RecipientUserIdsNotNil() predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldNotNull(FieldRecipientUserIds)) +} + +// StatusEQ applies the EQ predicate on the "status" field. +func StatusEQ(v string) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldEQ(FieldStatus, v)) +} + +// StatusNEQ applies the NEQ predicate on the "status" field. +func StatusNEQ(v string) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldNEQ(FieldStatus, v)) +} + +// StatusIn applies the In predicate on the "status" field. +func StatusIn(vs ...string) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldIn(FieldStatus, vs...)) +} + +// StatusNotIn applies the NotIn predicate on the "status" field. +func StatusNotIn(vs ...string) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldNotIn(FieldStatus, vs...)) +} + +// StatusGT applies the GT predicate on the "status" field. +func StatusGT(v string) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldGT(FieldStatus, v)) +} + +// StatusGTE applies the GTE predicate on the "status" field. +func StatusGTE(v string) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldGTE(FieldStatus, v)) +} + +// StatusLT applies the LT predicate on the "status" field. +func StatusLT(v string) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldLT(FieldStatus, v)) +} + +// StatusLTE applies the LTE predicate on the "status" field. +func StatusLTE(v string) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldLTE(FieldStatus, v)) +} + +// StatusContains applies the Contains predicate on the "status" field. +func StatusContains(v string) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldContains(FieldStatus, v)) +} + +// StatusHasPrefix applies the HasPrefix predicate on the "status" field. +func StatusHasPrefix(v string) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldHasPrefix(FieldStatus, v)) +} + +// StatusHasSuffix applies the HasSuffix predicate on the "status" field. +func StatusHasSuffix(v string) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldHasSuffix(FieldStatus, v)) +} + +// StatusEqualFold applies the EqualFold predicate on the "status" field. +func StatusEqualFold(v string) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldEqualFold(FieldStatus, v)) +} + +// StatusContainsFold applies the ContainsFold predicate on the "status" field. +func StatusContainsFold(v string) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldContainsFold(FieldStatus, v)) +} + +// TotalCountEQ applies the EQ predicate on the "total_count" field. +func TotalCountEQ(v int) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldEQ(FieldTotalCount, v)) +} + +// TotalCountNEQ applies the NEQ predicate on the "total_count" field. +func TotalCountNEQ(v int) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldNEQ(FieldTotalCount, v)) +} + +// TotalCountIn applies the In predicate on the "total_count" field. +func TotalCountIn(vs ...int) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldIn(FieldTotalCount, vs...)) +} + +// TotalCountNotIn applies the NotIn predicate on the "total_count" field. +func TotalCountNotIn(vs ...int) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldNotIn(FieldTotalCount, vs...)) +} + +// TotalCountGT applies the GT predicate on the "total_count" field. +func TotalCountGT(v int) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldGT(FieldTotalCount, v)) +} + +// TotalCountGTE applies the GTE predicate on the "total_count" field. +func TotalCountGTE(v int) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldGTE(FieldTotalCount, v)) +} + +// TotalCountLT applies the LT predicate on the "total_count" field. +func TotalCountLT(v int) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldLT(FieldTotalCount, v)) +} + +// TotalCountLTE applies the LTE predicate on the "total_count" field. +func TotalCountLTE(v int) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldLTE(FieldTotalCount, v)) +} + +// SuccessCountEQ applies the EQ predicate on the "success_count" field. +func SuccessCountEQ(v int) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldEQ(FieldSuccessCount, v)) +} + +// SuccessCountNEQ applies the NEQ predicate on the "success_count" field. +func SuccessCountNEQ(v int) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldNEQ(FieldSuccessCount, v)) +} + +// SuccessCountIn applies the In predicate on the "success_count" field. +func SuccessCountIn(vs ...int) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldIn(FieldSuccessCount, vs...)) +} + +// SuccessCountNotIn applies the NotIn predicate on the "success_count" field. +func SuccessCountNotIn(vs ...int) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldNotIn(FieldSuccessCount, vs...)) +} + +// SuccessCountGT applies the GT predicate on the "success_count" field. +func SuccessCountGT(v int) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldGT(FieldSuccessCount, v)) +} + +// SuccessCountGTE applies the GTE predicate on the "success_count" field. +func SuccessCountGTE(v int) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldGTE(FieldSuccessCount, v)) +} + +// SuccessCountLT applies the LT predicate on the "success_count" field. +func SuccessCountLT(v int) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldLT(FieldSuccessCount, v)) +} + +// SuccessCountLTE applies the LTE predicate on the "success_count" field. +func SuccessCountLTE(v int) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldLTE(FieldSuccessCount, v)) +} + +// FailedCountEQ applies the EQ predicate on the "failed_count" field. +func FailedCountEQ(v int) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldEQ(FieldFailedCount, v)) +} + +// FailedCountNEQ applies the NEQ predicate on the "failed_count" field. +func FailedCountNEQ(v int) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldNEQ(FieldFailedCount, v)) +} + +// FailedCountIn applies the In predicate on the "failed_count" field. +func FailedCountIn(vs ...int) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldIn(FieldFailedCount, vs...)) +} + +// FailedCountNotIn applies the NotIn predicate on the "failed_count" field. +func FailedCountNotIn(vs ...int) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldNotIn(FieldFailedCount, vs...)) +} + +// FailedCountGT applies the GT predicate on the "failed_count" field. +func FailedCountGT(v int) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldGT(FieldFailedCount, v)) +} + +// FailedCountGTE applies the GTE predicate on the "failed_count" field. +func FailedCountGTE(v int) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldGTE(FieldFailedCount, v)) +} + +// FailedCountLT applies the LT predicate on the "failed_count" field. +func FailedCountLT(v int) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldLT(FieldFailedCount, v)) +} + +// FailedCountLTE applies the LTE predicate on the "failed_count" field. +func FailedCountLTE(v int) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldLTE(FieldFailedCount, v)) +} + +// ErrorMessageEQ applies the EQ predicate on the "error_message" field. +func ErrorMessageEQ(v string) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldEQ(FieldErrorMessage, v)) +} + +// ErrorMessageNEQ applies the NEQ predicate on the "error_message" field. +func ErrorMessageNEQ(v string) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldNEQ(FieldErrorMessage, v)) +} + +// ErrorMessageIn applies the In predicate on the "error_message" field. +func ErrorMessageIn(vs ...string) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldIn(FieldErrorMessage, vs...)) +} + +// ErrorMessageNotIn applies the NotIn predicate on the "error_message" field. +func ErrorMessageNotIn(vs ...string) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldNotIn(FieldErrorMessage, vs...)) +} + +// ErrorMessageGT applies the GT predicate on the "error_message" field. +func ErrorMessageGT(v string) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldGT(FieldErrorMessage, v)) +} + +// ErrorMessageGTE applies the GTE predicate on the "error_message" field. +func ErrorMessageGTE(v string) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldGTE(FieldErrorMessage, v)) +} + +// ErrorMessageLT applies the LT predicate on the "error_message" field. +func ErrorMessageLT(v string) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldLT(FieldErrorMessage, v)) +} + +// ErrorMessageLTE applies the LTE predicate on the "error_message" field. +func ErrorMessageLTE(v string) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldLTE(FieldErrorMessage, v)) +} + +// ErrorMessageContains applies the Contains predicate on the "error_message" field. +func ErrorMessageContains(v string) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldContains(FieldErrorMessage, v)) +} + +// ErrorMessageHasPrefix applies the HasPrefix predicate on the "error_message" field. +func ErrorMessageHasPrefix(v string) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldHasPrefix(FieldErrorMessage, v)) +} + +// ErrorMessageHasSuffix applies the HasSuffix predicate on the "error_message" field. +func ErrorMessageHasSuffix(v string) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldHasSuffix(FieldErrorMessage, v)) +} + +// ErrorMessageIsNil applies the IsNil predicate on the "error_message" field. +func ErrorMessageIsNil() predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldIsNull(FieldErrorMessage)) +} + +// ErrorMessageNotNil applies the NotNil predicate on the "error_message" field. +func ErrorMessageNotNil() predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldNotNull(FieldErrorMessage)) +} + +// ErrorMessageEqualFold applies the EqualFold predicate on the "error_message" field. +func ErrorMessageEqualFold(v string) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldEqualFold(FieldErrorMessage, v)) +} + +// ErrorMessageContainsFold applies the ContainsFold predicate on the "error_message" field. +func ErrorMessageContainsFold(v string) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldContainsFold(FieldErrorMessage, v)) +} + +// CreatedByEQ applies the EQ predicate on the "created_by" field. +func CreatedByEQ(v int64) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldEQ(FieldCreatedBy, v)) +} + +// CreatedByNEQ applies the NEQ predicate on the "created_by" field. +func CreatedByNEQ(v int64) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldNEQ(FieldCreatedBy, v)) +} + +// CreatedByIn applies the In predicate on the "created_by" field. +func CreatedByIn(vs ...int64) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldIn(FieldCreatedBy, vs...)) +} + +// CreatedByNotIn applies the NotIn predicate on the "created_by" field. +func CreatedByNotIn(vs ...int64) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldNotIn(FieldCreatedBy, vs...)) +} + +// CreatedByGT applies the GT predicate on the "created_by" field. +func CreatedByGT(v int64) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldGT(FieldCreatedBy, v)) +} + +// CreatedByGTE applies the GTE predicate on the "created_by" field. +func CreatedByGTE(v int64) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldGTE(FieldCreatedBy, v)) +} + +// CreatedByLT applies the LT predicate on the "created_by" field. +func CreatedByLT(v int64) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldLT(FieldCreatedBy, v)) +} + +// CreatedByLTE applies the LTE predicate on the "created_by" field. +func CreatedByLTE(v int64) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldLTE(FieldCreatedBy, v)) +} + +// CreatedByIsNil applies the IsNil predicate on the "created_by" field. +func CreatedByIsNil() predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldIsNull(FieldCreatedBy)) +} + +// CreatedByNotNil applies the NotNil predicate on the "created_by" field. +func CreatedByNotNil() predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldNotNull(FieldCreatedBy)) +} + +// StartedAtEQ applies the EQ predicate on the "started_at" field. +func StartedAtEQ(v time.Time) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldEQ(FieldStartedAt, v)) +} + +// StartedAtNEQ applies the NEQ predicate on the "started_at" field. +func StartedAtNEQ(v time.Time) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldNEQ(FieldStartedAt, v)) +} + +// StartedAtIn applies the In predicate on the "started_at" field. +func StartedAtIn(vs ...time.Time) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldIn(FieldStartedAt, vs...)) +} + +// StartedAtNotIn applies the NotIn predicate on the "started_at" field. +func StartedAtNotIn(vs ...time.Time) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldNotIn(FieldStartedAt, vs...)) +} + +// StartedAtGT applies the GT predicate on the "started_at" field. +func StartedAtGT(v time.Time) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldGT(FieldStartedAt, v)) +} + +// StartedAtGTE applies the GTE predicate on the "started_at" field. +func StartedAtGTE(v time.Time) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldGTE(FieldStartedAt, v)) +} + +// StartedAtLT applies the LT predicate on the "started_at" field. +func StartedAtLT(v time.Time) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldLT(FieldStartedAt, v)) +} + +// StartedAtLTE applies the LTE predicate on the "started_at" field. +func StartedAtLTE(v time.Time) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldLTE(FieldStartedAt, v)) +} + +// StartedAtIsNil applies the IsNil predicate on the "started_at" field. +func StartedAtIsNil() predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldIsNull(FieldStartedAt)) +} + +// StartedAtNotNil applies the NotNil predicate on the "started_at" field. +func StartedAtNotNil() predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldNotNull(FieldStartedAt)) +} + +// FinishedAtEQ applies the EQ predicate on the "finished_at" field. +func FinishedAtEQ(v time.Time) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldEQ(FieldFinishedAt, v)) +} + +// FinishedAtNEQ applies the NEQ predicate on the "finished_at" field. +func FinishedAtNEQ(v time.Time) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldNEQ(FieldFinishedAt, v)) +} + +// FinishedAtIn applies the In predicate on the "finished_at" field. +func FinishedAtIn(vs ...time.Time) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldIn(FieldFinishedAt, vs...)) +} + +// FinishedAtNotIn applies the NotIn predicate on the "finished_at" field. +func FinishedAtNotIn(vs ...time.Time) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldNotIn(FieldFinishedAt, vs...)) +} + +// FinishedAtGT applies the GT predicate on the "finished_at" field. +func FinishedAtGT(v time.Time) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldGT(FieldFinishedAt, v)) +} + +// FinishedAtGTE applies the GTE predicate on the "finished_at" field. +func FinishedAtGTE(v time.Time) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldGTE(FieldFinishedAt, v)) +} + +// FinishedAtLT applies the LT predicate on the "finished_at" field. +func FinishedAtLT(v time.Time) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldLT(FieldFinishedAt, v)) +} + +// FinishedAtLTE applies the LTE predicate on the "finished_at" field. +func FinishedAtLTE(v time.Time) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldLTE(FieldFinishedAt, v)) +} + +// FinishedAtIsNil applies the IsNil predicate on the "finished_at" field. +func FinishedAtIsNil() predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldIsNull(FieldFinishedAt)) +} + +// FinishedAtNotNil applies the NotNil predicate on the "finished_at" field. +func FinishedAtNotNil() predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldNotNull(FieldFinishedAt)) +} + +// CreatedAtEQ applies the EQ predicate on the "created_at" field. +func CreatedAtEQ(v time.Time) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldEQ(FieldCreatedAt, v)) +} + +// CreatedAtNEQ applies the NEQ predicate on the "created_at" field. +func CreatedAtNEQ(v time.Time) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldNEQ(FieldCreatedAt, v)) +} + +// CreatedAtIn applies the In predicate on the "created_at" field. +func CreatedAtIn(vs ...time.Time) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldIn(FieldCreatedAt, vs...)) +} + +// CreatedAtNotIn applies the NotIn predicate on the "created_at" field. +func CreatedAtNotIn(vs ...time.Time) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldNotIn(FieldCreatedAt, vs...)) +} + +// CreatedAtGT applies the GT predicate on the "created_at" field. +func CreatedAtGT(v time.Time) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldGT(FieldCreatedAt, v)) +} + +// CreatedAtGTE applies the GTE predicate on the "created_at" field. +func CreatedAtGTE(v time.Time) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldGTE(FieldCreatedAt, v)) +} + +// CreatedAtLT applies the LT predicate on the "created_at" field. +func CreatedAtLT(v time.Time) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldLT(FieldCreatedAt, v)) +} + +// CreatedAtLTE applies the LTE predicate on the "created_at" field. +func CreatedAtLTE(v time.Time) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldLTE(FieldCreatedAt, v)) +} + +// UpdatedAtEQ applies the EQ predicate on the "updated_at" field. +func UpdatedAtEQ(v time.Time) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldEQ(FieldUpdatedAt, v)) +} + +// UpdatedAtNEQ applies the NEQ predicate on the "updated_at" field. +func UpdatedAtNEQ(v time.Time) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldNEQ(FieldUpdatedAt, v)) +} + +// UpdatedAtIn applies the In predicate on the "updated_at" field. +func UpdatedAtIn(vs ...time.Time) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldIn(FieldUpdatedAt, vs...)) +} + +// UpdatedAtNotIn applies the NotIn predicate on the "updated_at" field. +func UpdatedAtNotIn(vs ...time.Time) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldNotIn(FieldUpdatedAt, vs...)) +} + +// UpdatedAtGT applies the GT predicate on the "updated_at" field. +func UpdatedAtGT(v time.Time) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldGT(FieldUpdatedAt, v)) +} + +// UpdatedAtGTE applies the GTE predicate on the "updated_at" field. +func UpdatedAtGTE(v time.Time) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldGTE(FieldUpdatedAt, v)) +} + +// UpdatedAtLT applies the LT predicate on the "updated_at" field. +func UpdatedAtLT(v time.Time) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldLT(FieldUpdatedAt, v)) +} + +// UpdatedAtLTE applies the LTE predicate on the "updated_at" field. +func UpdatedAtLTE(v time.Time) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.FieldLTE(FieldUpdatedAt, v)) +} + +// And groups predicates with the AND operator between them. +func And(predicates ...predicate.EmailBroadcast) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.AndPredicates(predicates...)) +} + +// Or groups predicates with the OR operator between them. +func Or(predicates ...predicate.EmailBroadcast) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.OrPredicates(predicates...)) +} + +// Not applies the not operator on the given predicate. +func Not(p predicate.EmailBroadcast) predicate.EmailBroadcast { + return predicate.EmailBroadcast(sql.NotPredicates(p)) +} diff --git a/backend/ent/emailbroadcast_create.go b/backend/ent/emailbroadcast_create.go new file mode 100644 index 00000000000..c755561cf94 --- /dev/null +++ b/backend/ent/emailbroadcast_create.go @@ -0,0 +1,1508 @@ +// 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/Wei-Shaw/sub2api/ent/emailbroadcast" +) + +// EmailBroadcastCreate is the builder for creating a EmailBroadcast entity. +type EmailBroadcastCreate struct { + config + mutation *EmailBroadcastMutation + hooks []Hook + conflict []sql.ConflictOption +} + +// SetSubject sets the "subject" field. +func (_c *EmailBroadcastCreate) SetSubject(v string) *EmailBroadcastCreate { + _c.mutation.SetSubject(v) + return _c +} + +// SetBody sets the "body" field. +func (_c *EmailBroadcastCreate) SetBody(v string) *EmailBroadcastCreate { + _c.mutation.SetBody(v) + return _c +} + +// SetBodyFormat sets the "body_format" field. +func (_c *EmailBroadcastCreate) SetBodyFormat(v string) *EmailBroadcastCreate { + _c.mutation.SetBodyFormat(v) + return _c +} + +// SetNillableBodyFormat sets the "body_format" field if the given value is not nil. +func (_c *EmailBroadcastCreate) SetNillableBodyFormat(v *string) *EmailBroadcastCreate { + if v != nil { + _c.SetBodyFormat(*v) + } + return _c +} + +// SetRecipientsMode sets the "recipients_mode" field. +func (_c *EmailBroadcastCreate) SetRecipientsMode(v string) *EmailBroadcastCreate { + _c.mutation.SetRecipientsMode(v) + return _c +} + +// SetNillableRecipientsMode sets the "recipients_mode" field if the given value is not nil. +func (_c *EmailBroadcastCreate) SetNillableRecipientsMode(v *string) *EmailBroadcastCreate { + if v != nil { + _c.SetRecipientsMode(*v) + } + return _c +} + +// SetRecipientUserIds sets the "recipient_user_ids" field. +func (_c *EmailBroadcastCreate) SetRecipientUserIds(v []int64) *EmailBroadcastCreate { + _c.mutation.SetRecipientUserIds(v) + return _c +} + +// SetStatus sets the "status" field. +func (_c *EmailBroadcastCreate) SetStatus(v string) *EmailBroadcastCreate { + _c.mutation.SetStatus(v) + return _c +} + +// SetNillableStatus sets the "status" field if the given value is not nil. +func (_c *EmailBroadcastCreate) SetNillableStatus(v *string) *EmailBroadcastCreate { + if v != nil { + _c.SetStatus(*v) + } + return _c +} + +// SetTotalCount sets the "total_count" field. +func (_c *EmailBroadcastCreate) SetTotalCount(v int) *EmailBroadcastCreate { + _c.mutation.SetTotalCount(v) + return _c +} + +// SetNillableTotalCount sets the "total_count" field if the given value is not nil. +func (_c *EmailBroadcastCreate) SetNillableTotalCount(v *int) *EmailBroadcastCreate { + if v != nil { + _c.SetTotalCount(*v) + } + return _c +} + +// SetSuccessCount sets the "success_count" field. +func (_c *EmailBroadcastCreate) SetSuccessCount(v int) *EmailBroadcastCreate { + _c.mutation.SetSuccessCount(v) + return _c +} + +// SetNillableSuccessCount sets the "success_count" field if the given value is not nil. +func (_c *EmailBroadcastCreate) SetNillableSuccessCount(v *int) *EmailBroadcastCreate { + if v != nil { + _c.SetSuccessCount(*v) + } + return _c +} + +// SetFailedCount sets the "failed_count" field. +func (_c *EmailBroadcastCreate) SetFailedCount(v int) *EmailBroadcastCreate { + _c.mutation.SetFailedCount(v) + return _c +} + +// SetNillableFailedCount sets the "failed_count" field if the given value is not nil. +func (_c *EmailBroadcastCreate) SetNillableFailedCount(v *int) *EmailBroadcastCreate { + if v != nil { + _c.SetFailedCount(*v) + } + return _c +} + +// SetErrorMessage sets the "error_message" field. +func (_c *EmailBroadcastCreate) SetErrorMessage(v string) *EmailBroadcastCreate { + _c.mutation.SetErrorMessage(v) + return _c +} + +// SetNillableErrorMessage sets the "error_message" field if the given value is not nil. +func (_c *EmailBroadcastCreate) SetNillableErrorMessage(v *string) *EmailBroadcastCreate { + if v != nil { + _c.SetErrorMessage(*v) + } + return _c +} + +// SetCreatedBy sets the "created_by" field. +func (_c *EmailBroadcastCreate) SetCreatedBy(v int64) *EmailBroadcastCreate { + _c.mutation.SetCreatedBy(v) + return _c +} + +// SetNillableCreatedBy sets the "created_by" field if the given value is not nil. +func (_c *EmailBroadcastCreate) SetNillableCreatedBy(v *int64) *EmailBroadcastCreate { + if v != nil { + _c.SetCreatedBy(*v) + } + return _c +} + +// SetStartedAt sets the "started_at" field. +func (_c *EmailBroadcastCreate) SetStartedAt(v time.Time) *EmailBroadcastCreate { + _c.mutation.SetStartedAt(v) + return _c +} + +// SetNillableStartedAt sets the "started_at" field if the given value is not nil. +func (_c *EmailBroadcastCreate) SetNillableStartedAt(v *time.Time) *EmailBroadcastCreate { + if v != nil { + _c.SetStartedAt(*v) + } + return _c +} + +// SetFinishedAt sets the "finished_at" field. +func (_c *EmailBroadcastCreate) SetFinishedAt(v time.Time) *EmailBroadcastCreate { + _c.mutation.SetFinishedAt(v) + return _c +} + +// SetNillableFinishedAt sets the "finished_at" field if the given value is not nil. +func (_c *EmailBroadcastCreate) SetNillableFinishedAt(v *time.Time) *EmailBroadcastCreate { + if v != nil { + _c.SetFinishedAt(*v) + } + return _c +} + +// SetCreatedAt sets the "created_at" field. +func (_c *EmailBroadcastCreate) SetCreatedAt(v time.Time) *EmailBroadcastCreate { + _c.mutation.SetCreatedAt(v) + return _c +} + +// SetNillableCreatedAt sets the "created_at" field if the given value is not nil. +func (_c *EmailBroadcastCreate) SetNillableCreatedAt(v *time.Time) *EmailBroadcastCreate { + if v != nil { + _c.SetCreatedAt(*v) + } + return _c +} + +// SetUpdatedAt sets the "updated_at" field. +func (_c *EmailBroadcastCreate) SetUpdatedAt(v time.Time) *EmailBroadcastCreate { + _c.mutation.SetUpdatedAt(v) + return _c +} + +// SetNillableUpdatedAt sets the "updated_at" field if the given value is not nil. +func (_c *EmailBroadcastCreate) SetNillableUpdatedAt(v *time.Time) *EmailBroadcastCreate { + if v != nil { + _c.SetUpdatedAt(*v) + } + return _c +} + +// Mutation returns the EmailBroadcastMutation object of the builder. +func (_c *EmailBroadcastCreate) Mutation() *EmailBroadcastMutation { + return _c.mutation +} + +// Save creates the EmailBroadcast in the database. +func (_c *EmailBroadcastCreate) Save(ctx context.Context) (*EmailBroadcast, error) { + _c.defaults() + return withHooks(ctx, _c.sqlSave, _c.mutation, _c.hooks) +} + +// SaveX calls Save and panics if Save returns an error. +func (_c *EmailBroadcastCreate) SaveX(ctx context.Context) *EmailBroadcast { + v, err := _c.Save(ctx) + if err != nil { + panic(err) + } + return v +} + +// Exec executes the query. +func (_c *EmailBroadcastCreate) Exec(ctx context.Context) error { + _, err := _c.Save(ctx) + return err +} + +// ExecX is like Exec, but panics if an error occurs. +func (_c *EmailBroadcastCreate) ExecX(ctx context.Context) { + if err := _c.Exec(ctx); err != nil { + panic(err) + } +} + +// defaults sets the default values of the builder before save. +func (_c *EmailBroadcastCreate) defaults() { + if _, ok := _c.mutation.BodyFormat(); !ok { + v := emailbroadcast.DefaultBodyFormat + _c.mutation.SetBodyFormat(v) + } + if _, ok := _c.mutation.RecipientsMode(); !ok { + v := emailbroadcast.DefaultRecipientsMode + _c.mutation.SetRecipientsMode(v) + } + if _, ok := _c.mutation.Status(); !ok { + v := emailbroadcast.DefaultStatus + _c.mutation.SetStatus(v) + } + if _, ok := _c.mutation.TotalCount(); !ok { + v := emailbroadcast.DefaultTotalCount + _c.mutation.SetTotalCount(v) + } + if _, ok := _c.mutation.SuccessCount(); !ok { + v := emailbroadcast.DefaultSuccessCount + _c.mutation.SetSuccessCount(v) + } + if _, ok := _c.mutation.FailedCount(); !ok { + v := emailbroadcast.DefaultFailedCount + _c.mutation.SetFailedCount(v) + } + if _, ok := _c.mutation.CreatedAt(); !ok { + v := emailbroadcast.DefaultCreatedAt() + _c.mutation.SetCreatedAt(v) + } + if _, ok := _c.mutation.UpdatedAt(); !ok { + v := emailbroadcast.DefaultUpdatedAt() + _c.mutation.SetUpdatedAt(v) + } +} + +// check runs all checks and user-defined validators on the builder. +func (_c *EmailBroadcastCreate) check() error { + if _, ok := _c.mutation.Subject(); !ok { + return &ValidationError{Name: "subject", err: errors.New(`ent: missing required field "EmailBroadcast.subject"`)} + } + if v, ok := _c.mutation.Subject(); ok { + if err := emailbroadcast.SubjectValidator(v); err != nil { + return &ValidationError{Name: "subject", err: fmt.Errorf(`ent: validator failed for field "EmailBroadcast.subject": %w`, err)} + } + } + if _, ok := _c.mutation.Body(); !ok { + return &ValidationError{Name: "body", err: errors.New(`ent: missing required field "EmailBroadcast.body"`)} + } + if v, ok := _c.mutation.Body(); ok { + if err := emailbroadcast.BodyValidator(v); err != nil { + return &ValidationError{Name: "body", err: fmt.Errorf(`ent: validator failed for field "EmailBroadcast.body": %w`, err)} + } + } + if _, ok := _c.mutation.BodyFormat(); !ok { + return &ValidationError{Name: "body_format", err: errors.New(`ent: missing required field "EmailBroadcast.body_format"`)} + } + if v, ok := _c.mutation.BodyFormat(); ok { + if err := emailbroadcast.BodyFormatValidator(v); err != nil { + return &ValidationError{Name: "body_format", err: fmt.Errorf(`ent: validator failed for field "EmailBroadcast.body_format": %w`, err)} + } + } + if _, ok := _c.mutation.RecipientsMode(); !ok { + return &ValidationError{Name: "recipients_mode", err: errors.New(`ent: missing required field "EmailBroadcast.recipients_mode"`)} + } + if v, ok := _c.mutation.RecipientsMode(); ok { + if err := emailbroadcast.RecipientsModeValidator(v); err != nil { + return &ValidationError{Name: "recipients_mode", err: fmt.Errorf(`ent: validator failed for field "EmailBroadcast.recipients_mode": %w`, err)} + } + } + if _, ok := _c.mutation.Status(); !ok { + return &ValidationError{Name: "status", err: errors.New(`ent: missing required field "EmailBroadcast.status"`)} + } + if v, ok := _c.mutation.Status(); ok { + if err := emailbroadcast.StatusValidator(v); err != nil { + return &ValidationError{Name: "status", err: fmt.Errorf(`ent: validator failed for field "EmailBroadcast.status": %w`, err)} + } + } + if _, ok := _c.mutation.TotalCount(); !ok { + return &ValidationError{Name: "total_count", err: errors.New(`ent: missing required field "EmailBroadcast.total_count"`)} + } + if v, ok := _c.mutation.TotalCount(); ok { + if err := emailbroadcast.TotalCountValidator(v); err != nil { + return &ValidationError{Name: "total_count", err: fmt.Errorf(`ent: validator failed for field "EmailBroadcast.total_count": %w`, err)} + } + } + if _, ok := _c.mutation.SuccessCount(); !ok { + return &ValidationError{Name: "success_count", err: errors.New(`ent: missing required field "EmailBroadcast.success_count"`)} + } + if v, ok := _c.mutation.SuccessCount(); ok { + if err := emailbroadcast.SuccessCountValidator(v); err != nil { + return &ValidationError{Name: "success_count", err: fmt.Errorf(`ent: validator failed for field "EmailBroadcast.success_count": %w`, err)} + } + } + if _, ok := _c.mutation.FailedCount(); !ok { + return &ValidationError{Name: "failed_count", err: errors.New(`ent: missing required field "EmailBroadcast.failed_count"`)} + } + if v, ok := _c.mutation.FailedCount(); ok { + if err := emailbroadcast.FailedCountValidator(v); err != nil { + return &ValidationError{Name: "failed_count", err: fmt.Errorf(`ent: validator failed for field "EmailBroadcast.failed_count": %w`, err)} + } + } + if _, ok := _c.mutation.CreatedAt(); !ok { + return &ValidationError{Name: "created_at", err: errors.New(`ent: missing required field "EmailBroadcast.created_at"`)} + } + if _, ok := _c.mutation.UpdatedAt(); !ok { + return &ValidationError{Name: "updated_at", err: errors.New(`ent: missing required field "EmailBroadcast.updated_at"`)} + } + return nil +} + +func (_c *EmailBroadcastCreate) sqlSave(ctx context.Context) (*EmailBroadcast, error) { + if err := _c.check(); err != nil { + return nil, err + } + _node, _spec := _c.createSpec() + if err := sqlgraph.CreateNode(ctx, _c.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 = int64(id) + _c.mutation.id = &_node.ID + _c.mutation.done = true + return _node, nil +} + +func (_c *EmailBroadcastCreate) createSpec() (*EmailBroadcast, *sqlgraph.CreateSpec) { + var ( + _node = &EmailBroadcast{config: _c.config} + _spec = sqlgraph.NewCreateSpec(emailbroadcast.Table, sqlgraph.NewFieldSpec(emailbroadcast.FieldID, field.TypeInt64)) + ) + _spec.OnConflict = _c.conflict + if value, ok := _c.mutation.Subject(); ok { + _spec.SetField(emailbroadcast.FieldSubject, field.TypeString, value) + _node.Subject = value + } + if value, ok := _c.mutation.Body(); ok { + _spec.SetField(emailbroadcast.FieldBody, field.TypeString, value) + _node.Body = value + } + if value, ok := _c.mutation.BodyFormat(); ok { + _spec.SetField(emailbroadcast.FieldBodyFormat, field.TypeString, value) + _node.BodyFormat = value + } + if value, ok := _c.mutation.RecipientsMode(); ok { + _spec.SetField(emailbroadcast.FieldRecipientsMode, field.TypeString, value) + _node.RecipientsMode = value + } + if value, ok := _c.mutation.RecipientUserIds(); ok { + _spec.SetField(emailbroadcast.FieldRecipientUserIds, field.TypeJSON, value) + _node.RecipientUserIds = value + } + if value, ok := _c.mutation.Status(); ok { + _spec.SetField(emailbroadcast.FieldStatus, field.TypeString, value) + _node.Status = value + } + if value, ok := _c.mutation.TotalCount(); ok { + _spec.SetField(emailbroadcast.FieldTotalCount, field.TypeInt, value) + _node.TotalCount = value + } + if value, ok := _c.mutation.SuccessCount(); ok { + _spec.SetField(emailbroadcast.FieldSuccessCount, field.TypeInt, value) + _node.SuccessCount = value + } + if value, ok := _c.mutation.FailedCount(); ok { + _spec.SetField(emailbroadcast.FieldFailedCount, field.TypeInt, value) + _node.FailedCount = value + } + if value, ok := _c.mutation.ErrorMessage(); ok { + _spec.SetField(emailbroadcast.FieldErrorMessage, field.TypeString, value) + _node.ErrorMessage = &value + } + if value, ok := _c.mutation.CreatedBy(); ok { + _spec.SetField(emailbroadcast.FieldCreatedBy, field.TypeInt64, value) + _node.CreatedBy = &value + } + if value, ok := _c.mutation.StartedAt(); ok { + _spec.SetField(emailbroadcast.FieldStartedAt, field.TypeTime, value) + _node.StartedAt = &value + } + if value, ok := _c.mutation.FinishedAt(); ok { + _spec.SetField(emailbroadcast.FieldFinishedAt, field.TypeTime, value) + _node.FinishedAt = &value + } + if value, ok := _c.mutation.CreatedAt(); ok { + _spec.SetField(emailbroadcast.FieldCreatedAt, field.TypeTime, value) + _node.CreatedAt = value + } + if value, ok := _c.mutation.UpdatedAt(); ok { + _spec.SetField(emailbroadcast.FieldUpdatedAt, field.TypeTime, value) + _node.UpdatedAt = value + } + return _node, _spec +} + +// OnConflict allows configuring the `ON CONFLICT` / `ON DUPLICATE KEY` clause +// of the `INSERT` statement. For example: +// +// client.EmailBroadcast.Create(). +// SetSubject(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.EmailBroadcastUpsert) { +// SetSubject(v+v). +// }). +// Exec(ctx) +func (_c *EmailBroadcastCreate) OnConflict(opts ...sql.ConflictOption) *EmailBroadcastUpsertOne { + _c.conflict = opts + return &EmailBroadcastUpsertOne{ + create: _c, + } +} + +// OnConflictColumns calls `OnConflict` and configures the columns +// as conflict target. Using this option is equivalent to using: +// +// client.EmailBroadcast.Create(). +// OnConflict(sql.ConflictColumns(columns...)). +// Exec(ctx) +func (_c *EmailBroadcastCreate) OnConflictColumns(columns ...string) *EmailBroadcastUpsertOne { + _c.conflict = append(_c.conflict, sql.ConflictColumns(columns...)) + return &EmailBroadcastUpsertOne{ + create: _c, + } +} + +type ( + // EmailBroadcastUpsertOne is the builder for "upsert"-ing + // one EmailBroadcast node. + EmailBroadcastUpsertOne struct { + create *EmailBroadcastCreate + } + + // EmailBroadcastUpsert is the "OnConflict" setter. + EmailBroadcastUpsert struct { + *sql.UpdateSet + } +) + +// SetSubject sets the "subject" field. +func (u *EmailBroadcastUpsert) SetSubject(v string) *EmailBroadcastUpsert { + u.Set(emailbroadcast.FieldSubject, v) + return u +} + +// UpdateSubject sets the "subject" field to the value that was provided on create. +func (u *EmailBroadcastUpsert) UpdateSubject() *EmailBroadcastUpsert { + u.SetExcluded(emailbroadcast.FieldSubject) + return u +} + +// SetBody sets the "body" field. +func (u *EmailBroadcastUpsert) SetBody(v string) *EmailBroadcastUpsert { + u.Set(emailbroadcast.FieldBody, v) + return u +} + +// UpdateBody sets the "body" field to the value that was provided on create. +func (u *EmailBroadcastUpsert) UpdateBody() *EmailBroadcastUpsert { + u.SetExcluded(emailbroadcast.FieldBody) + return u +} + +// SetBodyFormat sets the "body_format" field. +func (u *EmailBroadcastUpsert) SetBodyFormat(v string) *EmailBroadcastUpsert { + u.Set(emailbroadcast.FieldBodyFormat, v) + return u +} + +// UpdateBodyFormat sets the "body_format" field to the value that was provided on create. +func (u *EmailBroadcastUpsert) UpdateBodyFormat() *EmailBroadcastUpsert { + u.SetExcluded(emailbroadcast.FieldBodyFormat) + return u +} + +// SetRecipientsMode sets the "recipients_mode" field. +func (u *EmailBroadcastUpsert) SetRecipientsMode(v string) *EmailBroadcastUpsert { + u.Set(emailbroadcast.FieldRecipientsMode, v) + return u +} + +// UpdateRecipientsMode sets the "recipients_mode" field to the value that was provided on create. +func (u *EmailBroadcastUpsert) UpdateRecipientsMode() *EmailBroadcastUpsert { + u.SetExcluded(emailbroadcast.FieldRecipientsMode) + return u +} + +// SetRecipientUserIds sets the "recipient_user_ids" field. +func (u *EmailBroadcastUpsert) SetRecipientUserIds(v []int64) *EmailBroadcastUpsert { + u.Set(emailbroadcast.FieldRecipientUserIds, v) + return u +} + +// UpdateRecipientUserIds sets the "recipient_user_ids" field to the value that was provided on create. +func (u *EmailBroadcastUpsert) UpdateRecipientUserIds() *EmailBroadcastUpsert { + u.SetExcluded(emailbroadcast.FieldRecipientUserIds) + return u +} + +// ClearRecipientUserIds clears the value of the "recipient_user_ids" field. +func (u *EmailBroadcastUpsert) ClearRecipientUserIds() *EmailBroadcastUpsert { + u.SetNull(emailbroadcast.FieldRecipientUserIds) + return u +} + +// SetStatus sets the "status" field. +func (u *EmailBroadcastUpsert) SetStatus(v string) *EmailBroadcastUpsert { + u.Set(emailbroadcast.FieldStatus, v) + return u +} + +// UpdateStatus sets the "status" field to the value that was provided on create. +func (u *EmailBroadcastUpsert) UpdateStatus() *EmailBroadcastUpsert { + u.SetExcluded(emailbroadcast.FieldStatus) + return u +} + +// SetTotalCount sets the "total_count" field. +func (u *EmailBroadcastUpsert) SetTotalCount(v int) *EmailBroadcastUpsert { + u.Set(emailbroadcast.FieldTotalCount, v) + return u +} + +// UpdateTotalCount sets the "total_count" field to the value that was provided on create. +func (u *EmailBroadcastUpsert) UpdateTotalCount() *EmailBroadcastUpsert { + u.SetExcluded(emailbroadcast.FieldTotalCount) + return u +} + +// AddTotalCount adds v to the "total_count" field. +func (u *EmailBroadcastUpsert) AddTotalCount(v int) *EmailBroadcastUpsert { + u.Add(emailbroadcast.FieldTotalCount, v) + return u +} + +// SetSuccessCount sets the "success_count" field. +func (u *EmailBroadcastUpsert) SetSuccessCount(v int) *EmailBroadcastUpsert { + u.Set(emailbroadcast.FieldSuccessCount, v) + return u +} + +// UpdateSuccessCount sets the "success_count" field to the value that was provided on create. +func (u *EmailBroadcastUpsert) UpdateSuccessCount() *EmailBroadcastUpsert { + u.SetExcluded(emailbroadcast.FieldSuccessCount) + return u +} + +// AddSuccessCount adds v to the "success_count" field. +func (u *EmailBroadcastUpsert) AddSuccessCount(v int) *EmailBroadcastUpsert { + u.Add(emailbroadcast.FieldSuccessCount, v) + return u +} + +// SetFailedCount sets the "failed_count" field. +func (u *EmailBroadcastUpsert) SetFailedCount(v int) *EmailBroadcastUpsert { + u.Set(emailbroadcast.FieldFailedCount, v) + return u +} + +// UpdateFailedCount sets the "failed_count" field to the value that was provided on create. +func (u *EmailBroadcastUpsert) UpdateFailedCount() *EmailBroadcastUpsert { + u.SetExcluded(emailbroadcast.FieldFailedCount) + return u +} + +// AddFailedCount adds v to the "failed_count" field. +func (u *EmailBroadcastUpsert) AddFailedCount(v int) *EmailBroadcastUpsert { + u.Add(emailbroadcast.FieldFailedCount, v) + return u +} + +// SetErrorMessage sets the "error_message" field. +func (u *EmailBroadcastUpsert) SetErrorMessage(v string) *EmailBroadcastUpsert { + u.Set(emailbroadcast.FieldErrorMessage, v) + return u +} + +// UpdateErrorMessage sets the "error_message" field to the value that was provided on create. +func (u *EmailBroadcastUpsert) UpdateErrorMessage() *EmailBroadcastUpsert { + u.SetExcluded(emailbroadcast.FieldErrorMessage) + return u +} + +// ClearErrorMessage clears the value of the "error_message" field. +func (u *EmailBroadcastUpsert) ClearErrorMessage() *EmailBroadcastUpsert { + u.SetNull(emailbroadcast.FieldErrorMessage) + return u +} + +// SetCreatedBy sets the "created_by" field. +func (u *EmailBroadcastUpsert) SetCreatedBy(v int64) *EmailBroadcastUpsert { + u.Set(emailbroadcast.FieldCreatedBy, v) + return u +} + +// UpdateCreatedBy sets the "created_by" field to the value that was provided on create. +func (u *EmailBroadcastUpsert) UpdateCreatedBy() *EmailBroadcastUpsert { + u.SetExcluded(emailbroadcast.FieldCreatedBy) + return u +} + +// AddCreatedBy adds v to the "created_by" field. +func (u *EmailBroadcastUpsert) AddCreatedBy(v int64) *EmailBroadcastUpsert { + u.Add(emailbroadcast.FieldCreatedBy, v) + return u +} + +// ClearCreatedBy clears the value of the "created_by" field. +func (u *EmailBroadcastUpsert) ClearCreatedBy() *EmailBroadcastUpsert { + u.SetNull(emailbroadcast.FieldCreatedBy) + return u +} + +// SetStartedAt sets the "started_at" field. +func (u *EmailBroadcastUpsert) SetStartedAt(v time.Time) *EmailBroadcastUpsert { + u.Set(emailbroadcast.FieldStartedAt, v) + return u +} + +// UpdateStartedAt sets the "started_at" field to the value that was provided on create. +func (u *EmailBroadcastUpsert) UpdateStartedAt() *EmailBroadcastUpsert { + u.SetExcluded(emailbroadcast.FieldStartedAt) + return u +} + +// ClearStartedAt clears the value of the "started_at" field. +func (u *EmailBroadcastUpsert) ClearStartedAt() *EmailBroadcastUpsert { + u.SetNull(emailbroadcast.FieldStartedAt) + return u +} + +// SetFinishedAt sets the "finished_at" field. +func (u *EmailBroadcastUpsert) SetFinishedAt(v time.Time) *EmailBroadcastUpsert { + u.Set(emailbroadcast.FieldFinishedAt, v) + return u +} + +// UpdateFinishedAt sets the "finished_at" field to the value that was provided on create. +func (u *EmailBroadcastUpsert) UpdateFinishedAt() *EmailBroadcastUpsert { + u.SetExcluded(emailbroadcast.FieldFinishedAt) + return u +} + +// ClearFinishedAt clears the value of the "finished_at" field. +func (u *EmailBroadcastUpsert) ClearFinishedAt() *EmailBroadcastUpsert { + u.SetNull(emailbroadcast.FieldFinishedAt) + return u +} + +// SetUpdatedAt sets the "updated_at" field. +func (u *EmailBroadcastUpsert) SetUpdatedAt(v time.Time) *EmailBroadcastUpsert { + u.Set(emailbroadcast.FieldUpdatedAt, v) + return u +} + +// UpdateUpdatedAt sets the "updated_at" field to the value that was provided on create. +func (u *EmailBroadcastUpsert) UpdateUpdatedAt() *EmailBroadcastUpsert { + u.SetExcluded(emailbroadcast.FieldUpdatedAt) + return u +} + +// UpdateNewValues updates the mutable fields using the new values that were set on create. +// Using this option is equivalent to using: +// +// client.EmailBroadcast.Create(). +// OnConflict( +// sql.ResolveWithNewValues(), +// ). +// Exec(ctx) +func (u *EmailBroadcastUpsertOne) UpdateNewValues() *EmailBroadcastUpsertOne { + 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(emailbroadcast.FieldCreatedAt) + } + })) + return u +} + +// Ignore sets each column to itself in case of conflict. +// Using this option is equivalent to using: +// +// client.EmailBroadcast.Create(). +// OnConflict(sql.ResolveWithIgnore()). +// Exec(ctx) +func (u *EmailBroadcastUpsertOne) Ignore() *EmailBroadcastUpsertOne { + 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 *EmailBroadcastUpsertOne) DoNothing() *EmailBroadcastUpsertOne { + u.create.conflict = append(u.create.conflict, sql.DoNothing()) + return u +} + +// Update allows overriding fields `UPDATE` values. See the EmailBroadcastCreate.OnConflict +// documentation for more info. +func (u *EmailBroadcastUpsertOne) Update(set func(*EmailBroadcastUpsert)) *EmailBroadcastUpsertOne { + u.create.conflict = append(u.create.conflict, sql.ResolveWith(func(update *sql.UpdateSet) { + set(&EmailBroadcastUpsert{UpdateSet: update}) + })) + return u +} + +// SetSubject sets the "subject" field. +func (u *EmailBroadcastUpsertOne) SetSubject(v string) *EmailBroadcastUpsertOne { + return u.Update(func(s *EmailBroadcastUpsert) { + s.SetSubject(v) + }) +} + +// UpdateSubject sets the "subject" field to the value that was provided on create. +func (u *EmailBroadcastUpsertOne) UpdateSubject() *EmailBroadcastUpsertOne { + return u.Update(func(s *EmailBroadcastUpsert) { + s.UpdateSubject() + }) +} + +// SetBody sets the "body" field. +func (u *EmailBroadcastUpsertOne) SetBody(v string) *EmailBroadcastUpsertOne { + return u.Update(func(s *EmailBroadcastUpsert) { + s.SetBody(v) + }) +} + +// UpdateBody sets the "body" field to the value that was provided on create. +func (u *EmailBroadcastUpsertOne) UpdateBody() *EmailBroadcastUpsertOne { + return u.Update(func(s *EmailBroadcastUpsert) { + s.UpdateBody() + }) +} + +// SetBodyFormat sets the "body_format" field. +func (u *EmailBroadcastUpsertOne) SetBodyFormat(v string) *EmailBroadcastUpsertOne { + return u.Update(func(s *EmailBroadcastUpsert) { + s.SetBodyFormat(v) + }) +} + +// UpdateBodyFormat sets the "body_format" field to the value that was provided on create. +func (u *EmailBroadcastUpsertOne) UpdateBodyFormat() *EmailBroadcastUpsertOne { + return u.Update(func(s *EmailBroadcastUpsert) { + s.UpdateBodyFormat() + }) +} + +// SetRecipientsMode sets the "recipients_mode" field. +func (u *EmailBroadcastUpsertOne) SetRecipientsMode(v string) *EmailBroadcastUpsertOne { + return u.Update(func(s *EmailBroadcastUpsert) { + s.SetRecipientsMode(v) + }) +} + +// UpdateRecipientsMode sets the "recipients_mode" field to the value that was provided on create. +func (u *EmailBroadcastUpsertOne) UpdateRecipientsMode() *EmailBroadcastUpsertOne { + return u.Update(func(s *EmailBroadcastUpsert) { + s.UpdateRecipientsMode() + }) +} + +// SetRecipientUserIds sets the "recipient_user_ids" field. +func (u *EmailBroadcastUpsertOne) SetRecipientUserIds(v []int64) *EmailBroadcastUpsertOne { + return u.Update(func(s *EmailBroadcastUpsert) { + s.SetRecipientUserIds(v) + }) +} + +// UpdateRecipientUserIds sets the "recipient_user_ids" field to the value that was provided on create. +func (u *EmailBroadcastUpsertOne) UpdateRecipientUserIds() *EmailBroadcastUpsertOne { + return u.Update(func(s *EmailBroadcastUpsert) { + s.UpdateRecipientUserIds() + }) +} + +// ClearRecipientUserIds clears the value of the "recipient_user_ids" field. +func (u *EmailBroadcastUpsertOne) ClearRecipientUserIds() *EmailBroadcastUpsertOne { + return u.Update(func(s *EmailBroadcastUpsert) { + s.ClearRecipientUserIds() + }) +} + +// SetStatus sets the "status" field. +func (u *EmailBroadcastUpsertOne) SetStatus(v string) *EmailBroadcastUpsertOne { + return u.Update(func(s *EmailBroadcastUpsert) { + s.SetStatus(v) + }) +} + +// UpdateStatus sets the "status" field to the value that was provided on create. +func (u *EmailBroadcastUpsertOne) UpdateStatus() *EmailBroadcastUpsertOne { + return u.Update(func(s *EmailBroadcastUpsert) { + s.UpdateStatus() + }) +} + +// SetTotalCount sets the "total_count" field. +func (u *EmailBroadcastUpsertOne) SetTotalCount(v int) *EmailBroadcastUpsertOne { + return u.Update(func(s *EmailBroadcastUpsert) { + s.SetTotalCount(v) + }) +} + +// AddTotalCount adds v to the "total_count" field. +func (u *EmailBroadcastUpsertOne) AddTotalCount(v int) *EmailBroadcastUpsertOne { + return u.Update(func(s *EmailBroadcastUpsert) { + s.AddTotalCount(v) + }) +} + +// UpdateTotalCount sets the "total_count" field to the value that was provided on create. +func (u *EmailBroadcastUpsertOne) UpdateTotalCount() *EmailBroadcastUpsertOne { + return u.Update(func(s *EmailBroadcastUpsert) { + s.UpdateTotalCount() + }) +} + +// SetSuccessCount sets the "success_count" field. +func (u *EmailBroadcastUpsertOne) SetSuccessCount(v int) *EmailBroadcastUpsertOne { + return u.Update(func(s *EmailBroadcastUpsert) { + s.SetSuccessCount(v) + }) +} + +// AddSuccessCount adds v to the "success_count" field. +func (u *EmailBroadcastUpsertOne) AddSuccessCount(v int) *EmailBroadcastUpsertOne { + return u.Update(func(s *EmailBroadcastUpsert) { + s.AddSuccessCount(v) + }) +} + +// UpdateSuccessCount sets the "success_count" field to the value that was provided on create. +func (u *EmailBroadcastUpsertOne) UpdateSuccessCount() *EmailBroadcastUpsertOne { + return u.Update(func(s *EmailBroadcastUpsert) { + s.UpdateSuccessCount() + }) +} + +// SetFailedCount sets the "failed_count" field. +func (u *EmailBroadcastUpsertOne) SetFailedCount(v int) *EmailBroadcastUpsertOne { + return u.Update(func(s *EmailBroadcastUpsert) { + s.SetFailedCount(v) + }) +} + +// AddFailedCount adds v to the "failed_count" field. +func (u *EmailBroadcastUpsertOne) AddFailedCount(v int) *EmailBroadcastUpsertOne { + return u.Update(func(s *EmailBroadcastUpsert) { + s.AddFailedCount(v) + }) +} + +// UpdateFailedCount sets the "failed_count" field to the value that was provided on create. +func (u *EmailBroadcastUpsertOne) UpdateFailedCount() *EmailBroadcastUpsertOne { + return u.Update(func(s *EmailBroadcastUpsert) { + s.UpdateFailedCount() + }) +} + +// SetErrorMessage sets the "error_message" field. +func (u *EmailBroadcastUpsertOne) SetErrorMessage(v string) *EmailBroadcastUpsertOne { + return u.Update(func(s *EmailBroadcastUpsert) { + s.SetErrorMessage(v) + }) +} + +// UpdateErrorMessage sets the "error_message" field to the value that was provided on create. +func (u *EmailBroadcastUpsertOne) UpdateErrorMessage() *EmailBroadcastUpsertOne { + return u.Update(func(s *EmailBroadcastUpsert) { + s.UpdateErrorMessage() + }) +} + +// ClearErrorMessage clears the value of the "error_message" field. +func (u *EmailBroadcastUpsertOne) ClearErrorMessage() *EmailBroadcastUpsertOne { + return u.Update(func(s *EmailBroadcastUpsert) { + s.ClearErrorMessage() + }) +} + +// SetCreatedBy sets the "created_by" field. +func (u *EmailBroadcastUpsertOne) SetCreatedBy(v int64) *EmailBroadcastUpsertOne { + return u.Update(func(s *EmailBroadcastUpsert) { + s.SetCreatedBy(v) + }) +} + +// AddCreatedBy adds v to the "created_by" field. +func (u *EmailBroadcastUpsertOne) AddCreatedBy(v int64) *EmailBroadcastUpsertOne { + return u.Update(func(s *EmailBroadcastUpsert) { + s.AddCreatedBy(v) + }) +} + +// UpdateCreatedBy sets the "created_by" field to the value that was provided on create. +func (u *EmailBroadcastUpsertOne) UpdateCreatedBy() *EmailBroadcastUpsertOne { + return u.Update(func(s *EmailBroadcastUpsert) { + s.UpdateCreatedBy() + }) +} + +// ClearCreatedBy clears the value of the "created_by" field. +func (u *EmailBroadcastUpsertOne) ClearCreatedBy() *EmailBroadcastUpsertOne { + return u.Update(func(s *EmailBroadcastUpsert) { + s.ClearCreatedBy() + }) +} + +// SetStartedAt sets the "started_at" field. +func (u *EmailBroadcastUpsertOne) SetStartedAt(v time.Time) *EmailBroadcastUpsertOne { + return u.Update(func(s *EmailBroadcastUpsert) { + s.SetStartedAt(v) + }) +} + +// UpdateStartedAt sets the "started_at" field to the value that was provided on create. +func (u *EmailBroadcastUpsertOne) UpdateStartedAt() *EmailBroadcastUpsertOne { + return u.Update(func(s *EmailBroadcastUpsert) { + s.UpdateStartedAt() + }) +} + +// ClearStartedAt clears the value of the "started_at" field. +func (u *EmailBroadcastUpsertOne) ClearStartedAt() *EmailBroadcastUpsertOne { + return u.Update(func(s *EmailBroadcastUpsert) { + s.ClearStartedAt() + }) +} + +// SetFinishedAt sets the "finished_at" field. +func (u *EmailBroadcastUpsertOne) SetFinishedAt(v time.Time) *EmailBroadcastUpsertOne { + return u.Update(func(s *EmailBroadcastUpsert) { + s.SetFinishedAt(v) + }) +} + +// UpdateFinishedAt sets the "finished_at" field to the value that was provided on create. +func (u *EmailBroadcastUpsertOne) UpdateFinishedAt() *EmailBroadcastUpsertOne { + return u.Update(func(s *EmailBroadcastUpsert) { + s.UpdateFinishedAt() + }) +} + +// ClearFinishedAt clears the value of the "finished_at" field. +func (u *EmailBroadcastUpsertOne) ClearFinishedAt() *EmailBroadcastUpsertOne { + return u.Update(func(s *EmailBroadcastUpsert) { + s.ClearFinishedAt() + }) +} + +// SetUpdatedAt sets the "updated_at" field. +func (u *EmailBroadcastUpsertOne) SetUpdatedAt(v time.Time) *EmailBroadcastUpsertOne { + return u.Update(func(s *EmailBroadcastUpsert) { + s.SetUpdatedAt(v) + }) +} + +// UpdateUpdatedAt sets the "updated_at" field to the value that was provided on create. +func (u *EmailBroadcastUpsertOne) UpdateUpdatedAt() *EmailBroadcastUpsertOne { + return u.Update(func(s *EmailBroadcastUpsert) { + s.UpdateUpdatedAt() + }) +} + +// Exec executes the query. +func (u *EmailBroadcastUpsertOne) Exec(ctx context.Context) error { + if len(u.create.conflict) == 0 { + return errors.New("ent: missing options for EmailBroadcastCreate.OnConflict") + } + return u.create.Exec(ctx) +} + +// ExecX is like Exec, but panics if an error occurs. +func (u *EmailBroadcastUpsertOne) 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 *EmailBroadcastUpsertOne) ID(ctx context.Context) (id int64, 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 *EmailBroadcastUpsertOne) IDX(ctx context.Context) int64 { + id, err := u.ID(ctx) + if err != nil { + panic(err) + } + return id +} + +// EmailBroadcastCreateBulk is the builder for creating many EmailBroadcast entities in bulk. +type EmailBroadcastCreateBulk struct { + config + err error + builders []*EmailBroadcastCreate + conflict []sql.ConflictOption +} + +// Save creates the EmailBroadcast entities in the database. +func (_c *EmailBroadcastCreateBulk) Save(ctx context.Context) ([]*EmailBroadcast, error) { + if _c.err != nil { + return nil, _c.err + } + specs := make([]*sqlgraph.CreateSpec, len(_c.builders)) + nodes := make([]*EmailBroadcast, len(_c.builders)) + mutators := make([]Mutator, len(_c.builders)) + for i := range _c.builders { + func(i int, root context.Context) { + builder := _c.builders[i] + builder.defaults() + var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) { + mutation, ok := m.(*EmailBroadcastMutation) + 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, _c.builders[i+1].mutation) + } else { + spec := &sqlgraph.BatchCreateSpec{Nodes: specs} + spec.OnConflict = _c.conflict + // Invoke the actual operation on the latest mutation in the chain. + if err = sqlgraph.BatchCreate(ctx, _c.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 = int64(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, _c.builders[0].mutation); err != nil { + return nil, err + } + } + return nodes, nil +} + +// SaveX is like Save, but panics if an error occurs. +func (_c *EmailBroadcastCreateBulk) SaveX(ctx context.Context) []*EmailBroadcast { + v, err := _c.Save(ctx) + if err != nil { + panic(err) + } + return v +} + +// Exec executes the query. +func (_c *EmailBroadcastCreateBulk) Exec(ctx context.Context) error { + _, err := _c.Save(ctx) + return err +} + +// ExecX is like Exec, but panics if an error occurs. +func (_c *EmailBroadcastCreateBulk) ExecX(ctx context.Context) { + if err := _c.Exec(ctx); err != nil { + panic(err) + } +} + +// OnConflict allows configuring the `ON CONFLICT` / `ON DUPLICATE KEY` clause +// of the `INSERT` statement. For example: +// +// client.EmailBroadcast.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.EmailBroadcastUpsert) { +// SetSubject(v+v). +// }). +// Exec(ctx) +func (_c *EmailBroadcastCreateBulk) OnConflict(opts ...sql.ConflictOption) *EmailBroadcastUpsertBulk { + _c.conflict = opts + return &EmailBroadcastUpsertBulk{ + create: _c, + } +} + +// OnConflictColumns calls `OnConflict` and configures the columns +// as conflict target. Using this option is equivalent to using: +// +// client.EmailBroadcast.Create(). +// OnConflict(sql.ConflictColumns(columns...)). +// Exec(ctx) +func (_c *EmailBroadcastCreateBulk) OnConflictColumns(columns ...string) *EmailBroadcastUpsertBulk { + _c.conflict = append(_c.conflict, sql.ConflictColumns(columns...)) + return &EmailBroadcastUpsertBulk{ + create: _c, + } +} + +// EmailBroadcastUpsertBulk is the builder for "upsert"-ing +// a bulk of EmailBroadcast nodes. +type EmailBroadcastUpsertBulk struct { + create *EmailBroadcastCreateBulk +} + +// UpdateNewValues updates the mutable fields using the new values that +// were set on create. Using this option is equivalent to using: +// +// client.EmailBroadcast.Create(). +// OnConflict( +// sql.ResolveWithNewValues(), +// ). +// Exec(ctx) +func (u *EmailBroadcastUpsertBulk) UpdateNewValues() *EmailBroadcastUpsertBulk { + 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(emailbroadcast.FieldCreatedAt) + } + } + })) + return u +} + +// Ignore sets each column to itself in case of conflict. +// Using this option is equivalent to using: +// +// client.EmailBroadcast.Create(). +// OnConflict(sql.ResolveWithIgnore()). +// Exec(ctx) +func (u *EmailBroadcastUpsertBulk) Ignore() *EmailBroadcastUpsertBulk { + 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 *EmailBroadcastUpsertBulk) DoNothing() *EmailBroadcastUpsertBulk { + u.create.conflict = append(u.create.conflict, sql.DoNothing()) + return u +} + +// Update allows overriding fields `UPDATE` values. See the EmailBroadcastCreateBulk.OnConflict +// documentation for more info. +func (u *EmailBroadcastUpsertBulk) Update(set func(*EmailBroadcastUpsert)) *EmailBroadcastUpsertBulk { + u.create.conflict = append(u.create.conflict, sql.ResolveWith(func(update *sql.UpdateSet) { + set(&EmailBroadcastUpsert{UpdateSet: update}) + })) + return u +} + +// SetSubject sets the "subject" field. +func (u *EmailBroadcastUpsertBulk) SetSubject(v string) *EmailBroadcastUpsertBulk { + return u.Update(func(s *EmailBroadcastUpsert) { + s.SetSubject(v) + }) +} + +// UpdateSubject sets the "subject" field to the value that was provided on create. +func (u *EmailBroadcastUpsertBulk) UpdateSubject() *EmailBroadcastUpsertBulk { + return u.Update(func(s *EmailBroadcastUpsert) { + s.UpdateSubject() + }) +} + +// SetBody sets the "body" field. +func (u *EmailBroadcastUpsertBulk) SetBody(v string) *EmailBroadcastUpsertBulk { + return u.Update(func(s *EmailBroadcastUpsert) { + s.SetBody(v) + }) +} + +// UpdateBody sets the "body" field to the value that was provided on create. +func (u *EmailBroadcastUpsertBulk) UpdateBody() *EmailBroadcastUpsertBulk { + return u.Update(func(s *EmailBroadcastUpsert) { + s.UpdateBody() + }) +} + +// SetBodyFormat sets the "body_format" field. +func (u *EmailBroadcastUpsertBulk) SetBodyFormat(v string) *EmailBroadcastUpsertBulk { + return u.Update(func(s *EmailBroadcastUpsert) { + s.SetBodyFormat(v) + }) +} + +// UpdateBodyFormat sets the "body_format" field to the value that was provided on create. +func (u *EmailBroadcastUpsertBulk) UpdateBodyFormat() *EmailBroadcastUpsertBulk { + return u.Update(func(s *EmailBroadcastUpsert) { + s.UpdateBodyFormat() + }) +} + +// SetRecipientsMode sets the "recipients_mode" field. +func (u *EmailBroadcastUpsertBulk) SetRecipientsMode(v string) *EmailBroadcastUpsertBulk { + return u.Update(func(s *EmailBroadcastUpsert) { + s.SetRecipientsMode(v) + }) +} + +// UpdateRecipientsMode sets the "recipients_mode" field to the value that was provided on create. +func (u *EmailBroadcastUpsertBulk) UpdateRecipientsMode() *EmailBroadcastUpsertBulk { + return u.Update(func(s *EmailBroadcastUpsert) { + s.UpdateRecipientsMode() + }) +} + +// SetRecipientUserIds sets the "recipient_user_ids" field. +func (u *EmailBroadcastUpsertBulk) SetRecipientUserIds(v []int64) *EmailBroadcastUpsertBulk { + return u.Update(func(s *EmailBroadcastUpsert) { + s.SetRecipientUserIds(v) + }) +} + +// UpdateRecipientUserIds sets the "recipient_user_ids" field to the value that was provided on create. +func (u *EmailBroadcastUpsertBulk) UpdateRecipientUserIds() *EmailBroadcastUpsertBulk { + return u.Update(func(s *EmailBroadcastUpsert) { + s.UpdateRecipientUserIds() + }) +} + +// ClearRecipientUserIds clears the value of the "recipient_user_ids" field. +func (u *EmailBroadcastUpsertBulk) ClearRecipientUserIds() *EmailBroadcastUpsertBulk { + return u.Update(func(s *EmailBroadcastUpsert) { + s.ClearRecipientUserIds() + }) +} + +// SetStatus sets the "status" field. +func (u *EmailBroadcastUpsertBulk) SetStatus(v string) *EmailBroadcastUpsertBulk { + return u.Update(func(s *EmailBroadcastUpsert) { + s.SetStatus(v) + }) +} + +// UpdateStatus sets the "status" field to the value that was provided on create. +func (u *EmailBroadcastUpsertBulk) UpdateStatus() *EmailBroadcastUpsertBulk { + return u.Update(func(s *EmailBroadcastUpsert) { + s.UpdateStatus() + }) +} + +// SetTotalCount sets the "total_count" field. +func (u *EmailBroadcastUpsertBulk) SetTotalCount(v int) *EmailBroadcastUpsertBulk { + return u.Update(func(s *EmailBroadcastUpsert) { + s.SetTotalCount(v) + }) +} + +// AddTotalCount adds v to the "total_count" field. +func (u *EmailBroadcastUpsertBulk) AddTotalCount(v int) *EmailBroadcastUpsertBulk { + return u.Update(func(s *EmailBroadcastUpsert) { + s.AddTotalCount(v) + }) +} + +// UpdateTotalCount sets the "total_count" field to the value that was provided on create. +func (u *EmailBroadcastUpsertBulk) UpdateTotalCount() *EmailBroadcastUpsertBulk { + return u.Update(func(s *EmailBroadcastUpsert) { + s.UpdateTotalCount() + }) +} + +// SetSuccessCount sets the "success_count" field. +func (u *EmailBroadcastUpsertBulk) SetSuccessCount(v int) *EmailBroadcastUpsertBulk { + return u.Update(func(s *EmailBroadcastUpsert) { + s.SetSuccessCount(v) + }) +} + +// AddSuccessCount adds v to the "success_count" field. +func (u *EmailBroadcastUpsertBulk) AddSuccessCount(v int) *EmailBroadcastUpsertBulk { + return u.Update(func(s *EmailBroadcastUpsert) { + s.AddSuccessCount(v) + }) +} + +// UpdateSuccessCount sets the "success_count" field to the value that was provided on create. +func (u *EmailBroadcastUpsertBulk) UpdateSuccessCount() *EmailBroadcastUpsertBulk { + return u.Update(func(s *EmailBroadcastUpsert) { + s.UpdateSuccessCount() + }) +} + +// SetFailedCount sets the "failed_count" field. +func (u *EmailBroadcastUpsertBulk) SetFailedCount(v int) *EmailBroadcastUpsertBulk { + return u.Update(func(s *EmailBroadcastUpsert) { + s.SetFailedCount(v) + }) +} + +// AddFailedCount adds v to the "failed_count" field. +func (u *EmailBroadcastUpsertBulk) AddFailedCount(v int) *EmailBroadcastUpsertBulk { + return u.Update(func(s *EmailBroadcastUpsert) { + s.AddFailedCount(v) + }) +} + +// UpdateFailedCount sets the "failed_count" field to the value that was provided on create. +func (u *EmailBroadcastUpsertBulk) UpdateFailedCount() *EmailBroadcastUpsertBulk { + return u.Update(func(s *EmailBroadcastUpsert) { + s.UpdateFailedCount() + }) +} + +// SetErrorMessage sets the "error_message" field. +func (u *EmailBroadcastUpsertBulk) SetErrorMessage(v string) *EmailBroadcastUpsertBulk { + return u.Update(func(s *EmailBroadcastUpsert) { + s.SetErrorMessage(v) + }) +} + +// UpdateErrorMessage sets the "error_message" field to the value that was provided on create. +func (u *EmailBroadcastUpsertBulk) UpdateErrorMessage() *EmailBroadcastUpsertBulk { + return u.Update(func(s *EmailBroadcastUpsert) { + s.UpdateErrorMessage() + }) +} + +// ClearErrorMessage clears the value of the "error_message" field. +func (u *EmailBroadcastUpsertBulk) ClearErrorMessage() *EmailBroadcastUpsertBulk { + return u.Update(func(s *EmailBroadcastUpsert) { + s.ClearErrorMessage() + }) +} + +// SetCreatedBy sets the "created_by" field. +func (u *EmailBroadcastUpsertBulk) SetCreatedBy(v int64) *EmailBroadcastUpsertBulk { + return u.Update(func(s *EmailBroadcastUpsert) { + s.SetCreatedBy(v) + }) +} + +// AddCreatedBy adds v to the "created_by" field. +func (u *EmailBroadcastUpsertBulk) AddCreatedBy(v int64) *EmailBroadcastUpsertBulk { + return u.Update(func(s *EmailBroadcastUpsert) { + s.AddCreatedBy(v) + }) +} + +// UpdateCreatedBy sets the "created_by" field to the value that was provided on create. +func (u *EmailBroadcastUpsertBulk) UpdateCreatedBy() *EmailBroadcastUpsertBulk { + return u.Update(func(s *EmailBroadcastUpsert) { + s.UpdateCreatedBy() + }) +} + +// ClearCreatedBy clears the value of the "created_by" field. +func (u *EmailBroadcastUpsertBulk) ClearCreatedBy() *EmailBroadcastUpsertBulk { + return u.Update(func(s *EmailBroadcastUpsert) { + s.ClearCreatedBy() + }) +} + +// SetStartedAt sets the "started_at" field. +func (u *EmailBroadcastUpsertBulk) SetStartedAt(v time.Time) *EmailBroadcastUpsertBulk { + return u.Update(func(s *EmailBroadcastUpsert) { + s.SetStartedAt(v) + }) +} + +// UpdateStartedAt sets the "started_at" field to the value that was provided on create. +func (u *EmailBroadcastUpsertBulk) UpdateStartedAt() *EmailBroadcastUpsertBulk { + return u.Update(func(s *EmailBroadcastUpsert) { + s.UpdateStartedAt() + }) +} + +// ClearStartedAt clears the value of the "started_at" field. +func (u *EmailBroadcastUpsertBulk) ClearStartedAt() *EmailBroadcastUpsertBulk { + return u.Update(func(s *EmailBroadcastUpsert) { + s.ClearStartedAt() + }) +} + +// SetFinishedAt sets the "finished_at" field. +func (u *EmailBroadcastUpsertBulk) SetFinishedAt(v time.Time) *EmailBroadcastUpsertBulk { + return u.Update(func(s *EmailBroadcastUpsert) { + s.SetFinishedAt(v) + }) +} + +// UpdateFinishedAt sets the "finished_at" field to the value that was provided on create. +func (u *EmailBroadcastUpsertBulk) UpdateFinishedAt() *EmailBroadcastUpsertBulk { + return u.Update(func(s *EmailBroadcastUpsert) { + s.UpdateFinishedAt() + }) +} + +// ClearFinishedAt clears the value of the "finished_at" field. +func (u *EmailBroadcastUpsertBulk) ClearFinishedAt() *EmailBroadcastUpsertBulk { + return u.Update(func(s *EmailBroadcastUpsert) { + s.ClearFinishedAt() + }) +} + +// SetUpdatedAt sets the "updated_at" field. +func (u *EmailBroadcastUpsertBulk) SetUpdatedAt(v time.Time) *EmailBroadcastUpsertBulk { + return u.Update(func(s *EmailBroadcastUpsert) { + s.SetUpdatedAt(v) + }) +} + +// UpdateUpdatedAt sets the "updated_at" field to the value that was provided on create. +func (u *EmailBroadcastUpsertBulk) UpdateUpdatedAt() *EmailBroadcastUpsertBulk { + return u.Update(func(s *EmailBroadcastUpsert) { + s.UpdateUpdatedAt() + }) +} + +// Exec executes the query. +func (u *EmailBroadcastUpsertBulk) 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 EmailBroadcastCreateBulk instead", i) + } + } + if len(u.create.conflict) == 0 { + return errors.New("ent: missing options for EmailBroadcastCreateBulk.OnConflict") + } + return u.create.Exec(ctx) +} + +// ExecX is like Exec, but panics if an error occurs. +func (u *EmailBroadcastUpsertBulk) ExecX(ctx context.Context) { + if err := u.create.Exec(ctx); err != nil { + panic(err) + } +} diff --git a/backend/ent/emailbroadcast_delete.go b/backend/ent/emailbroadcast_delete.go new file mode 100644 index 00000000000..f9ecc53c375 --- /dev/null +++ b/backend/ent/emailbroadcast_delete.go @@ -0,0 +1,88 @@ +// Code generated by ent, DO NOT EDIT. + +package ent + +import ( + "context" + + "entgo.io/ent/dialect/sql" + "entgo.io/ent/dialect/sql/sqlgraph" + "entgo.io/ent/schema/field" + "github.com/Wei-Shaw/sub2api/ent/emailbroadcast" + "github.com/Wei-Shaw/sub2api/ent/predicate" +) + +// EmailBroadcastDelete is the builder for deleting a EmailBroadcast entity. +type EmailBroadcastDelete struct { + config + hooks []Hook + mutation *EmailBroadcastMutation +} + +// Where appends a list predicates to the EmailBroadcastDelete builder. +func (_d *EmailBroadcastDelete) Where(ps ...predicate.EmailBroadcast) *EmailBroadcastDelete { + _d.mutation.Where(ps...) + return _d +} + +// Exec executes the deletion query and returns how many vertices were deleted. +func (_d *EmailBroadcastDelete) Exec(ctx context.Context) (int, error) { + return withHooks(ctx, _d.sqlExec, _d.mutation, _d.hooks) +} + +// ExecX is like Exec, but panics if an error occurs. +func (_d *EmailBroadcastDelete) ExecX(ctx context.Context) int { + n, err := _d.Exec(ctx) + if err != nil { + panic(err) + } + return n +} + +func (_d *EmailBroadcastDelete) sqlExec(ctx context.Context) (int, error) { + _spec := sqlgraph.NewDeleteSpec(emailbroadcast.Table, sqlgraph.NewFieldSpec(emailbroadcast.FieldID, field.TypeInt64)) + if ps := _d.mutation.predicates; len(ps) > 0 { + _spec.Predicate = func(selector *sql.Selector) { + for i := range ps { + ps[i](selector) + } + } + } + affected, err := sqlgraph.DeleteNodes(ctx, _d.driver, _spec) + if err != nil && sqlgraph.IsConstraintError(err) { + err = &ConstraintError{msg: err.Error(), wrap: err} + } + _d.mutation.done = true + return affected, err +} + +// EmailBroadcastDeleteOne is the builder for deleting a single EmailBroadcast entity. +type EmailBroadcastDeleteOne struct { + _d *EmailBroadcastDelete +} + +// Where appends a list predicates to the EmailBroadcastDelete builder. +func (_d *EmailBroadcastDeleteOne) Where(ps ...predicate.EmailBroadcast) *EmailBroadcastDeleteOne { + _d._d.mutation.Where(ps...) + return _d +} + +// Exec executes the deletion query. +func (_d *EmailBroadcastDeleteOne) Exec(ctx context.Context) error { + n, err := _d._d.Exec(ctx) + switch { + case err != nil: + return err + case n == 0: + return &NotFoundError{emailbroadcast.Label} + default: + return nil + } +} + +// ExecX is like Exec, but panics if an error occurs. +func (_d *EmailBroadcastDeleteOne) ExecX(ctx context.Context) { + if err := _d.Exec(ctx); err != nil { + panic(err) + } +} diff --git a/backend/ent/emailbroadcast_query.go b/backend/ent/emailbroadcast_query.go new file mode 100644 index 00000000000..97b42dc671b --- /dev/null +++ b/backend/ent/emailbroadcast_query.go @@ -0,0 +1,564 @@ +// Code generated by ent, DO NOT EDIT. + +package ent + +import ( + "context" + "fmt" + "math" + + "entgo.io/ent" + "entgo.io/ent/dialect" + "entgo.io/ent/dialect/sql" + "entgo.io/ent/dialect/sql/sqlgraph" + "entgo.io/ent/schema/field" + "github.com/Wei-Shaw/sub2api/ent/emailbroadcast" + "github.com/Wei-Shaw/sub2api/ent/predicate" +) + +// EmailBroadcastQuery is the builder for querying EmailBroadcast entities. +type EmailBroadcastQuery struct { + config + ctx *QueryContext + order []emailbroadcast.OrderOption + inters []Interceptor + predicates []predicate.EmailBroadcast + modifiers []func(*sql.Selector) + // intermediate query (i.e. traversal path). + sql *sql.Selector + path func(context.Context) (*sql.Selector, error) +} + +// Where adds a new predicate for the EmailBroadcastQuery builder. +func (_q *EmailBroadcastQuery) Where(ps ...predicate.EmailBroadcast) *EmailBroadcastQuery { + _q.predicates = append(_q.predicates, ps...) + return _q +} + +// Limit the number of records to be returned by this query. +func (_q *EmailBroadcastQuery) Limit(limit int) *EmailBroadcastQuery { + _q.ctx.Limit = &limit + return _q +} + +// Offset to start from. +func (_q *EmailBroadcastQuery) Offset(offset int) *EmailBroadcastQuery { + _q.ctx.Offset = &offset + return _q +} + +// 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 (_q *EmailBroadcastQuery) Unique(unique bool) *EmailBroadcastQuery { + _q.ctx.Unique = &unique + return _q +} + +// Order specifies how the records should be ordered. +func (_q *EmailBroadcastQuery) Order(o ...emailbroadcast.OrderOption) *EmailBroadcastQuery { + _q.order = append(_q.order, o...) + return _q +} + +// First returns the first EmailBroadcast entity from the query. +// Returns a *NotFoundError when no EmailBroadcast was found. +func (_q *EmailBroadcastQuery) First(ctx context.Context) (*EmailBroadcast, error) { + nodes, err := _q.Limit(1).All(setContextOp(ctx, _q.ctx, ent.OpQueryFirst)) + if err != nil { + return nil, err + } + if len(nodes) == 0 { + return nil, &NotFoundError{emailbroadcast.Label} + } + return nodes[0], nil +} + +// FirstX is like First, but panics if an error occurs. +func (_q *EmailBroadcastQuery) FirstX(ctx context.Context) *EmailBroadcast { + node, err := _q.First(ctx) + if err != nil && !IsNotFound(err) { + panic(err) + } + return node +} + +// FirstID returns the first EmailBroadcast ID from the query. +// Returns a *NotFoundError when no EmailBroadcast ID was found. +func (_q *EmailBroadcastQuery) FirstID(ctx context.Context) (id int64, err error) { + var ids []int64 + if ids, err = _q.Limit(1).IDs(setContextOp(ctx, _q.ctx, ent.OpQueryFirstID)); err != nil { + return + } + if len(ids) == 0 { + err = &NotFoundError{emailbroadcast.Label} + return + } + return ids[0], nil +} + +// FirstIDX is like FirstID, but panics if an error occurs. +func (_q *EmailBroadcastQuery) FirstIDX(ctx context.Context) int64 { + id, err := _q.FirstID(ctx) + if err != nil && !IsNotFound(err) { + panic(err) + } + return id +} + +// Only returns a single EmailBroadcast entity found by the query, ensuring it only returns one. +// Returns a *NotSingularError when more than one EmailBroadcast entity is found. +// Returns a *NotFoundError when no EmailBroadcast entities are found. +func (_q *EmailBroadcastQuery) Only(ctx context.Context) (*EmailBroadcast, error) { + nodes, err := _q.Limit(2).All(setContextOp(ctx, _q.ctx, ent.OpQueryOnly)) + if err != nil { + return nil, err + } + switch len(nodes) { + case 1: + return nodes[0], nil + case 0: + return nil, &NotFoundError{emailbroadcast.Label} + default: + return nil, &NotSingularError{emailbroadcast.Label} + } +} + +// OnlyX is like Only, but panics if an error occurs. +func (_q *EmailBroadcastQuery) OnlyX(ctx context.Context) *EmailBroadcast { + node, err := _q.Only(ctx) + if err != nil { + panic(err) + } + return node +} + +// OnlyID is like Only, but returns the only EmailBroadcast ID in the query. +// Returns a *NotSingularError when more than one EmailBroadcast ID is found. +// Returns a *NotFoundError when no entities are found. +func (_q *EmailBroadcastQuery) OnlyID(ctx context.Context) (id int64, err error) { + var ids []int64 + if ids, err = _q.Limit(2).IDs(setContextOp(ctx, _q.ctx, ent.OpQueryOnlyID)); err != nil { + return + } + switch len(ids) { + case 1: + id = ids[0] + case 0: + err = &NotFoundError{emailbroadcast.Label} + default: + err = &NotSingularError{emailbroadcast.Label} + } + return +} + +// OnlyIDX is like OnlyID, but panics if an error occurs. +func (_q *EmailBroadcastQuery) OnlyIDX(ctx context.Context) int64 { + id, err := _q.OnlyID(ctx) + if err != nil { + panic(err) + } + return id +} + +// All executes the query and returns a list of EmailBroadcasts. +func (_q *EmailBroadcastQuery) All(ctx context.Context) ([]*EmailBroadcast, error) { + ctx = setContextOp(ctx, _q.ctx, ent.OpQueryAll) + if err := _q.prepareQuery(ctx); err != nil { + return nil, err + } + qr := querierAll[[]*EmailBroadcast, *EmailBroadcastQuery]() + return withInterceptors[[]*EmailBroadcast](ctx, _q, qr, _q.inters) +} + +// AllX is like All, but panics if an error occurs. +func (_q *EmailBroadcastQuery) AllX(ctx context.Context) []*EmailBroadcast { + nodes, err := _q.All(ctx) + if err != nil { + panic(err) + } + return nodes +} + +// IDs executes the query and returns a list of EmailBroadcast IDs. +func (_q *EmailBroadcastQuery) IDs(ctx context.Context) (ids []int64, err error) { + if _q.ctx.Unique == nil && _q.path != nil { + _q.Unique(true) + } + ctx = setContextOp(ctx, _q.ctx, ent.OpQueryIDs) + if err = _q.Select(emailbroadcast.FieldID).Scan(ctx, &ids); err != nil { + return nil, err + } + return ids, nil +} + +// IDsX is like IDs, but panics if an error occurs. +func (_q *EmailBroadcastQuery) IDsX(ctx context.Context) []int64 { + ids, err := _q.IDs(ctx) + if err != nil { + panic(err) + } + return ids +} + +// Count returns the count of the given query. +func (_q *EmailBroadcastQuery) Count(ctx context.Context) (int, error) { + ctx = setContextOp(ctx, _q.ctx, ent.OpQueryCount) + if err := _q.prepareQuery(ctx); err != nil { + return 0, err + } + return withInterceptors[int](ctx, _q, querierCount[*EmailBroadcastQuery](), _q.inters) +} + +// CountX is like Count, but panics if an error occurs. +func (_q *EmailBroadcastQuery) CountX(ctx context.Context) int { + count, err := _q.Count(ctx) + if err != nil { + panic(err) + } + return count +} + +// Exist returns true if the query has elements in the graph. +func (_q *EmailBroadcastQuery) Exist(ctx context.Context) (bool, error) { + ctx = setContextOp(ctx, _q.ctx, ent.OpQueryExist) + switch _, err := _q.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 (_q *EmailBroadcastQuery) ExistX(ctx context.Context) bool { + exist, err := _q.Exist(ctx) + if err != nil { + panic(err) + } + return exist +} + +// Clone returns a duplicate of the EmailBroadcastQuery builder, including all associated steps. It can be +// used to prepare common query builders and use them differently after the clone is made. +func (_q *EmailBroadcastQuery) Clone() *EmailBroadcastQuery { + if _q == nil { + return nil + } + return &EmailBroadcastQuery{ + config: _q.config, + ctx: _q.ctx.Clone(), + order: append([]emailbroadcast.OrderOption{}, _q.order...), + inters: append([]Interceptor{}, _q.inters...), + predicates: append([]predicate.EmailBroadcast{}, _q.predicates...), + // clone intermediate query. + sql: _q.sql.Clone(), + path: _q.path, + } +} + +// GroupBy is used to group vertices by one or more fields/columns. +// It is often used with aggregate functions, like: count, max, mean, min, sum. +// +// Example: +// +// var v []struct { +// Subject string `json:"subject,omitempty"` +// Count int `json:"count,omitempty"` +// } +// +// client.EmailBroadcast.Query(). +// GroupBy(emailbroadcast.FieldSubject). +// Aggregate(ent.Count()). +// Scan(ctx, &v) +func (_q *EmailBroadcastQuery) GroupBy(field string, fields ...string) *EmailBroadcastGroupBy { + _q.ctx.Fields = append([]string{field}, fields...) + grbuild := &EmailBroadcastGroupBy{build: _q} + grbuild.flds = &_q.ctx.Fields + grbuild.label = emailbroadcast.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 { +// Subject string `json:"subject,omitempty"` +// } +// +// client.EmailBroadcast.Query(). +// Select(emailbroadcast.FieldSubject). +// Scan(ctx, &v) +func (_q *EmailBroadcastQuery) Select(fields ...string) *EmailBroadcastSelect { + _q.ctx.Fields = append(_q.ctx.Fields, fields...) + sbuild := &EmailBroadcastSelect{EmailBroadcastQuery: _q} + sbuild.label = emailbroadcast.Label + sbuild.flds, sbuild.scan = &_q.ctx.Fields, sbuild.Scan + return sbuild +} + +// Aggregate returns a EmailBroadcastSelect configured with the given aggregations. +func (_q *EmailBroadcastQuery) Aggregate(fns ...AggregateFunc) *EmailBroadcastSelect { + return _q.Select().Aggregate(fns...) +} + +func (_q *EmailBroadcastQuery) prepareQuery(ctx context.Context) error { + for _, inter := range _q.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, _q); err != nil { + return err + } + } + } + for _, f := range _q.ctx.Fields { + if !emailbroadcast.ValidColumn(f) { + return &ValidationError{Name: f, err: fmt.Errorf("ent: invalid field %q for query", f)} + } + } + if _q.path != nil { + prev, err := _q.path(ctx) + if err != nil { + return err + } + _q.sql = prev + } + return nil +} + +func (_q *EmailBroadcastQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*EmailBroadcast, error) { + var ( + nodes = []*EmailBroadcast{} + _spec = _q.querySpec() + ) + _spec.ScanValues = func(columns []string) ([]any, error) { + return (*EmailBroadcast).scanValues(nil, columns) + } + _spec.Assign = func(columns []string, values []any) error { + node := &EmailBroadcast{config: _q.config} + nodes = append(nodes, node) + return node.assignValues(columns, values) + } + if len(_q.modifiers) > 0 { + _spec.Modifiers = _q.modifiers + } + for i := range hooks { + hooks[i](ctx, _spec) + } + if err := sqlgraph.QueryNodes(ctx, _q.driver, _spec); err != nil { + return nil, err + } + if len(nodes) == 0 { + return nodes, nil + } + return nodes, nil +} + +func (_q *EmailBroadcastQuery) sqlCount(ctx context.Context) (int, error) { + _spec := _q.querySpec() + if len(_q.modifiers) > 0 { + _spec.Modifiers = _q.modifiers + } + _spec.Node.Columns = _q.ctx.Fields + if len(_q.ctx.Fields) > 0 { + _spec.Unique = _q.ctx.Unique != nil && *_q.ctx.Unique + } + return sqlgraph.CountNodes(ctx, _q.driver, _spec) +} + +func (_q *EmailBroadcastQuery) querySpec() *sqlgraph.QuerySpec { + _spec := sqlgraph.NewQuerySpec(emailbroadcast.Table, emailbroadcast.Columns, sqlgraph.NewFieldSpec(emailbroadcast.FieldID, field.TypeInt64)) + _spec.From = _q.sql + if unique := _q.ctx.Unique; unique != nil { + _spec.Unique = *unique + } else if _q.path != nil { + _spec.Unique = true + } + if fields := _q.ctx.Fields; len(fields) > 0 { + _spec.Node.Columns = make([]string, 0, len(fields)) + _spec.Node.Columns = append(_spec.Node.Columns, emailbroadcast.FieldID) + for i := range fields { + if fields[i] != emailbroadcast.FieldID { + _spec.Node.Columns = append(_spec.Node.Columns, fields[i]) + } + } + } + if ps := _q.predicates; len(ps) > 0 { + _spec.Predicate = func(selector *sql.Selector) { + for i := range ps { + ps[i](selector) + } + } + } + if limit := _q.ctx.Limit; limit != nil { + _spec.Limit = *limit + } + if offset := _q.ctx.Offset; offset != nil { + _spec.Offset = *offset + } + if ps := _q.order; len(ps) > 0 { + _spec.Order = func(selector *sql.Selector) { + for i := range ps { + ps[i](selector) + } + } + } + return _spec +} + +func (_q *EmailBroadcastQuery) sqlQuery(ctx context.Context) *sql.Selector { + builder := sql.Dialect(_q.driver.Dialect()) + t1 := builder.Table(emailbroadcast.Table) + columns := _q.ctx.Fields + if len(columns) == 0 { + columns = emailbroadcast.Columns + } + selector := builder.Select(t1.Columns(columns...)...).From(t1) + if _q.sql != nil { + selector = _q.sql + selector.Select(selector.Columns(columns...)...) + } + if _q.ctx.Unique != nil && *_q.ctx.Unique { + selector.Distinct() + } + for _, m := range _q.modifiers { + m(selector) + } + for _, p := range _q.predicates { + p(selector) + } + for _, p := range _q.order { + p(selector) + } + if offset := _q.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 := _q.ctx.Limit; limit != nil { + selector.Limit(*limit) + } + return selector +} + +// ForUpdate locks the selected rows against concurrent updates, and prevent them from being +// updated, deleted or "selected ... for update" by other sessions, until the transaction is +// either committed or rolled-back. +func (_q *EmailBroadcastQuery) ForUpdate(opts ...sql.LockOption) *EmailBroadcastQuery { + if _q.driver.Dialect() == dialect.Postgres { + _q.Unique(false) + } + _q.modifiers = append(_q.modifiers, func(s *sql.Selector) { + s.ForUpdate(opts...) + }) + return _q +} + +// ForShare behaves similarly to ForUpdate, except that it acquires a shared mode lock +// on any rows that are read. Other sessions can read the rows, but cannot modify them +// until your transaction commits. +func (_q *EmailBroadcastQuery) ForShare(opts ...sql.LockOption) *EmailBroadcastQuery { + if _q.driver.Dialect() == dialect.Postgres { + _q.Unique(false) + } + _q.modifiers = append(_q.modifiers, func(s *sql.Selector) { + s.ForShare(opts...) + }) + return _q +} + +// EmailBroadcastGroupBy is the group-by builder for EmailBroadcast entities. +type EmailBroadcastGroupBy struct { + selector + build *EmailBroadcastQuery +} + +// Aggregate adds the given aggregation functions to the group-by query. +func (_g *EmailBroadcastGroupBy) Aggregate(fns ...AggregateFunc) *EmailBroadcastGroupBy { + _g.fns = append(_g.fns, fns...) + return _g +} + +// Scan applies the selector query and scans the result into the given value. +func (_g *EmailBroadcastGroupBy) Scan(ctx context.Context, v any) error { + ctx = setContextOp(ctx, _g.build.ctx, ent.OpQueryGroupBy) + if err := _g.build.prepareQuery(ctx); err != nil { + return err + } + return scanWithInterceptors[*EmailBroadcastQuery, *EmailBroadcastGroupBy](ctx, _g.build, _g, _g.build.inters, v) +} + +func (_g *EmailBroadcastGroupBy) sqlScan(ctx context.Context, root *EmailBroadcastQuery, v any) error { + selector := root.sqlQuery(ctx).Select() + aggregation := make([]string, 0, len(_g.fns)) + for _, fn := range _g.fns { + aggregation = append(aggregation, fn(selector)) + } + if len(selector.SelectedColumns()) == 0 { + columns := make([]string, 0, len(*_g.flds)+len(_g.fns)) + for _, f := range *_g.flds { + columns = append(columns, selector.C(f)) + } + columns = append(columns, aggregation...) + selector.Select(columns...) + } + selector.GroupBy(selector.Columns(*_g.flds...)...) + if err := selector.Err(); err != nil { + return err + } + rows := &sql.Rows{} + query, args := selector.Query() + if err := _g.build.driver.Query(ctx, query, args, rows); err != nil { + return err + } + defer rows.Close() + return sql.ScanSlice(rows, v) +} + +// EmailBroadcastSelect is the builder for selecting fields of EmailBroadcast entities. +type EmailBroadcastSelect struct { + *EmailBroadcastQuery + selector +} + +// Aggregate adds the given aggregation functions to the selector query. +func (_s *EmailBroadcastSelect) Aggregate(fns ...AggregateFunc) *EmailBroadcastSelect { + _s.fns = append(_s.fns, fns...) + return _s +} + +// Scan applies the selector query and scans the result into the given value. +func (_s *EmailBroadcastSelect) Scan(ctx context.Context, v any) error { + ctx = setContextOp(ctx, _s.ctx, ent.OpQuerySelect) + if err := _s.prepareQuery(ctx); err != nil { + return err + } + return scanWithInterceptors[*EmailBroadcastQuery, *EmailBroadcastSelect](ctx, _s.EmailBroadcastQuery, _s, _s.inters, v) +} + +func (_s *EmailBroadcastSelect) sqlScan(ctx context.Context, root *EmailBroadcastQuery, v any) error { + selector := root.sqlQuery(ctx) + aggregation := make([]string, 0, len(_s.fns)) + for _, fn := range _s.fns { + aggregation = append(aggregation, fn(selector)) + } + switch n := len(*_s.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 := _s.driver.Query(ctx, query, args, rows); err != nil { + return err + } + defer rows.Close() + return sql.ScanSlice(rows, v) +} diff --git a/backend/ent/emailbroadcast_update.go b/backend/ent/emailbroadcast_update.go new file mode 100644 index 00000000000..86670313260 --- /dev/null +++ b/backend/ent/emailbroadcast_update.go @@ -0,0 +1,927 @@ +// 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/dialect/sql/sqljson" + "entgo.io/ent/schema/field" + "github.com/Wei-Shaw/sub2api/ent/emailbroadcast" + "github.com/Wei-Shaw/sub2api/ent/predicate" +) + +// EmailBroadcastUpdate is the builder for updating EmailBroadcast entities. +type EmailBroadcastUpdate struct { + config + hooks []Hook + mutation *EmailBroadcastMutation +} + +// Where appends a list predicates to the EmailBroadcastUpdate builder. +func (_u *EmailBroadcastUpdate) Where(ps ...predicate.EmailBroadcast) *EmailBroadcastUpdate { + _u.mutation.Where(ps...) + return _u +} + +// SetSubject sets the "subject" field. +func (_u *EmailBroadcastUpdate) SetSubject(v string) *EmailBroadcastUpdate { + _u.mutation.SetSubject(v) + return _u +} + +// SetNillableSubject sets the "subject" field if the given value is not nil. +func (_u *EmailBroadcastUpdate) SetNillableSubject(v *string) *EmailBroadcastUpdate { + if v != nil { + _u.SetSubject(*v) + } + return _u +} + +// SetBody sets the "body" field. +func (_u *EmailBroadcastUpdate) SetBody(v string) *EmailBroadcastUpdate { + _u.mutation.SetBody(v) + return _u +} + +// SetNillableBody sets the "body" field if the given value is not nil. +func (_u *EmailBroadcastUpdate) SetNillableBody(v *string) *EmailBroadcastUpdate { + if v != nil { + _u.SetBody(*v) + } + return _u +} + +// SetBodyFormat sets the "body_format" field. +func (_u *EmailBroadcastUpdate) SetBodyFormat(v string) *EmailBroadcastUpdate { + _u.mutation.SetBodyFormat(v) + return _u +} + +// SetNillableBodyFormat sets the "body_format" field if the given value is not nil. +func (_u *EmailBroadcastUpdate) SetNillableBodyFormat(v *string) *EmailBroadcastUpdate { + if v != nil { + _u.SetBodyFormat(*v) + } + return _u +} + +// SetRecipientsMode sets the "recipients_mode" field. +func (_u *EmailBroadcastUpdate) SetRecipientsMode(v string) *EmailBroadcastUpdate { + _u.mutation.SetRecipientsMode(v) + return _u +} + +// SetNillableRecipientsMode sets the "recipients_mode" field if the given value is not nil. +func (_u *EmailBroadcastUpdate) SetNillableRecipientsMode(v *string) *EmailBroadcastUpdate { + if v != nil { + _u.SetRecipientsMode(*v) + } + return _u +} + +// SetRecipientUserIds sets the "recipient_user_ids" field. +func (_u *EmailBroadcastUpdate) SetRecipientUserIds(v []int64) *EmailBroadcastUpdate { + _u.mutation.SetRecipientUserIds(v) + return _u +} + +// AppendRecipientUserIds appends value to the "recipient_user_ids" field. +func (_u *EmailBroadcastUpdate) AppendRecipientUserIds(v []int64) *EmailBroadcastUpdate { + _u.mutation.AppendRecipientUserIds(v) + return _u +} + +// ClearRecipientUserIds clears the value of the "recipient_user_ids" field. +func (_u *EmailBroadcastUpdate) ClearRecipientUserIds() *EmailBroadcastUpdate { + _u.mutation.ClearRecipientUserIds() + return _u +} + +// SetStatus sets the "status" field. +func (_u *EmailBroadcastUpdate) SetStatus(v string) *EmailBroadcastUpdate { + _u.mutation.SetStatus(v) + return _u +} + +// SetNillableStatus sets the "status" field if the given value is not nil. +func (_u *EmailBroadcastUpdate) SetNillableStatus(v *string) *EmailBroadcastUpdate { + if v != nil { + _u.SetStatus(*v) + } + return _u +} + +// SetTotalCount sets the "total_count" field. +func (_u *EmailBroadcastUpdate) SetTotalCount(v int) *EmailBroadcastUpdate { + _u.mutation.ResetTotalCount() + _u.mutation.SetTotalCount(v) + return _u +} + +// SetNillableTotalCount sets the "total_count" field if the given value is not nil. +func (_u *EmailBroadcastUpdate) SetNillableTotalCount(v *int) *EmailBroadcastUpdate { + if v != nil { + _u.SetTotalCount(*v) + } + return _u +} + +// AddTotalCount adds value to the "total_count" field. +func (_u *EmailBroadcastUpdate) AddTotalCount(v int) *EmailBroadcastUpdate { + _u.mutation.AddTotalCount(v) + return _u +} + +// SetSuccessCount sets the "success_count" field. +func (_u *EmailBroadcastUpdate) SetSuccessCount(v int) *EmailBroadcastUpdate { + _u.mutation.ResetSuccessCount() + _u.mutation.SetSuccessCount(v) + return _u +} + +// SetNillableSuccessCount sets the "success_count" field if the given value is not nil. +func (_u *EmailBroadcastUpdate) SetNillableSuccessCount(v *int) *EmailBroadcastUpdate { + if v != nil { + _u.SetSuccessCount(*v) + } + return _u +} + +// AddSuccessCount adds value to the "success_count" field. +func (_u *EmailBroadcastUpdate) AddSuccessCount(v int) *EmailBroadcastUpdate { + _u.mutation.AddSuccessCount(v) + return _u +} + +// SetFailedCount sets the "failed_count" field. +func (_u *EmailBroadcastUpdate) SetFailedCount(v int) *EmailBroadcastUpdate { + _u.mutation.ResetFailedCount() + _u.mutation.SetFailedCount(v) + return _u +} + +// SetNillableFailedCount sets the "failed_count" field if the given value is not nil. +func (_u *EmailBroadcastUpdate) SetNillableFailedCount(v *int) *EmailBroadcastUpdate { + if v != nil { + _u.SetFailedCount(*v) + } + return _u +} + +// AddFailedCount adds value to the "failed_count" field. +func (_u *EmailBroadcastUpdate) AddFailedCount(v int) *EmailBroadcastUpdate { + _u.mutation.AddFailedCount(v) + return _u +} + +// SetErrorMessage sets the "error_message" field. +func (_u *EmailBroadcastUpdate) SetErrorMessage(v string) *EmailBroadcastUpdate { + _u.mutation.SetErrorMessage(v) + return _u +} + +// SetNillableErrorMessage sets the "error_message" field if the given value is not nil. +func (_u *EmailBroadcastUpdate) SetNillableErrorMessage(v *string) *EmailBroadcastUpdate { + if v != nil { + _u.SetErrorMessage(*v) + } + return _u +} + +// ClearErrorMessage clears the value of the "error_message" field. +func (_u *EmailBroadcastUpdate) ClearErrorMessage() *EmailBroadcastUpdate { + _u.mutation.ClearErrorMessage() + return _u +} + +// SetCreatedBy sets the "created_by" field. +func (_u *EmailBroadcastUpdate) SetCreatedBy(v int64) *EmailBroadcastUpdate { + _u.mutation.ResetCreatedBy() + _u.mutation.SetCreatedBy(v) + return _u +} + +// SetNillableCreatedBy sets the "created_by" field if the given value is not nil. +func (_u *EmailBroadcastUpdate) SetNillableCreatedBy(v *int64) *EmailBroadcastUpdate { + if v != nil { + _u.SetCreatedBy(*v) + } + return _u +} + +// AddCreatedBy adds value to the "created_by" field. +func (_u *EmailBroadcastUpdate) AddCreatedBy(v int64) *EmailBroadcastUpdate { + _u.mutation.AddCreatedBy(v) + return _u +} + +// ClearCreatedBy clears the value of the "created_by" field. +func (_u *EmailBroadcastUpdate) ClearCreatedBy() *EmailBroadcastUpdate { + _u.mutation.ClearCreatedBy() + return _u +} + +// SetStartedAt sets the "started_at" field. +func (_u *EmailBroadcastUpdate) SetStartedAt(v time.Time) *EmailBroadcastUpdate { + _u.mutation.SetStartedAt(v) + return _u +} + +// SetNillableStartedAt sets the "started_at" field if the given value is not nil. +func (_u *EmailBroadcastUpdate) SetNillableStartedAt(v *time.Time) *EmailBroadcastUpdate { + if v != nil { + _u.SetStartedAt(*v) + } + return _u +} + +// ClearStartedAt clears the value of the "started_at" field. +func (_u *EmailBroadcastUpdate) ClearStartedAt() *EmailBroadcastUpdate { + _u.mutation.ClearStartedAt() + return _u +} + +// SetFinishedAt sets the "finished_at" field. +func (_u *EmailBroadcastUpdate) SetFinishedAt(v time.Time) *EmailBroadcastUpdate { + _u.mutation.SetFinishedAt(v) + return _u +} + +// SetNillableFinishedAt sets the "finished_at" field if the given value is not nil. +func (_u *EmailBroadcastUpdate) SetNillableFinishedAt(v *time.Time) *EmailBroadcastUpdate { + if v != nil { + _u.SetFinishedAt(*v) + } + return _u +} + +// ClearFinishedAt clears the value of the "finished_at" field. +func (_u *EmailBroadcastUpdate) ClearFinishedAt() *EmailBroadcastUpdate { + _u.mutation.ClearFinishedAt() + return _u +} + +// SetUpdatedAt sets the "updated_at" field. +func (_u *EmailBroadcastUpdate) SetUpdatedAt(v time.Time) *EmailBroadcastUpdate { + _u.mutation.SetUpdatedAt(v) + return _u +} + +// Mutation returns the EmailBroadcastMutation object of the builder. +func (_u *EmailBroadcastUpdate) Mutation() *EmailBroadcastMutation { + return _u.mutation +} + +// Save executes the query and returns the number of nodes affected by the update operation. +func (_u *EmailBroadcastUpdate) Save(ctx context.Context) (int, error) { + _u.defaults() + return withHooks(ctx, _u.sqlSave, _u.mutation, _u.hooks) +} + +// SaveX is like Save, but panics if an error occurs. +func (_u *EmailBroadcastUpdate) SaveX(ctx context.Context) int { + affected, err := _u.Save(ctx) + if err != nil { + panic(err) + } + return affected +} + +// Exec executes the query. +func (_u *EmailBroadcastUpdate) Exec(ctx context.Context) error { + _, err := _u.Save(ctx) + return err +} + +// ExecX is like Exec, but panics if an error occurs. +func (_u *EmailBroadcastUpdate) ExecX(ctx context.Context) { + if err := _u.Exec(ctx); err != nil { + panic(err) + } +} + +// defaults sets the default values of the builder before save. +func (_u *EmailBroadcastUpdate) defaults() { + if _, ok := _u.mutation.UpdatedAt(); !ok { + v := emailbroadcast.UpdateDefaultUpdatedAt() + _u.mutation.SetUpdatedAt(v) + } +} + +// check runs all checks and user-defined validators on the builder. +func (_u *EmailBroadcastUpdate) check() error { + if v, ok := _u.mutation.Subject(); ok { + if err := emailbroadcast.SubjectValidator(v); err != nil { + return &ValidationError{Name: "subject", err: fmt.Errorf(`ent: validator failed for field "EmailBroadcast.subject": %w`, err)} + } + } + if v, ok := _u.mutation.Body(); ok { + if err := emailbroadcast.BodyValidator(v); err != nil { + return &ValidationError{Name: "body", err: fmt.Errorf(`ent: validator failed for field "EmailBroadcast.body": %w`, err)} + } + } + if v, ok := _u.mutation.BodyFormat(); ok { + if err := emailbroadcast.BodyFormatValidator(v); err != nil { + return &ValidationError{Name: "body_format", err: fmt.Errorf(`ent: validator failed for field "EmailBroadcast.body_format": %w`, err)} + } + } + if v, ok := _u.mutation.RecipientsMode(); ok { + if err := emailbroadcast.RecipientsModeValidator(v); err != nil { + return &ValidationError{Name: "recipients_mode", err: fmt.Errorf(`ent: validator failed for field "EmailBroadcast.recipients_mode": %w`, err)} + } + } + if v, ok := _u.mutation.Status(); ok { + if err := emailbroadcast.StatusValidator(v); err != nil { + return &ValidationError{Name: "status", err: fmt.Errorf(`ent: validator failed for field "EmailBroadcast.status": %w`, err)} + } + } + if v, ok := _u.mutation.TotalCount(); ok { + if err := emailbroadcast.TotalCountValidator(v); err != nil { + return &ValidationError{Name: "total_count", err: fmt.Errorf(`ent: validator failed for field "EmailBroadcast.total_count": %w`, err)} + } + } + if v, ok := _u.mutation.SuccessCount(); ok { + if err := emailbroadcast.SuccessCountValidator(v); err != nil { + return &ValidationError{Name: "success_count", err: fmt.Errorf(`ent: validator failed for field "EmailBroadcast.success_count": %w`, err)} + } + } + if v, ok := _u.mutation.FailedCount(); ok { + if err := emailbroadcast.FailedCountValidator(v); err != nil { + return &ValidationError{Name: "failed_count", err: fmt.Errorf(`ent: validator failed for field "EmailBroadcast.failed_count": %w`, err)} + } + } + return nil +} + +func (_u *EmailBroadcastUpdate) sqlSave(ctx context.Context) (_node int, err error) { + if err := _u.check(); err != nil { + return _node, err + } + _spec := sqlgraph.NewUpdateSpec(emailbroadcast.Table, emailbroadcast.Columns, sqlgraph.NewFieldSpec(emailbroadcast.FieldID, field.TypeInt64)) + if ps := _u.mutation.predicates; len(ps) > 0 { + _spec.Predicate = func(selector *sql.Selector) { + for i := range ps { + ps[i](selector) + } + } + } + if value, ok := _u.mutation.Subject(); ok { + _spec.SetField(emailbroadcast.FieldSubject, field.TypeString, value) + } + if value, ok := _u.mutation.Body(); ok { + _spec.SetField(emailbroadcast.FieldBody, field.TypeString, value) + } + if value, ok := _u.mutation.BodyFormat(); ok { + _spec.SetField(emailbroadcast.FieldBodyFormat, field.TypeString, value) + } + if value, ok := _u.mutation.RecipientsMode(); ok { + _spec.SetField(emailbroadcast.FieldRecipientsMode, field.TypeString, value) + } + if value, ok := _u.mutation.RecipientUserIds(); ok { + _spec.SetField(emailbroadcast.FieldRecipientUserIds, field.TypeJSON, value) + } + if value, ok := _u.mutation.AppendedRecipientUserIds(); ok { + _spec.AddModifier(func(u *sql.UpdateBuilder) { + sqljson.Append(u, emailbroadcast.FieldRecipientUserIds, value) + }) + } + if _u.mutation.RecipientUserIdsCleared() { + _spec.ClearField(emailbroadcast.FieldRecipientUserIds, field.TypeJSON) + } + if value, ok := _u.mutation.Status(); ok { + _spec.SetField(emailbroadcast.FieldStatus, field.TypeString, value) + } + if value, ok := _u.mutation.TotalCount(); ok { + _spec.SetField(emailbroadcast.FieldTotalCount, field.TypeInt, value) + } + if value, ok := _u.mutation.AddedTotalCount(); ok { + _spec.AddField(emailbroadcast.FieldTotalCount, field.TypeInt, value) + } + if value, ok := _u.mutation.SuccessCount(); ok { + _spec.SetField(emailbroadcast.FieldSuccessCount, field.TypeInt, value) + } + if value, ok := _u.mutation.AddedSuccessCount(); ok { + _spec.AddField(emailbroadcast.FieldSuccessCount, field.TypeInt, value) + } + if value, ok := _u.mutation.FailedCount(); ok { + _spec.SetField(emailbroadcast.FieldFailedCount, field.TypeInt, value) + } + if value, ok := _u.mutation.AddedFailedCount(); ok { + _spec.AddField(emailbroadcast.FieldFailedCount, field.TypeInt, value) + } + if value, ok := _u.mutation.ErrorMessage(); ok { + _spec.SetField(emailbroadcast.FieldErrorMessage, field.TypeString, value) + } + if _u.mutation.ErrorMessageCleared() { + _spec.ClearField(emailbroadcast.FieldErrorMessage, field.TypeString) + } + if value, ok := _u.mutation.CreatedBy(); ok { + _spec.SetField(emailbroadcast.FieldCreatedBy, field.TypeInt64, value) + } + if value, ok := _u.mutation.AddedCreatedBy(); ok { + _spec.AddField(emailbroadcast.FieldCreatedBy, field.TypeInt64, value) + } + if _u.mutation.CreatedByCleared() { + _spec.ClearField(emailbroadcast.FieldCreatedBy, field.TypeInt64) + } + if value, ok := _u.mutation.StartedAt(); ok { + _spec.SetField(emailbroadcast.FieldStartedAt, field.TypeTime, value) + } + if _u.mutation.StartedAtCleared() { + _spec.ClearField(emailbroadcast.FieldStartedAt, field.TypeTime) + } + if value, ok := _u.mutation.FinishedAt(); ok { + _spec.SetField(emailbroadcast.FieldFinishedAt, field.TypeTime, value) + } + if _u.mutation.FinishedAtCleared() { + _spec.ClearField(emailbroadcast.FieldFinishedAt, field.TypeTime) + } + if value, ok := _u.mutation.UpdatedAt(); ok { + _spec.SetField(emailbroadcast.FieldUpdatedAt, field.TypeTime, value) + } + if _node, err = sqlgraph.UpdateNodes(ctx, _u.driver, _spec); err != nil { + if _, ok := err.(*sqlgraph.NotFoundError); ok { + err = &NotFoundError{emailbroadcast.Label} + } else if sqlgraph.IsConstraintError(err) { + err = &ConstraintError{msg: err.Error(), wrap: err} + } + return 0, err + } + _u.mutation.done = true + return _node, nil +} + +// EmailBroadcastUpdateOne is the builder for updating a single EmailBroadcast entity. +type EmailBroadcastUpdateOne struct { + config + fields []string + hooks []Hook + mutation *EmailBroadcastMutation +} + +// SetSubject sets the "subject" field. +func (_u *EmailBroadcastUpdateOne) SetSubject(v string) *EmailBroadcastUpdateOne { + _u.mutation.SetSubject(v) + return _u +} + +// SetNillableSubject sets the "subject" field if the given value is not nil. +func (_u *EmailBroadcastUpdateOne) SetNillableSubject(v *string) *EmailBroadcastUpdateOne { + if v != nil { + _u.SetSubject(*v) + } + return _u +} + +// SetBody sets the "body" field. +func (_u *EmailBroadcastUpdateOne) SetBody(v string) *EmailBroadcastUpdateOne { + _u.mutation.SetBody(v) + return _u +} + +// SetNillableBody sets the "body" field if the given value is not nil. +func (_u *EmailBroadcastUpdateOne) SetNillableBody(v *string) *EmailBroadcastUpdateOne { + if v != nil { + _u.SetBody(*v) + } + return _u +} + +// SetBodyFormat sets the "body_format" field. +func (_u *EmailBroadcastUpdateOne) SetBodyFormat(v string) *EmailBroadcastUpdateOne { + _u.mutation.SetBodyFormat(v) + return _u +} + +// SetNillableBodyFormat sets the "body_format" field if the given value is not nil. +func (_u *EmailBroadcastUpdateOne) SetNillableBodyFormat(v *string) *EmailBroadcastUpdateOne { + if v != nil { + _u.SetBodyFormat(*v) + } + return _u +} + +// SetRecipientsMode sets the "recipients_mode" field. +func (_u *EmailBroadcastUpdateOne) SetRecipientsMode(v string) *EmailBroadcastUpdateOne { + _u.mutation.SetRecipientsMode(v) + return _u +} + +// SetNillableRecipientsMode sets the "recipients_mode" field if the given value is not nil. +func (_u *EmailBroadcastUpdateOne) SetNillableRecipientsMode(v *string) *EmailBroadcastUpdateOne { + if v != nil { + _u.SetRecipientsMode(*v) + } + return _u +} + +// SetRecipientUserIds sets the "recipient_user_ids" field. +func (_u *EmailBroadcastUpdateOne) SetRecipientUserIds(v []int64) *EmailBroadcastUpdateOne { + _u.mutation.SetRecipientUserIds(v) + return _u +} + +// AppendRecipientUserIds appends value to the "recipient_user_ids" field. +func (_u *EmailBroadcastUpdateOne) AppendRecipientUserIds(v []int64) *EmailBroadcastUpdateOne { + _u.mutation.AppendRecipientUserIds(v) + return _u +} + +// ClearRecipientUserIds clears the value of the "recipient_user_ids" field. +func (_u *EmailBroadcastUpdateOne) ClearRecipientUserIds() *EmailBroadcastUpdateOne { + _u.mutation.ClearRecipientUserIds() + return _u +} + +// SetStatus sets the "status" field. +func (_u *EmailBroadcastUpdateOne) SetStatus(v string) *EmailBroadcastUpdateOne { + _u.mutation.SetStatus(v) + return _u +} + +// SetNillableStatus sets the "status" field if the given value is not nil. +func (_u *EmailBroadcastUpdateOne) SetNillableStatus(v *string) *EmailBroadcastUpdateOne { + if v != nil { + _u.SetStatus(*v) + } + return _u +} + +// SetTotalCount sets the "total_count" field. +func (_u *EmailBroadcastUpdateOne) SetTotalCount(v int) *EmailBroadcastUpdateOne { + _u.mutation.ResetTotalCount() + _u.mutation.SetTotalCount(v) + return _u +} + +// SetNillableTotalCount sets the "total_count" field if the given value is not nil. +func (_u *EmailBroadcastUpdateOne) SetNillableTotalCount(v *int) *EmailBroadcastUpdateOne { + if v != nil { + _u.SetTotalCount(*v) + } + return _u +} + +// AddTotalCount adds value to the "total_count" field. +func (_u *EmailBroadcastUpdateOne) AddTotalCount(v int) *EmailBroadcastUpdateOne { + _u.mutation.AddTotalCount(v) + return _u +} + +// SetSuccessCount sets the "success_count" field. +func (_u *EmailBroadcastUpdateOne) SetSuccessCount(v int) *EmailBroadcastUpdateOne { + _u.mutation.ResetSuccessCount() + _u.mutation.SetSuccessCount(v) + return _u +} + +// SetNillableSuccessCount sets the "success_count" field if the given value is not nil. +func (_u *EmailBroadcastUpdateOne) SetNillableSuccessCount(v *int) *EmailBroadcastUpdateOne { + if v != nil { + _u.SetSuccessCount(*v) + } + return _u +} + +// AddSuccessCount adds value to the "success_count" field. +func (_u *EmailBroadcastUpdateOne) AddSuccessCount(v int) *EmailBroadcastUpdateOne { + _u.mutation.AddSuccessCount(v) + return _u +} + +// SetFailedCount sets the "failed_count" field. +func (_u *EmailBroadcastUpdateOne) SetFailedCount(v int) *EmailBroadcastUpdateOne { + _u.mutation.ResetFailedCount() + _u.mutation.SetFailedCount(v) + return _u +} + +// SetNillableFailedCount sets the "failed_count" field if the given value is not nil. +func (_u *EmailBroadcastUpdateOne) SetNillableFailedCount(v *int) *EmailBroadcastUpdateOne { + if v != nil { + _u.SetFailedCount(*v) + } + return _u +} + +// AddFailedCount adds value to the "failed_count" field. +func (_u *EmailBroadcastUpdateOne) AddFailedCount(v int) *EmailBroadcastUpdateOne { + _u.mutation.AddFailedCount(v) + return _u +} + +// SetErrorMessage sets the "error_message" field. +func (_u *EmailBroadcastUpdateOne) SetErrorMessage(v string) *EmailBroadcastUpdateOne { + _u.mutation.SetErrorMessage(v) + return _u +} + +// SetNillableErrorMessage sets the "error_message" field if the given value is not nil. +func (_u *EmailBroadcastUpdateOne) SetNillableErrorMessage(v *string) *EmailBroadcastUpdateOne { + if v != nil { + _u.SetErrorMessage(*v) + } + return _u +} + +// ClearErrorMessage clears the value of the "error_message" field. +func (_u *EmailBroadcastUpdateOne) ClearErrorMessage() *EmailBroadcastUpdateOne { + _u.mutation.ClearErrorMessage() + return _u +} + +// SetCreatedBy sets the "created_by" field. +func (_u *EmailBroadcastUpdateOne) SetCreatedBy(v int64) *EmailBroadcastUpdateOne { + _u.mutation.ResetCreatedBy() + _u.mutation.SetCreatedBy(v) + return _u +} + +// SetNillableCreatedBy sets the "created_by" field if the given value is not nil. +func (_u *EmailBroadcastUpdateOne) SetNillableCreatedBy(v *int64) *EmailBroadcastUpdateOne { + if v != nil { + _u.SetCreatedBy(*v) + } + return _u +} + +// AddCreatedBy adds value to the "created_by" field. +func (_u *EmailBroadcastUpdateOne) AddCreatedBy(v int64) *EmailBroadcastUpdateOne { + _u.mutation.AddCreatedBy(v) + return _u +} + +// ClearCreatedBy clears the value of the "created_by" field. +func (_u *EmailBroadcastUpdateOne) ClearCreatedBy() *EmailBroadcastUpdateOne { + _u.mutation.ClearCreatedBy() + return _u +} + +// SetStartedAt sets the "started_at" field. +func (_u *EmailBroadcastUpdateOne) SetStartedAt(v time.Time) *EmailBroadcastUpdateOne { + _u.mutation.SetStartedAt(v) + return _u +} + +// SetNillableStartedAt sets the "started_at" field if the given value is not nil. +func (_u *EmailBroadcastUpdateOne) SetNillableStartedAt(v *time.Time) *EmailBroadcastUpdateOne { + if v != nil { + _u.SetStartedAt(*v) + } + return _u +} + +// ClearStartedAt clears the value of the "started_at" field. +func (_u *EmailBroadcastUpdateOne) ClearStartedAt() *EmailBroadcastUpdateOne { + _u.mutation.ClearStartedAt() + return _u +} + +// SetFinishedAt sets the "finished_at" field. +func (_u *EmailBroadcastUpdateOne) SetFinishedAt(v time.Time) *EmailBroadcastUpdateOne { + _u.mutation.SetFinishedAt(v) + return _u +} + +// SetNillableFinishedAt sets the "finished_at" field if the given value is not nil. +func (_u *EmailBroadcastUpdateOne) SetNillableFinishedAt(v *time.Time) *EmailBroadcastUpdateOne { + if v != nil { + _u.SetFinishedAt(*v) + } + return _u +} + +// ClearFinishedAt clears the value of the "finished_at" field. +func (_u *EmailBroadcastUpdateOne) ClearFinishedAt() *EmailBroadcastUpdateOne { + _u.mutation.ClearFinishedAt() + return _u +} + +// SetUpdatedAt sets the "updated_at" field. +func (_u *EmailBroadcastUpdateOne) SetUpdatedAt(v time.Time) *EmailBroadcastUpdateOne { + _u.mutation.SetUpdatedAt(v) + return _u +} + +// Mutation returns the EmailBroadcastMutation object of the builder. +func (_u *EmailBroadcastUpdateOne) Mutation() *EmailBroadcastMutation { + return _u.mutation +} + +// Where appends a list predicates to the EmailBroadcastUpdate builder. +func (_u *EmailBroadcastUpdateOne) Where(ps ...predicate.EmailBroadcast) *EmailBroadcastUpdateOne { + _u.mutation.Where(ps...) + return _u +} + +// Select allows selecting one or more fields (columns) of the returned entity. +// The default is selecting all fields defined in the entity schema. +func (_u *EmailBroadcastUpdateOne) Select(field string, fields ...string) *EmailBroadcastUpdateOne { + _u.fields = append([]string{field}, fields...) + return _u +} + +// Save executes the query and returns the updated EmailBroadcast entity. +func (_u *EmailBroadcastUpdateOne) Save(ctx context.Context) (*EmailBroadcast, error) { + _u.defaults() + return withHooks(ctx, _u.sqlSave, _u.mutation, _u.hooks) +} + +// SaveX is like Save, but panics if an error occurs. +func (_u *EmailBroadcastUpdateOne) SaveX(ctx context.Context) *EmailBroadcast { + node, err := _u.Save(ctx) + if err != nil { + panic(err) + } + return node +} + +// Exec executes the query on the entity. +func (_u *EmailBroadcastUpdateOne) Exec(ctx context.Context) error { + _, err := _u.Save(ctx) + return err +} + +// ExecX is like Exec, but panics if an error occurs. +func (_u *EmailBroadcastUpdateOne) ExecX(ctx context.Context) { + if err := _u.Exec(ctx); err != nil { + panic(err) + } +} + +// defaults sets the default values of the builder before save. +func (_u *EmailBroadcastUpdateOne) defaults() { + if _, ok := _u.mutation.UpdatedAt(); !ok { + v := emailbroadcast.UpdateDefaultUpdatedAt() + _u.mutation.SetUpdatedAt(v) + } +} + +// check runs all checks and user-defined validators on the builder. +func (_u *EmailBroadcastUpdateOne) check() error { + if v, ok := _u.mutation.Subject(); ok { + if err := emailbroadcast.SubjectValidator(v); err != nil { + return &ValidationError{Name: "subject", err: fmt.Errorf(`ent: validator failed for field "EmailBroadcast.subject": %w`, err)} + } + } + if v, ok := _u.mutation.Body(); ok { + if err := emailbroadcast.BodyValidator(v); err != nil { + return &ValidationError{Name: "body", err: fmt.Errorf(`ent: validator failed for field "EmailBroadcast.body": %w`, err)} + } + } + if v, ok := _u.mutation.BodyFormat(); ok { + if err := emailbroadcast.BodyFormatValidator(v); err != nil { + return &ValidationError{Name: "body_format", err: fmt.Errorf(`ent: validator failed for field "EmailBroadcast.body_format": %w`, err)} + } + } + if v, ok := _u.mutation.RecipientsMode(); ok { + if err := emailbroadcast.RecipientsModeValidator(v); err != nil { + return &ValidationError{Name: "recipients_mode", err: fmt.Errorf(`ent: validator failed for field "EmailBroadcast.recipients_mode": %w`, err)} + } + } + if v, ok := _u.mutation.Status(); ok { + if err := emailbroadcast.StatusValidator(v); err != nil { + return &ValidationError{Name: "status", err: fmt.Errorf(`ent: validator failed for field "EmailBroadcast.status": %w`, err)} + } + } + if v, ok := _u.mutation.TotalCount(); ok { + if err := emailbroadcast.TotalCountValidator(v); err != nil { + return &ValidationError{Name: "total_count", err: fmt.Errorf(`ent: validator failed for field "EmailBroadcast.total_count": %w`, err)} + } + } + if v, ok := _u.mutation.SuccessCount(); ok { + if err := emailbroadcast.SuccessCountValidator(v); err != nil { + return &ValidationError{Name: "success_count", err: fmt.Errorf(`ent: validator failed for field "EmailBroadcast.success_count": %w`, err)} + } + } + if v, ok := _u.mutation.FailedCount(); ok { + if err := emailbroadcast.FailedCountValidator(v); err != nil { + return &ValidationError{Name: "failed_count", err: fmt.Errorf(`ent: validator failed for field "EmailBroadcast.failed_count": %w`, err)} + } + } + return nil +} + +func (_u *EmailBroadcastUpdateOne) sqlSave(ctx context.Context) (_node *EmailBroadcast, err error) { + if err := _u.check(); err != nil { + return _node, err + } + _spec := sqlgraph.NewUpdateSpec(emailbroadcast.Table, emailbroadcast.Columns, sqlgraph.NewFieldSpec(emailbroadcast.FieldID, field.TypeInt64)) + id, ok := _u.mutation.ID() + if !ok { + return nil, &ValidationError{Name: "id", err: errors.New(`ent: missing "EmailBroadcast.id" for update`)} + } + _spec.Node.ID.Value = id + if fields := _u.fields; len(fields) > 0 { + _spec.Node.Columns = make([]string, 0, len(fields)) + _spec.Node.Columns = append(_spec.Node.Columns, emailbroadcast.FieldID) + for _, f := range fields { + if !emailbroadcast.ValidColumn(f) { + return nil, &ValidationError{Name: f, err: fmt.Errorf("ent: invalid field %q for query", f)} + } + if f != emailbroadcast.FieldID { + _spec.Node.Columns = append(_spec.Node.Columns, f) + } + } + } + if ps := _u.mutation.predicates; len(ps) > 0 { + _spec.Predicate = func(selector *sql.Selector) { + for i := range ps { + ps[i](selector) + } + } + } + if value, ok := _u.mutation.Subject(); ok { + _spec.SetField(emailbroadcast.FieldSubject, field.TypeString, value) + } + if value, ok := _u.mutation.Body(); ok { + _spec.SetField(emailbroadcast.FieldBody, field.TypeString, value) + } + if value, ok := _u.mutation.BodyFormat(); ok { + _spec.SetField(emailbroadcast.FieldBodyFormat, field.TypeString, value) + } + if value, ok := _u.mutation.RecipientsMode(); ok { + _spec.SetField(emailbroadcast.FieldRecipientsMode, field.TypeString, value) + } + if value, ok := _u.mutation.RecipientUserIds(); ok { + _spec.SetField(emailbroadcast.FieldRecipientUserIds, field.TypeJSON, value) + } + if value, ok := _u.mutation.AppendedRecipientUserIds(); ok { + _spec.AddModifier(func(u *sql.UpdateBuilder) { + sqljson.Append(u, emailbroadcast.FieldRecipientUserIds, value) + }) + } + if _u.mutation.RecipientUserIdsCleared() { + _spec.ClearField(emailbroadcast.FieldRecipientUserIds, field.TypeJSON) + } + if value, ok := _u.mutation.Status(); ok { + _spec.SetField(emailbroadcast.FieldStatus, field.TypeString, value) + } + if value, ok := _u.mutation.TotalCount(); ok { + _spec.SetField(emailbroadcast.FieldTotalCount, field.TypeInt, value) + } + if value, ok := _u.mutation.AddedTotalCount(); ok { + _spec.AddField(emailbroadcast.FieldTotalCount, field.TypeInt, value) + } + if value, ok := _u.mutation.SuccessCount(); ok { + _spec.SetField(emailbroadcast.FieldSuccessCount, field.TypeInt, value) + } + if value, ok := _u.mutation.AddedSuccessCount(); ok { + _spec.AddField(emailbroadcast.FieldSuccessCount, field.TypeInt, value) + } + if value, ok := _u.mutation.FailedCount(); ok { + _spec.SetField(emailbroadcast.FieldFailedCount, field.TypeInt, value) + } + if value, ok := _u.mutation.AddedFailedCount(); ok { + _spec.AddField(emailbroadcast.FieldFailedCount, field.TypeInt, value) + } + if value, ok := _u.mutation.ErrorMessage(); ok { + _spec.SetField(emailbroadcast.FieldErrorMessage, field.TypeString, value) + } + if _u.mutation.ErrorMessageCleared() { + _spec.ClearField(emailbroadcast.FieldErrorMessage, field.TypeString) + } + if value, ok := _u.mutation.CreatedBy(); ok { + _spec.SetField(emailbroadcast.FieldCreatedBy, field.TypeInt64, value) + } + if value, ok := _u.mutation.AddedCreatedBy(); ok { + _spec.AddField(emailbroadcast.FieldCreatedBy, field.TypeInt64, value) + } + if _u.mutation.CreatedByCleared() { + _spec.ClearField(emailbroadcast.FieldCreatedBy, field.TypeInt64) + } + if value, ok := _u.mutation.StartedAt(); ok { + _spec.SetField(emailbroadcast.FieldStartedAt, field.TypeTime, value) + } + if _u.mutation.StartedAtCleared() { + _spec.ClearField(emailbroadcast.FieldStartedAt, field.TypeTime) + } + if value, ok := _u.mutation.FinishedAt(); ok { + _spec.SetField(emailbroadcast.FieldFinishedAt, field.TypeTime, value) + } + if _u.mutation.FinishedAtCleared() { + _spec.ClearField(emailbroadcast.FieldFinishedAt, field.TypeTime) + } + if value, ok := _u.mutation.UpdatedAt(); ok { + _spec.SetField(emailbroadcast.FieldUpdatedAt, field.TypeTime, value) + } + _node = &EmailBroadcast{config: _u.config} + _spec.Assign = _node.assignValues + _spec.ScanValues = _node.scanValues + if err = sqlgraph.UpdateNode(ctx, _u.driver, _spec); err != nil { + if _, ok := err.(*sqlgraph.NotFoundError); ok { + err = &NotFoundError{emailbroadcast.Label} + } else if sqlgraph.IsConstraintError(err) { + err = &ConstraintError{msg: err.Error(), wrap: err} + } + return nil, err + } + _u.mutation.done = true + return _node, nil +} diff --git a/backend/ent/ent.go b/backend/ent/ent.go index 33d36e70ee8..f1208e43277 100644 --- a/backend/ent/ent.go +++ b/backend/ent/ent.go @@ -23,6 +23,7 @@ import ( "github.com/Wei-Shaw/sub2api/ent/channelmonitordailyrollup" "github.com/Wei-Shaw/sub2api/ent/channelmonitorhistory" "github.com/Wei-Shaw/sub2api/ent/channelmonitorrequesttemplate" + "github.com/Wei-Shaw/sub2api/ent/emailbroadcast" "github.com/Wei-Shaw/sub2api/ent/errorpassthroughrule" "github.com/Wei-Shaw/sub2api/ent/group" "github.com/Wei-Shaw/sub2api/ent/idempotencyrecord" @@ -118,6 +119,7 @@ func checkColumn(t, c string) error { channelmonitordailyrollup.Table: channelmonitordailyrollup.ValidColumn, channelmonitorhistory.Table: channelmonitorhistory.ValidColumn, channelmonitorrequesttemplate.Table: channelmonitorrequesttemplate.ValidColumn, + emailbroadcast.Table: emailbroadcast.ValidColumn, errorpassthroughrule.Table: errorpassthroughrule.ValidColumn, group.Table: group.ValidColumn, idempotencyrecord.Table: idempotencyrecord.ValidColumn, diff --git a/backend/ent/hook/hook.go b/backend/ent/hook/hook.go index 71bfd3b88eb..2781b91754c 100644 --- a/backend/ent/hook/hook.go +++ b/backend/ent/hook/hook.go @@ -141,6 +141,18 @@ func (f ChannelMonitorRequestTemplateFunc) Mutate(ctx context.Context, m ent.Mut return nil, fmt.Errorf("unexpected mutation type %T. expect *ent.ChannelMonitorRequestTemplateMutation", m) } +// The EmailBroadcastFunc type is an adapter to allow the use of ordinary +// function as EmailBroadcast mutator. +type EmailBroadcastFunc func(context.Context, *ent.EmailBroadcastMutation) (ent.Value, error) + +// Mutate calls f(ctx, m). +func (f EmailBroadcastFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, error) { + if mv, ok := m.(*ent.EmailBroadcastMutation); ok { + return f(ctx, mv) + } + return nil, fmt.Errorf("unexpected mutation type %T. expect *ent.EmailBroadcastMutation", m) +} + // The ErrorPassthroughRuleFunc type is an adapter to allow the use of ordinary // function as ErrorPassthroughRule mutator. type ErrorPassthroughRuleFunc func(context.Context, *ent.ErrorPassthroughRuleMutation) (ent.Value, error) diff --git a/backend/ent/intercept/intercept.go b/backend/ent/intercept/intercept.go index 5d86e25bd55..c38a6122709 100644 --- a/backend/ent/intercept/intercept.go +++ b/backend/ent/intercept/intercept.go @@ -19,6 +19,7 @@ import ( "github.com/Wei-Shaw/sub2api/ent/channelmonitordailyrollup" "github.com/Wei-Shaw/sub2api/ent/channelmonitorhistory" "github.com/Wei-Shaw/sub2api/ent/channelmonitorrequesttemplate" + "github.com/Wei-Shaw/sub2api/ent/emailbroadcast" "github.com/Wei-Shaw/sub2api/ent/errorpassthroughrule" "github.com/Wei-Shaw/sub2api/ent/group" "github.com/Wei-Shaw/sub2api/ent/idempotencyrecord" @@ -399,6 +400,33 @@ func (f TraverseChannelMonitorRequestTemplate) Traverse(ctx context.Context, q e return fmt.Errorf("unexpected query type %T. expect *ent.ChannelMonitorRequestTemplateQuery", q) } +// The EmailBroadcastFunc type is an adapter to allow the use of ordinary function as a Querier. +type EmailBroadcastFunc func(context.Context, *ent.EmailBroadcastQuery) (ent.Value, error) + +// Query calls f(ctx, q). +func (f EmailBroadcastFunc) Query(ctx context.Context, q ent.Query) (ent.Value, error) { + if q, ok := q.(*ent.EmailBroadcastQuery); ok { + return f(ctx, q) + } + return nil, fmt.Errorf("unexpected query type %T. expect *ent.EmailBroadcastQuery", q) +} + +// The TraverseEmailBroadcast type is an adapter to allow the use of ordinary function as Traverser. +type TraverseEmailBroadcast func(context.Context, *ent.EmailBroadcastQuery) error + +// Intercept is a dummy implementation of Intercept that returns the next Querier in the pipeline. +func (f TraverseEmailBroadcast) Intercept(next ent.Querier) ent.Querier { + return next +} + +// Traverse calls f(ctx, q). +func (f TraverseEmailBroadcast) Traverse(ctx context.Context, q ent.Query) error { + if q, ok := q.(*ent.EmailBroadcastQuery); ok { + return f(ctx, q) + } + return fmt.Errorf("unexpected query type %T. expect *ent.EmailBroadcastQuery", q) +} + // The ErrorPassthroughRuleFunc type is an adapter to allow the use of ordinary function as a Querier. type ErrorPassthroughRuleFunc func(context.Context, *ent.ErrorPassthroughRuleQuery) (ent.Value, error) @@ -1072,6 +1100,8 @@ func NewQuery(q ent.Query) (Query, error) { return &query[*ent.ChannelMonitorHistoryQuery, predicate.ChannelMonitorHistory, channelmonitorhistory.OrderOption]{typ: ent.TypeChannelMonitorHistory, tq: q}, nil case *ent.ChannelMonitorRequestTemplateQuery: return &query[*ent.ChannelMonitorRequestTemplateQuery, predicate.ChannelMonitorRequestTemplate, channelmonitorrequesttemplate.OrderOption]{typ: ent.TypeChannelMonitorRequestTemplate, tq: q}, nil + case *ent.EmailBroadcastQuery: + return &query[*ent.EmailBroadcastQuery, predicate.EmailBroadcast, emailbroadcast.OrderOption]{typ: ent.TypeEmailBroadcast, tq: q}, nil case *ent.ErrorPassthroughRuleQuery: return &query[*ent.ErrorPassthroughRuleQuery, predicate.ErrorPassthroughRule, errorpassthroughrule.OrderOption]{typ: ent.TypeErrorPassthroughRule, tq: q}, nil case *ent.GroupQuery: diff --git a/backend/ent/migrate/schema.go b/backend/ent/migrate/schema.go index 7abe4c601e3..4a20674d44a 100644 --- a/backend/ent/migrate/schema.go +++ b/backend/ent/migrate/schema.go @@ -596,6 +596,48 @@ var ( }, }, } + // EmailBroadcastsColumns holds the columns for the "email_broadcasts" table. + EmailBroadcastsColumns = []*schema.Column{ + {Name: "id", Type: field.TypeInt64, Increment: true}, + {Name: "subject", Type: field.TypeString, Size: 200}, + {Name: "body", Type: field.TypeString, SchemaType: map[string]string{"postgres": "text"}}, + {Name: "body_format", Type: field.TypeString, Size: 10, Default: "html"}, + {Name: "recipients_mode", Type: field.TypeString, Size: 20, Default: "selected"}, + {Name: "recipient_user_ids", Type: field.TypeJSON, Nullable: true, SchemaType: map[string]string{"postgres": "jsonb"}}, + {Name: "status", Type: field.TypeString, Size: 20, Default: "pending"}, + {Name: "total_count", Type: field.TypeInt, Default: 0}, + {Name: "success_count", Type: field.TypeInt, Default: 0}, + {Name: "failed_count", Type: field.TypeInt, Default: 0}, + {Name: "error_message", Type: field.TypeString, Nullable: true, SchemaType: map[string]string{"postgres": "text"}}, + {Name: "created_by", Type: field.TypeInt64, Nullable: true}, + {Name: "started_at", Type: field.TypeTime, Nullable: true, SchemaType: map[string]string{"postgres": "timestamptz"}}, + {Name: "finished_at", Type: field.TypeTime, Nullable: true, SchemaType: map[string]string{"postgres": "timestamptz"}}, + {Name: "created_at", Type: field.TypeTime, SchemaType: map[string]string{"postgres": "timestamptz"}}, + {Name: "updated_at", Type: field.TypeTime, SchemaType: map[string]string{"postgres": "timestamptz"}}, + } + // EmailBroadcastsTable holds the schema information for the "email_broadcasts" table. + EmailBroadcastsTable = &schema.Table{ + Name: "email_broadcasts", + Columns: EmailBroadcastsColumns, + PrimaryKey: []*schema.Column{EmailBroadcastsColumns[0]}, + Indexes: []*schema.Index{ + { + Name: "emailbroadcast_status", + Unique: false, + Columns: []*schema.Column{EmailBroadcastsColumns[6]}, + }, + { + Name: "emailbroadcast_created_at", + Unique: false, + Columns: []*schema.Column{EmailBroadcastsColumns[14]}, + }, + { + Name: "emailbroadcast_created_by", + Unique: false, + Columns: []*schema.Column{EmailBroadcastsColumns[11]}, + }, + }, + } // ErrorPassthroughRulesColumns holds the columns for the "error_passthrough_rules" table. ErrorPassthroughRulesColumns = []*schema.Column{ {Name: "id", Type: field.TypeInt64, Increment: true}, @@ -1762,6 +1804,7 @@ var ( ChannelMonitorDailyRollupsTable, ChannelMonitorHistoriesTable, ChannelMonitorRequestTemplatesTable, + EmailBroadcastsTable, ErrorPassthroughRulesTable, GroupsTable, IdempotencyRecordsTable, @@ -1835,6 +1878,9 @@ func init() { ChannelMonitorRequestTemplatesTable.Annotation = &entsql.Annotation{ Table: "channel_monitor_request_templates", } + EmailBroadcastsTable.Annotation = &entsql.Annotation{ + Table: "email_broadcasts", + } ErrorPassthroughRulesTable.Annotation = &entsql.Annotation{ Table: "error_passthrough_rules", } diff --git a/backend/ent/mutation.go b/backend/ent/mutation.go index 003e25d5015..cb693cfcba1 100644 --- a/backend/ent/mutation.go +++ b/backend/ent/mutation.go @@ -23,6 +23,7 @@ import ( "github.com/Wei-Shaw/sub2api/ent/channelmonitordailyrollup" "github.com/Wei-Shaw/sub2api/ent/channelmonitorhistory" "github.com/Wei-Shaw/sub2api/ent/channelmonitorrequesttemplate" + "github.com/Wei-Shaw/sub2api/ent/emailbroadcast" "github.com/Wei-Shaw/sub2api/ent/errorpassthroughrule" "github.com/Wei-Shaw/sub2api/ent/group" "github.com/Wei-Shaw/sub2api/ent/idempotencyrecord" @@ -71,6 +72,7 @@ const ( TypeChannelMonitorDailyRollup = "ChannelMonitorDailyRollup" TypeChannelMonitorHistory = "ChannelMonitorHistory" TypeChannelMonitorRequestTemplate = "ChannelMonitorRequestTemplate" + TypeEmailBroadcast = "EmailBroadcast" TypeErrorPassthroughRule = "ErrorPassthroughRule" TypeGroup = "Group" TypeIdempotencyRecord = "IdempotencyRecord" @@ -13529,6 +13531,1339 @@ func (m *ChannelMonitorRequestTemplateMutation) ResetEdge(name string) error { return fmt.Errorf("unknown ChannelMonitorRequestTemplate edge %s", name) } +// EmailBroadcastMutation represents an operation that mutates the EmailBroadcast nodes in the graph. +type EmailBroadcastMutation struct { + config + op Op + typ string + id *int64 + subject *string + body *string + body_format *string + recipients_mode *string + recipient_user_ids *[]int64 + appendrecipient_user_ids []int64 + status *string + total_count *int + addtotal_count *int + success_count *int + addsuccess_count *int + failed_count *int + addfailed_count *int + error_message *string + created_by *int64 + addcreated_by *int64 + started_at *time.Time + finished_at *time.Time + created_at *time.Time + updated_at *time.Time + clearedFields map[string]struct{} + done bool + oldValue func(context.Context) (*EmailBroadcast, error) + predicates []predicate.EmailBroadcast +} + +var _ ent.Mutation = (*EmailBroadcastMutation)(nil) + +// emailbroadcastOption allows management of the mutation configuration using functional options. +type emailbroadcastOption func(*EmailBroadcastMutation) + +// newEmailBroadcastMutation creates new mutation for the EmailBroadcast entity. +func newEmailBroadcastMutation(c config, op Op, opts ...emailbroadcastOption) *EmailBroadcastMutation { + m := &EmailBroadcastMutation{ + config: c, + op: op, + typ: TypeEmailBroadcast, + clearedFields: make(map[string]struct{}), + } + for _, opt := range opts { + opt(m) + } + return m +} + +// withEmailBroadcastID sets the ID field of the mutation. +func withEmailBroadcastID(id int64) emailbroadcastOption { + return func(m *EmailBroadcastMutation) { + var ( + err error + once sync.Once + value *EmailBroadcast + ) + m.oldValue = func(ctx context.Context) (*EmailBroadcast, error) { + once.Do(func() { + if m.done { + err = errors.New("querying old values post mutation is not allowed") + } else { + value, err = m.Client().EmailBroadcast.Get(ctx, id) + } + }) + return value, err + } + m.id = &id + } +} + +// withEmailBroadcast sets the old EmailBroadcast of the mutation. +func withEmailBroadcast(node *EmailBroadcast) emailbroadcastOption { + return func(m *EmailBroadcastMutation) { + m.oldValue = func(context.Context) (*EmailBroadcast, 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 EmailBroadcastMutation) 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 EmailBroadcastMutation) 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 *EmailBroadcastMutation) ID() (id int64, 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 *EmailBroadcastMutation) IDs(ctx context.Context) ([]int64, error) { + switch { + case m.op.Is(OpUpdateOne | OpDeleteOne): + id, exists := m.ID() + if exists { + return []int64{id}, nil + } + fallthrough + case m.op.Is(OpUpdate | OpDelete): + return m.Client().EmailBroadcast.Query().Where(m.predicates...).IDs(ctx) + default: + return nil, fmt.Errorf("IDs is not allowed on %s operations", m.op) + } +} + +// SetSubject sets the "subject" field. +func (m *EmailBroadcastMutation) SetSubject(s string) { + m.subject = &s +} + +// Subject returns the value of the "subject" field in the mutation. +func (m *EmailBroadcastMutation) Subject() (r string, exists bool) { + v := m.subject + if v == nil { + return + } + return *v, true +} + +// OldSubject returns the old "subject" field's value of the EmailBroadcast entity. +// If the EmailBroadcast 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 *EmailBroadcastMutation) OldSubject(ctx context.Context) (v string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldSubject is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldSubject requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldSubject: %w", err) + } + return oldValue.Subject, nil +} + +// ResetSubject resets all changes to the "subject" field. +func (m *EmailBroadcastMutation) ResetSubject() { + m.subject = nil +} + +// SetBody sets the "body" field. +func (m *EmailBroadcastMutation) SetBody(s string) { + m.body = &s +} + +// Body returns the value of the "body" field in the mutation. +func (m *EmailBroadcastMutation) Body() (r string, exists bool) { + v := m.body + if v == nil { + return + } + return *v, true +} + +// OldBody returns the old "body" field's value of the EmailBroadcast entity. +// If the EmailBroadcast 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 *EmailBroadcastMutation) OldBody(ctx context.Context) (v string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldBody is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldBody requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldBody: %w", err) + } + return oldValue.Body, nil +} + +// ResetBody resets all changes to the "body" field. +func (m *EmailBroadcastMutation) ResetBody() { + m.body = nil +} + +// SetBodyFormat sets the "body_format" field. +func (m *EmailBroadcastMutation) SetBodyFormat(s string) { + m.body_format = &s +} + +// BodyFormat returns the value of the "body_format" field in the mutation. +func (m *EmailBroadcastMutation) BodyFormat() (r string, exists bool) { + v := m.body_format + if v == nil { + return + } + return *v, true +} + +// OldBodyFormat returns the old "body_format" field's value of the EmailBroadcast entity. +// If the EmailBroadcast 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 *EmailBroadcastMutation) OldBodyFormat(ctx context.Context) (v string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldBodyFormat is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldBodyFormat requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldBodyFormat: %w", err) + } + return oldValue.BodyFormat, nil +} + +// ResetBodyFormat resets all changes to the "body_format" field. +func (m *EmailBroadcastMutation) ResetBodyFormat() { + m.body_format = nil +} + +// SetRecipientsMode sets the "recipients_mode" field. +func (m *EmailBroadcastMutation) SetRecipientsMode(s string) { + m.recipients_mode = &s +} + +// RecipientsMode returns the value of the "recipients_mode" field in the mutation. +func (m *EmailBroadcastMutation) RecipientsMode() (r string, exists bool) { + v := m.recipients_mode + if v == nil { + return + } + return *v, true +} + +// OldRecipientsMode returns the old "recipients_mode" field's value of the EmailBroadcast entity. +// If the EmailBroadcast 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 *EmailBroadcastMutation) OldRecipientsMode(ctx context.Context) (v string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldRecipientsMode is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldRecipientsMode requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldRecipientsMode: %w", err) + } + return oldValue.RecipientsMode, nil +} + +// ResetRecipientsMode resets all changes to the "recipients_mode" field. +func (m *EmailBroadcastMutation) ResetRecipientsMode() { + m.recipients_mode = nil +} + +// SetRecipientUserIds sets the "recipient_user_ids" field. +func (m *EmailBroadcastMutation) SetRecipientUserIds(i []int64) { + m.recipient_user_ids = &i + m.appendrecipient_user_ids = nil +} + +// RecipientUserIds returns the value of the "recipient_user_ids" field in the mutation. +func (m *EmailBroadcastMutation) RecipientUserIds() (r []int64, exists bool) { + v := m.recipient_user_ids + if v == nil { + return + } + return *v, true +} + +// OldRecipientUserIds returns the old "recipient_user_ids" field's value of the EmailBroadcast entity. +// If the EmailBroadcast 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 *EmailBroadcastMutation) OldRecipientUserIds(ctx context.Context) (v []int64, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldRecipientUserIds is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldRecipientUserIds requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldRecipientUserIds: %w", err) + } + return oldValue.RecipientUserIds, nil +} + +// AppendRecipientUserIds adds i to the "recipient_user_ids" field. +func (m *EmailBroadcastMutation) AppendRecipientUserIds(i []int64) { + m.appendrecipient_user_ids = append(m.appendrecipient_user_ids, i...) +} + +// AppendedRecipientUserIds returns the list of values that were appended to the "recipient_user_ids" field in this mutation. +func (m *EmailBroadcastMutation) AppendedRecipientUserIds() ([]int64, bool) { + if len(m.appendrecipient_user_ids) == 0 { + return nil, false + } + return m.appendrecipient_user_ids, true +} + +// ClearRecipientUserIds clears the value of the "recipient_user_ids" field. +func (m *EmailBroadcastMutation) ClearRecipientUserIds() { + m.recipient_user_ids = nil + m.appendrecipient_user_ids = nil + m.clearedFields[emailbroadcast.FieldRecipientUserIds] = struct{}{} +} + +// RecipientUserIdsCleared returns if the "recipient_user_ids" field was cleared in this mutation. +func (m *EmailBroadcastMutation) RecipientUserIdsCleared() bool { + _, ok := m.clearedFields[emailbroadcast.FieldRecipientUserIds] + return ok +} + +// ResetRecipientUserIds resets all changes to the "recipient_user_ids" field. +func (m *EmailBroadcastMutation) ResetRecipientUserIds() { + m.recipient_user_ids = nil + m.appendrecipient_user_ids = nil + delete(m.clearedFields, emailbroadcast.FieldRecipientUserIds) +} + +// SetStatus sets the "status" field. +func (m *EmailBroadcastMutation) SetStatus(s string) { + m.status = &s +} + +// Status returns the value of the "status" field in the mutation. +func (m *EmailBroadcastMutation) Status() (r string, exists bool) { + v := m.status + if v == nil { + return + } + return *v, true +} + +// OldStatus returns the old "status" field's value of the EmailBroadcast entity. +// If the EmailBroadcast 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 *EmailBroadcastMutation) OldStatus(ctx context.Context) (v string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldStatus is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldStatus requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldStatus: %w", err) + } + return oldValue.Status, nil +} + +// ResetStatus resets all changes to the "status" field. +func (m *EmailBroadcastMutation) ResetStatus() { + m.status = nil +} + +// SetTotalCount sets the "total_count" field. +func (m *EmailBroadcastMutation) SetTotalCount(i int) { + m.total_count = &i + m.addtotal_count = nil +} + +// TotalCount returns the value of the "total_count" field in the mutation. +func (m *EmailBroadcastMutation) TotalCount() (r int, exists bool) { + v := m.total_count + if v == nil { + return + } + return *v, true +} + +// OldTotalCount returns the old "total_count" field's value of the EmailBroadcast entity. +// If the EmailBroadcast 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 *EmailBroadcastMutation) OldTotalCount(ctx context.Context) (v int, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldTotalCount is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldTotalCount requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldTotalCount: %w", err) + } + return oldValue.TotalCount, nil +} + +// AddTotalCount adds i to the "total_count" field. +func (m *EmailBroadcastMutation) AddTotalCount(i int) { + if m.addtotal_count != nil { + *m.addtotal_count += i + } else { + m.addtotal_count = &i + } +} + +// AddedTotalCount returns the value that was added to the "total_count" field in this mutation. +func (m *EmailBroadcastMutation) AddedTotalCount() (r int, exists bool) { + v := m.addtotal_count + if v == nil { + return + } + return *v, true +} + +// ResetTotalCount resets all changes to the "total_count" field. +func (m *EmailBroadcastMutation) ResetTotalCount() { + m.total_count = nil + m.addtotal_count = nil +} + +// SetSuccessCount sets the "success_count" field. +func (m *EmailBroadcastMutation) SetSuccessCount(i int) { + m.success_count = &i + m.addsuccess_count = nil +} + +// SuccessCount returns the value of the "success_count" field in the mutation. +func (m *EmailBroadcastMutation) SuccessCount() (r int, exists bool) { + v := m.success_count + if v == nil { + return + } + return *v, true +} + +// OldSuccessCount returns the old "success_count" field's value of the EmailBroadcast entity. +// If the EmailBroadcast 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 *EmailBroadcastMutation) OldSuccessCount(ctx context.Context) (v int, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldSuccessCount is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldSuccessCount requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldSuccessCount: %w", err) + } + return oldValue.SuccessCount, nil +} + +// AddSuccessCount adds i to the "success_count" field. +func (m *EmailBroadcastMutation) AddSuccessCount(i int) { + if m.addsuccess_count != nil { + *m.addsuccess_count += i + } else { + m.addsuccess_count = &i + } +} + +// AddedSuccessCount returns the value that was added to the "success_count" field in this mutation. +func (m *EmailBroadcastMutation) AddedSuccessCount() (r int, exists bool) { + v := m.addsuccess_count + if v == nil { + return + } + return *v, true +} + +// ResetSuccessCount resets all changes to the "success_count" field. +func (m *EmailBroadcastMutation) ResetSuccessCount() { + m.success_count = nil + m.addsuccess_count = nil +} + +// SetFailedCount sets the "failed_count" field. +func (m *EmailBroadcastMutation) SetFailedCount(i int) { + m.failed_count = &i + m.addfailed_count = nil +} + +// FailedCount returns the value of the "failed_count" field in the mutation. +func (m *EmailBroadcastMutation) FailedCount() (r int, exists bool) { + v := m.failed_count + if v == nil { + return + } + return *v, true +} + +// OldFailedCount returns the old "failed_count" field's value of the EmailBroadcast entity. +// If the EmailBroadcast 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 *EmailBroadcastMutation) OldFailedCount(ctx context.Context) (v int, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldFailedCount is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldFailedCount requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldFailedCount: %w", err) + } + return oldValue.FailedCount, nil +} + +// AddFailedCount adds i to the "failed_count" field. +func (m *EmailBroadcastMutation) AddFailedCount(i int) { + if m.addfailed_count != nil { + *m.addfailed_count += i + } else { + m.addfailed_count = &i + } +} + +// AddedFailedCount returns the value that was added to the "failed_count" field in this mutation. +func (m *EmailBroadcastMutation) AddedFailedCount() (r int, exists bool) { + v := m.addfailed_count + if v == nil { + return + } + return *v, true +} + +// ResetFailedCount resets all changes to the "failed_count" field. +func (m *EmailBroadcastMutation) ResetFailedCount() { + m.failed_count = nil + m.addfailed_count = nil +} + +// SetErrorMessage sets the "error_message" field. +func (m *EmailBroadcastMutation) SetErrorMessage(s string) { + m.error_message = &s +} + +// ErrorMessage returns the value of the "error_message" field in the mutation. +func (m *EmailBroadcastMutation) ErrorMessage() (r string, exists bool) { + v := m.error_message + if v == nil { + return + } + return *v, true +} + +// OldErrorMessage returns the old "error_message" field's value of the EmailBroadcast entity. +// If the EmailBroadcast 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 *EmailBroadcastMutation) OldErrorMessage(ctx context.Context) (v *string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldErrorMessage is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldErrorMessage requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldErrorMessage: %w", err) + } + return oldValue.ErrorMessage, nil +} + +// ClearErrorMessage clears the value of the "error_message" field. +func (m *EmailBroadcastMutation) ClearErrorMessage() { + m.error_message = nil + m.clearedFields[emailbroadcast.FieldErrorMessage] = struct{}{} +} + +// ErrorMessageCleared returns if the "error_message" field was cleared in this mutation. +func (m *EmailBroadcastMutation) ErrorMessageCleared() bool { + _, ok := m.clearedFields[emailbroadcast.FieldErrorMessage] + return ok +} + +// ResetErrorMessage resets all changes to the "error_message" field. +func (m *EmailBroadcastMutation) ResetErrorMessage() { + m.error_message = nil + delete(m.clearedFields, emailbroadcast.FieldErrorMessage) +} + +// SetCreatedBy sets the "created_by" field. +func (m *EmailBroadcastMutation) SetCreatedBy(i int64) { + m.created_by = &i + m.addcreated_by = nil +} + +// CreatedBy returns the value of the "created_by" field in the mutation. +func (m *EmailBroadcastMutation) CreatedBy() (r int64, exists bool) { + v := m.created_by + if v == nil { + return + } + return *v, true +} + +// OldCreatedBy returns the old "created_by" field's value of the EmailBroadcast entity. +// If the EmailBroadcast 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 *EmailBroadcastMutation) OldCreatedBy(ctx context.Context) (v *int64, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldCreatedBy is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldCreatedBy requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldCreatedBy: %w", err) + } + return oldValue.CreatedBy, nil +} + +// AddCreatedBy adds i to the "created_by" field. +func (m *EmailBroadcastMutation) AddCreatedBy(i int64) { + if m.addcreated_by != nil { + *m.addcreated_by += i + } else { + m.addcreated_by = &i + } +} + +// AddedCreatedBy returns the value that was added to the "created_by" field in this mutation. +func (m *EmailBroadcastMutation) AddedCreatedBy() (r int64, exists bool) { + v := m.addcreated_by + if v == nil { + return + } + return *v, true +} + +// ClearCreatedBy clears the value of the "created_by" field. +func (m *EmailBroadcastMutation) ClearCreatedBy() { + m.created_by = nil + m.addcreated_by = nil + m.clearedFields[emailbroadcast.FieldCreatedBy] = struct{}{} +} + +// CreatedByCleared returns if the "created_by" field was cleared in this mutation. +func (m *EmailBroadcastMutation) CreatedByCleared() bool { + _, ok := m.clearedFields[emailbroadcast.FieldCreatedBy] + return ok +} + +// ResetCreatedBy resets all changes to the "created_by" field. +func (m *EmailBroadcastMutation) ResetCreatedBy() { + m.created_by = nil + m.addcreated_by = nil + delete(m.clearedFields, emailbroadcast.FieldCreatedBy) +} + +// SetStartedAt sets the "started_at" field. +func (m *EmailBroadcastMutation) SetStartedAt(t time.Time) { + m.started_at = &t +} + +// StartedAt returns the value of the "started_at" field in the mutation. +func (m *EmailBroadcastMutation) StartedAt() (r time.Time, exists bool) { + v := m.started_at + if v == nil { + return + } + return *v, true +} + +// OldStartedAt returns the old "started_at" field's value of the EmailBroadcast entity. +// If the EmailBroadcast 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 *EmailBroadcastMutation) OldStartedAt(ctx context.Context) (v *time.Time, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldStartedAt is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldStartedAt requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldStartedAt: %w", err) + } + return oldValue.StartedAt, nil +} + +// ClearStartedAt clears the value of the "started_at" field. +func (m *EmailBroadcastMutation) ClearStartedAt() { + m.started_at = nil + m.clearedFields[emailbroadcast.FieldStartedAt] = struct{}{} +} + +// StartedAtCleared returns if the "started_at" field was cleared in this mutation. +func (m *EmailBroadcastMutation) StartedAtCleared() bool { + _, ok := m.clearedFields[emailbroadcast.FieldStartedAt] + return ok +} + +// ResetStartedAt resets all changes to the "started_at" field. +func (m *EmailBroadcastMutation) ResetStartedAt() { + m.started_at = nil + delete(m.clearedFields, emailbroadcast.FieldStartedAt) +} + +// SetFinishedAt sets the "finished_at" field. +func (m *EmailBroadcastMutation) SetFinishedAt(t time.Time) { + m.finished_at = &t +} + +// FinishedAt returns the value of the "finished_at" field in the mutation. +func (m *EmailBroadcastMutation) FinishedAt() (r time.Time, exists bool) { + v := m.finished_at + if v == nil { + return + } + return *v, true +} + +// OldFinishedAt returns the old "finished_at" field's value of the EmailBroadcast entity. +// If the EmailBroadcast 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 *EmailBroadcastMutation) OldFinishedAt(ctx context.Context) (v *time.Time, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldFinishedAt is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldFinishedAt requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldFinishedAt: %w", err) + } + return oldValue.FinishedAt, nil +} + +// ClearFinishedAt clears the value of the "finished_at" field. +func (m *EmailBroadcastMutation) ClearFinishedAt() { + m.finished_at = nil + m.clearedFields[emailbroadcast.FieldFinishedAt] = struct{}{} +} + +// FinishedAtCleared returns if the "finished_at" field was cleared in this mutation. +func (m *EmailBroadcastMutation) FinishedAtCleared() bool { + _, ok := m.clearedFields[emailbroadcast.FieldFinishedAt] + return ok +} + +// ResetFinishedAt resets all changes to the "finished_at" field. +func (m *EmailBroadcastMutation) ResetFinishedAt() { + m.finished_at = nil + delete(m.clearedFields, emailbroadcast.FieldFinishedAt) +} + +// SetCreatedAt sets the "created_at" field. +func (m *EmailBroadcastMutation) SetCreatedAt(t time.Time) { + m.created_at = &t +} + +// CreatedAt returns the value of the "created_at" field in the mutation. +func (m *EmailBroadcastMutation) 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 EmailBroadcast entity. +// If the EmailBroadcast 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 *EmailBroadcastMutation) 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 *EmailBroadcastMutation) ResetCreatedAt() { + m.created_at = nil +} + +// SetUpdatedAt sets the "updated_at" field. +func (m *EmailBroadcastMutation) SetUpdatedAt(t time.Time) { + m.updated_at = &t +} + +// UpdatedAt returns the value of the "updated_at" field in the mutation. +func (m *EmailBroadcastMutation) 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 EmailBroadcast entity. +// If the EmailBroadcast 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 *EmailBroadcastMutation) 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 *EmailBroadcastMutation) ResetUpdatedAt() { + m.updated_at = nil +} + +// Where appends a list predicates to the EmailBroadcastMutation builder. +func (m *EmailBroadcastMutation) Where(ps ...predicate.EmailBroadcast) { + m.predicates = append(m.predicates, ps...) +} + +// WhereP appends storage-level predicates to the EmailBroadcastMutation builder. Using this method, +// users can use type-assertion to append predicates that do not depend on any generated package. +func (m *EmailBroadcastMutation) WhereP(ps ...func(*sql.Selector)) { + p := make([]predicate.EmailBroadcast, len(ps)) + for i := range ps { + p[i] = ps[i] + } + m.Where(p...) +} + +// Op returns the operation name. +func (m *EmailBroadcastMutation) Op() Op { + return m.op +} + +// SetOp allows setting the mutation operation. +func (m *EmailBroadcastMutation) SetOp(op Op) { + m.op = op +} + +// Type returns the node type of this mutation (EmailBroadcast). +func (m *EmailBroadcastMutation) 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 *EmailBroadcastMutation) Fields() []string { + fields := make([]string, 0, 15) + if m.subject != nil { + fields = append(fields, emailbroadcast.FieldSubject) + } + if m.body != nil { + fields = append(fields, emailbroadcast.FieldBody) + } + if m.body_format != nil { + fields = append(fields, emailbroadcast.FieldBodyFormat) + } + if m.recipients_mode != nil { + fields = append(fields, emailbroadcast.FieldRecipientsMode) + } + if m.recipient_user_ids != nil { + fields = append(fields, emailbroadcast.FieldRecipientUserIds) + } + if m.status != nil { + fields = append(fields, emailbroadcast.FieldStatus) + } + if m.total_count != nil { + fields = append(fields, emailbroadcast.FieldTotalCount) + } + if m.success_count != nil { + fields = append(fields, emailbroadcast.FieldSuccessCount) + } + if m.failed_count != nil { + fields = append(fields, emailbroadcast.FieldFailedCount) + } + if m.error_message != nil { + fields = append(fields, emailbroadcast.FieldErrorMessage) + } + if m.created_by != nil { + fields = append(fields, emailbroadcast.FieldCreatedBy) + } + if m.started_at != nil { + fields = append(fields, emailbroadcast.FieldStartedAt) + } + if m.finished_at != nil { + fields = append(fields, emailbroadcast.FieldFinishedAt) + } + if m.created_at != nil { + fields = append(fields, emailbroadcast.FieldCreatedAt) + } + if m.updated_at != nil { + fields = append(fields, emailbroadcast.FieldUpdatedAt) + } + 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 *EmailBroadcastMutation) Field(name string) (ent.Value, bool) { + switch name { + case emailbroadcast.FieldSubject: + return m.Subject() + case emailbroadcast.FieldBody: + return m.Body() + case emailbroadcast.FieldBodyFormat: + return m.BodyFormat() + case emailbroadcast.FieldRecipientsMode: + return m.RecipientsMode() + case emailbroadcast.FieldRecipientUserIds: + return m.RecipientUserIds() + case emailbroadcast.FieldStatus: + return m.Status() + case emailbroadcast.FieldTotalCount: + return m.TotalCount() + case emailbroadcast.FieldSuccessCount: + return m.SuccessCount() + case emailbroadcast.FieldFailedCount: + return m.FailedCount() + case emailbroadcast.FieldErrorMessage: + return m.ErrorMessage() + case emailbroadcast.FieldCreatedBy: + return m.CreatedBy() + case emailbroadcast.FieldStartedAt: + return m.StartedAt() + case emailbroadcast.FieldFinishedAt: + return m.FinishedAt() + case emailbroadcast.FieldCreatedAt: + return m.CreatedAt() + case emailbroadcast.FieldUpdatedAt: + return m.UpdatedAt() + } + 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 *EmailBroadcastMutation) OldField(ctx context.Context, name string) (ent.Value, error) { + switch name { + case emailbroadcast.FieldSubject: + return m.OldSubject(ctx) + case emailbroadcast.FieldBody: + return m.OldBody(ctx) + case emailbroadcast.FieldBodyFormat: + return m.OldBodyFormat(ctx) + case emailbroadcast.FieldRecipientsMode: + return m.OldRecipientsMode(ctx) + case emailbroadcast.FieldRecipientUserIds: + return m.OldRecipientUserIds(ctx) + case emailbroadcast.FieldStatus: + return m.OldStatus(ctx) + case emailbroadcast.FieldTotalCount: + return m.OldTotalCount(ctx) + case emailbroadcast.FieldSuccessCount: + return m.OldSuccessCount(ctx) + case emailbroadcast.FieldFailedCount: + return m.OldFailedCount(ctx) + case emailbroadcast.FieldErrorMessage: + return m.OldErrorMessage(ctx) + case emailbroadcast.FieldCreatedBy: + return m.OldCreatedBy(ctx) + case emailbroadcast.FieldStartedAt: + return m.OldStartedAt(ctx) + case emailbroadcast.FieldFinishedAt: + return m.OldFinishedAt(ctx) + case emailbroadcast.FieldCreatedAt: + return m.OldCreatedAt(ctx) + case emailbroadcast.FieldUpdatedAt: + return m.OldUpdatedAt(ctx) + } + return nil, fmt.Errorf("unknown EmailBroadcast 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 *EmailBroadcastMutation) SetField(name string, value ent.Value) error { + switch name { + case emailbroadcast.FieldSubject: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetSubject(v) + return nil + case emailbroadcast.FieldBody: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetBody(v) + return nil + case emailbroadcast.FieldBodyFormat: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetBodyFormat(v) + return nil + case emailbroadcast.FieldRecipientsMode: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetRecipientsMode(v) + return nil + case emailbroadcast.FieldRecipientUserIds: + v, ok := value.([]int64) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetRecipientUserIds(v) + return nil + case emailbroadcast.FieldStatus: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetStatus(v) + return nil + case emailbroadcast.FieldTotalCount: + v, ok := value.(int) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetTotalCount(v) + return nil + case emailbroadcast.FieldSuccessCount: + v, ok := value.(int) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetSuccessCount(v) + return nil + case emailbroadcast.FieldFailedCount: + v, ok := value.(int) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetFailedCount(v) + return nil + case emailbroadcast.FieldErrorMessage: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetErrorMessage(v) + return nil + case emailbroadcast.FieldCreatedBy: + v, ok := value.(int64) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetCreatedBy(v) + return nil + case emailbroadcast.FieldStartedAt: + v, ok := value.(time.Time) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetStartedAt(v) + return nil + case emailbroadcast.FieldFinishedAt: + v, ok := value.(time.Time) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetFinishedAt(v) + return nil + case emailbroadcast.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 emailbroadcast.FieldUpdatedAt: + v, ok := value.(time.Time) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetUpdatedAt(v) + return nil + } + return fmt.Errorf("unknown EmailBroadcast field %s", name) +} + +// AddedFields returns all numeric fields that were incremented/decremented during +// this mutation. +func (m *EmailBroadcastMutation) AddedFields() []string { + var fields []string + if m.addtotal_count != nil { + fields = append(fields, emailbroadcast.FieldTotalCount) + } + if m.addsuccess_count != nil { + fields = append(fields, emailbroadcast.FieldSuccessCount) + } + if m.addfailed_count != nil { + fields = append(fields, emailbroadcast.FieldFailedCount) + } + if m.addcreated_by != nil { + fields = append(fields, emailbroadcast.FieldCreatedBy) + } + 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 *EmailBroadcastMutation) AddedField(name string) (ent.Value, bool) { + switch name { + case emailbroadcast.FieldTotalCount: + return m.AddedTotalCount() + case emailbroadcast.FieldSuccessCount: + return m.AddedSuccessCount() + case emailbroadcast.FieldFailedCount: + return m.AddedFailedCount() + case emailbroadcast.FieldCreatedBy: + return m.AddedCreatedBy() + } + 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 *EmailBroadcastMutation) AddField(name string, value ent.Value) error { + switch name { + case emailbroadcast.FieldTotalCount: + v, ok := value.(int) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.AddTotalCount(v) + return nil + case emailbroadcast.FieldSuccessCount: + v, ok := value.(int) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.AddSuccessCount(v) + return nil + case emailbroadcast.FieldFailedCount: + v, ok := value.(int) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.AddFailedCount(v) + return nil + case emailbroadcast.FieldCreatedBy: + v, ok := value.(int64) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.AddCreatedBy(v) + return nil + } + return fmt.Errorf("unknown EmailBroadcast numeric field %s", name) +} + +// ClearedFields returns all nullable fields that were cleared during this +// mutation. +func (m *EmailBroadcastMutation) ClearedFields() []string { + var fields []string + if m.FieldCleared(emailbroadcast.FieldRecipientUserIds) { + fields = append(fields, emailbroadcast.FieldRecipientUserIds) + } + if m.FieldCleared(emailbroadcast.FieldErrorMessage) { + fields = append(fields, emailbroadcast.FieldErrorMessage) + } + if m.FieldCleared(emailbroadcast.FieldCreatedBy) { + fields = append(fields, emailbroadcast.FieldCreatedBy) + } + if m.FieldCleared(emailbroadcast.FieldStartedAt) { + fields = append(fields, emailbroadcast.FieldStartedAt) + } + if m.FieldCleared(emailbroadcast.FieldFinishedAt) { + fields = append(fields, emailbroadcast.FieldFinishedAt) + } + return fields +} + +// FieldCleared returns a boolean indicating if a field with the given name was +// cleared in this mutation. +func (m *EmailBroadcastMutation) 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 *EmailBroadcastMutation) ClearField(name string) error { + switch name { + case emailbroadcast.FieldRecipientUserIds: + m.ClearRecipientUserIds() + return nil + case emailbroadcast.FieldErrorMessage: + m.ClearErrorMessage() + return nil + case emailbroadcast.FieldCreatedBy: + m.ClearCreatedBy() + return nil + case emailbroadcast.FieldStartedAt: + m.ClearStartedAt() + return nil + case emailbroadcast.FieldFinishedAt: + m.ClearFinishedAt() + return nil + } + return fmt.Errorf("unknown EmailBroadcast 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 *EmailBroadcastMutation) ResetField(name string) error { + switch name { + case emailbroadcast.FieldSubject: + m.ResetSubject() + return nil + case emailbroadcast.FieldBody: + m.ResetBody() + return nil + case emailbroadcast.FieldBodyFormat: + m.ResetBodyFormat() + return nil + case emailbroadcast.FieldRecipientsMode: + m.ResetRecipientsMode() + return nil + case emailbroadcast.FieldRecipientUserIds: + m.ResetRecipientUserIds() + return nil + case emailbroadcast.FieldStatus: + m.ResetStatus() + return nil + case emailbroadcast.FieldTotalCount: + m.ResetTotalCount() + return nil + case emailbroadcast.FieldSuccessCount: + m.ResetSuccessCount() + return nil + case emailbroadcast.FieldFailedCount: + m.ResetFailedCount() + return nil + case emailbroadcast.FieldErrorMessage: + m.ResetErrorMessage() + return nil + case emailbroadcast.FieldCreatedBy: + m.ResetCreatedBy() + return nil + case emailbroadcast.FieldStartedAt: + m.ResetStartedAt() + return nil + case emailbroadcast.FieldFinishedAt: + m.ResetFinishedAt() + return nil + case emailbroadcast.FieldCreatedAt: + m.ResetCreatedAt() + return nil + case emailbroadcast.FieldUpdatedAt: + m.ResetUpdatedAt() + return nil + } + return fmt.Errorf("unknown EmailBroadcast field %s", name) +} + +// AddedEdges returns all edge names that were set/added in this mutation. +func (m *EmailBroadcastMutation) AddedEdges() []string { + edges := make([]string, 0, 0) + return edges +} + +// AddedIDs returns all IDs (to other nodes) that were added for the given edge +// name in this mutation. +func (m *EmailBroadcastMutation) AddedIDs(name string) []ent.Value { + return nil +} + +// RemovedEdges returns all edge names that were removed in this mutation. +func (m *EmailBroadcastMutation) RemovedEdges() []string { + edges := make([]string, 0, 0) + return edges +} + +// RemovedIDs returns all IDs (to other nodes) that were removed for the edge with +// the given name in this mutation. +func (m *EmailBroadcastMutation) RemovedIDs(name string) []ent.Value { + return nil +} + +// ClearedEdges returns all edge names that were cleared in this mutation. +func (m *EmailBroadcastMutation) ClearedEdges() []string { + edges := make([]string, 0, 0) + return edges +} + +// EdgeCleared returns a boolean which indicates if the edge with the given name +// was cleared in this mutation. +func (m *EmailBroadcastMutation) EdgeCleared(name string) bool { + return false +} + +// ClearEdge clears the value of the edge with the given name. It returns an error +// if that edge is not defined in the schema. +func (m *EmailBroadcastMutation) ClearEdge(name string) error { + return fmt.Errorf("unknown EmailBroadcast 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 *EmailBroadcastMutation) ResetEdge(name string) error { + return fmt.Errorf("unknown EmailBroadcast edge %s", name) +} + // ErrorPassthroughRuleMutation represents an operation that mutates the ErrorPassthroughRule nodes in the graph. type ErrorPassthroughRuleMutation struct { config diff --git a/backend/ent/predicate/predicate.go b/backend/ent/predicate/predicate.go index ab4d7d1827d..95207037980 100644 --- a/backend/ent/predicate/predicate.go +++ b/backend/ent/predicate/predicate.go @@ -39,6 +39,9 @@ type ChannelMonitorHistory func(*sql.Selector) // ChannelMonitorRequestTemplate is the predicate function for channelmonitorrequesttemplate builders. type ChannelMonitorRequestTemplate func(*sql.Selector) +// EmailBroadcast is the predicate function for emailbroadcast builders. +type EmailBroadcast func(*sql.Selector) + // ErrorPassthroughRule is the predicate function for errorpassthroughrule builders. type ErrorPassthroughRule func(*sql.Selector) diff --git a/backend/ent/runtime/runtime.go b/backend/ent/runtime/runtime.go index fdb837e805f..f05bbeb7a9e 100644 --- a/backend/ent/runtime/runtime.go +++ b/backend/ent/runtime/runtime.go @@ -16,6 +16,7 @@ import ( "github.com/Wei-Shaw/sub2api/ent/channelmonitordailyrollup" "github.com/Wei-Shaw/sub2api/ent/channelmonitorhistory" "github.com/Wei-Shaw/sub2api/ent/channelmonitorrequesttemplate" + "github.com/Wei-Shaw/sub2api/ent/emailbroadcast" "github.com/Wei-Shaw/sub2api/ent/errorpassthroughrule" "github.com/Wei-Shaw/sub2api/ent/group" "github.com/Wei-Shaw/sub2api/ent/idempotencyrecord" @@ -690,6 +691,76 @@ func init() { channelmonitorrequesttemplate.DefaultBodyOverrideMode = channelmonitorrequesttemplateDescBodyOverrideMode.Default.(string) // channelmonitorrequesttemplate.BodyOverrideModeValidator is a validator for the "body_override_mode" field. It is called by the builders before save. channelmonitorrequesttemplate.BodyOverrideModeValidator = channelmonitorrequesttemplateDescBodyOverrideMode.Validators[0].(func(string) error) + emailbroadcastFields := schema.EmailBroadcast{}.Fields() + _ = emailbroadcastFields + // emailbroadcastDescSubject is the schema descriptor for subject field. + emailbroadcastDescSubject := emailbroadcastFields[0].Descriptor() + // emailbroadcast.SubjectValidator is a validator for the "subject" field. It is called by the builders before save. + emailbroadcast.SubjectValidator = func() func(string) error { + validators := emailbroadcastDescSubject.Validators + fns := [...]func(string) error{ + validators[0].(func(string) error), + validators[1].(func(string) error), + } + return func(subject string) error { + for _, fn := range fns { + if err := fn(subject); err != nil { + return err + } + } + return nil + } + }() + // emailbroadcastDescBody is the schema descriptor for body field. + emailbroadcastDescBody := emailbroadcastFields[1].Descriptor() + // emailbroadcast.BodyValidator is a validator for the "body" field. It is called by the builders before save. + emailbroadcast.BodyValidator = emailbroadcastDescBody.Validators[0].(func(string) error) + // emailbroadcastDescBodyFormat is the schema descriptor for body_format field. + emailbroadcastDescBodyFormat := emailbroadcastFields[2].Descriptor() + // emailbroadcast.DefaultBodyFormat holds the default value on creation for the body_format field. + emailbroadcast.DefaultBodyFormat = emailbroadcastDescBodyFormat.Default.(string) + // emailbroadcast.BodyFormatValidator is a validator for the "body_format" field. It is called by the builders before save. + emailbroadcast.BodyFormatValidator = emailbroadcastDescBodyFormat.Validators[0].(func(string) error) + // emailbroadcastDescRecipientsMode is the schema descriptor for recipients_mode field. + emailbroadcastDescRecipientsMode := emailbroadcastFields[3].Descriptor() + // emailbroadcast.DefaultRecipientsMode holds the default value on creation for the recipients_mode field. + emailbroadcast.DefaultRecipientsMode = emailbroadcastDescRecipientsMode.Default.(string) + // emailbroadcast.RecipientsModeValidator is a validator for the "recipients_mode" field. It is called by the builders before save. + emailbroadcast.RecipientsModeValidator = emailbroadcastDescRecipientsMode.Validators[0].(func(string) error) + // emailbroadcastDescStatus is the schema descriptor for status field. + emailbroadcastDescStatus := emailbroadcastFields[5].Descriptor() + // emailbroadcast.DefaultStatus holds the default value on creation for the status field. + emailbroadcast.DefaultStatus = emailbroadcastDescStatus.Default.(string) + // emailbroadcast.StatusValidator is a validator for the "status" field. It is called by the builders before save. + emailbroadcast.StatusValidator = emailbroadcastDescStatus.Validators[0].(func(string) error) + // emailbroadcastDescTotalCount is the schema descriptor for total_count field. + emailbroadcastDescTotalCount := emailbroadcastFields[6].Descriptor() + // emailbroadcast.DefaultTotalCount holds the default value on creation for the total_count field. + emailbroadcast.DefaultTotalCount = emailbroadcastDescTotalCount.Default.(int) + // emailbroadcast.TotalCountValidator is a validator for the "total_count" field. It is called by the builders before save. + emailbroadcast.TotalCountValidator = emailbroadcastDescTotalCount.Validators[0].(func(int) error) + // emailbroadcastDescSuccessCount is the schema descriptor for success_count field. + emailbroadcastDescSuccessCount := emailbroadcastFields[7].Descriptor() + // emailbroadcast.DefaultSuccessCount holds the default value on creation for the success_count field. + emailbroadcast.DefaultSuccessCount = emailbroadcastDescSuccessCount.Default.(int) + // emailbroadcast.SuccessCountValidator is a validator for the "success_count" field. It is called by the builders before save. + emailbroadcast.SuccessCountValidator = emailbroadcastDescSuccessCount.Validators[0].(func(int) error) + // emailbroadcastDescFailedCount is the schema descriptor for failed_count field. + emailbroadcastDescFailedCount := emailbroadcastFields[8].Descriptor() + // emailbroadcast.DefaultFailedCount holds the default value on creation for the failed_count field. + emailbroadcast.DefaultFailedCount = emailbroadcastDescFailedCount.Default.(int) + // emailbroadcast.FailedCountValidator is a validator for the "failed_count" field. It is called by the builders before save. + emailbroadcast.FailedCountValidator = emailbroadcastDescFailedCount.Validators[0].(func(int) error) + // emailbroadcastDescCreatedAt is the schema descriptor for created_at field. + emailbroadcastDescCreatedAt := emailbroadcastFields[13].Descriptor() + // emailbroadcast.DefaultCreatedAt holds the default value on creation for the created_at field. + emailbroadcast.DefaultCreatedAt = emailbroadcastDescCreatedAt.Default.(func() time.Time) + // emailbroadcastDescUpdatedAt is the schema descriptor for updated_at field. + emailbroadcastDescUpdatedAt := emailbroadcastFields[14].Descriptor() + // emailbroadcast.DefaultUpdatedAt holds the default value on creation for the updated_at field. + emailbroadcast.DefaultUpdatedAt = emailbroadcastDescUpdatedAt.Default.(func() time.Time) + // emailbroadcast.UpdateDefaultUpdatedAt holds the default value on update for the updated_at field. + emailbroadcast.UpdateDefaultUpdatedAt = emailbroadcastDescUpdatedAt.UpdateDefault.(func() time.Time) errorpassthroughruleMixin := schema.ErrorPassthroughRule{}.Mixin() errorpassthroughruleMixinFields0 := errorpassthroughruleMixin[0].Fields() _ = errorpassthroughruleMixinFields0 diff --git a/backend/ent/schema/email_broadcast.go b/backend/ent/schema/email_broadcast.go new file mode 100644 index 00000000000..236a06e0514 --- /dev/null +++ b/backend/ent/schema/email_broadcast.go @@ -0,0 +1,102 @@ +package schema + +import ( + "time" + + "github.com/Wei-Shaw/sub2api/internal/domain" + + "entgo.io/ent" + "entgo.io/ent/dialect" + "entgo.io/ent/dialect/entsql" + "entgo.io/ent/schema" + "entgo.io/ent/schema/field" + "entgo.io/ent/schema/index" +) + +// EmailBroadcast 管理员批量公告邮件记录。 +// EmailBroadcast records an admin-issued bulk announcement email batch. +type EmailBroadcast struct { + ent.Schema +} + +func (EmailBroadcast) Annotations() []schema.Annotation { + return []schema.Annotation{ + entsql.Annotation{Table: "email_broadcasts"}, + } +} + +func (EmailBroadcast) Fields() []ent.Field { + return []ent.Field{ + field.String("subject"). + MaxLen(200). + NotEmpty(). + Comment("邮件主题"), + field.String("body"). + SchemaType(map[string]string{dialect.Postgres: "text"}). + NotEmpty(). + Comment("邮件正文 (HTML 或纯文本)"), + field.String("body_format"). + MaxLen(10). + Default(domain.EmailBroadcastBodyFormatHTML). + Comment("正文格式: html, text"), + field.String("recipients_mode"). + MaxLen(20). + Default(domain.EmailBroadcastRecipientsModeSelected). + Comment("收件人模式: all, selected"), + field.JSON("recipient_user_ids", []int64{}). + Optional(). + SchemaType(map[string]string{dialect.Postgres: "jsonb"}). + Comment("收件人用户 ID 列表 (selected 模式时使用)"), + field.String("status"). + MaxLen(20). + Default(domain.EmailBroadcastStatusPending). + Comment("状态: pending, sending, completed, failed"), + field.Int("total_count"). + Default(0). + NonNegative(). + Comment("收件人总数"), + field.Int("success_count"). + Default(0). + NonNegative(). + Comment("发送成功数"), + field.Int("failed_count"). + Default(0). + NonNegative(). + Comment("发送失败数"), + field.String("error_message"). + SchemaType(map[string]string{dialect.Postgres: "text"}). + Optional(). + Nillable(). + Comment("整批失败原因 (status=failed 时填充)"), + field.Int64("created_by"). + Optional(). + Nillable(). + Comment("创建管理员用户 ID"), + field.Time("started_at"). + Optional(). + Nillable(). + SchemaType(map[string]string{dialect.Postgres: "timestamptz"}). + Comment("开始发送时间"), + field.Time("finished_at"). + Optional(). + Nillable(). + SchemaType(map[string]string{dialect.Postgres: "timestamptz"}). + Comment("发送结束时间"), + field.Time("created_at"). + Immutable(). + Default(time.Now). + SchemaType(map[string]string{dialect.Postgres: "timestamptz"}), + field.Time("updated_at"). + Default(time.Now). + UpdateDefault(time.Now). + SchemaType(map[string]string{dialect.Postgres: "timestamptz"}), + } +} + +func (EmailBroadcast) Indexes() []ent.Index { + return []ent.Index{ + index.Fields("status"), + index.Fields("created_at"), + index.Fields("created_by"), + } +} diff --git a/backend/ent/tx.go b/backend/ent/tx.go index 846cfcd4dac..0ba5f4481d2 100644 --- a/backend/ent/tx.go +++ b/backend/ent/tx.go @@ -36,6 +36,8 @@ type Tx struct { ChannelMonitorHistory *ChannelMonitorHistoryClient // ChannelMonitorRequestTemplate is the client for interacting with the ChannelMonitorRequestTemplate builders. ChannelMonitorRequestTemplate *ChannelMonitorRequestTemplateClient + // EmailBroadcast is the client for interacting with the EmailBroadcast builders. + EmailBroadcast *EmailBroadcastClient // ErrorPassthroughRule is the client for interacting with the ErrorPassthroughRule builders. ErrorPassthroughRule *ErrorPassthroughRuleClient // Group is the client for interacting with the Group builders. @@ -226,6 +228,7 @@ func (tx *Tx) init() { tx.ChannelMonitorDailyRollup = NewChannelMonitorDailyRollupClient(tx.config) tx.ChannelMonitorHistory = NewChannelMonitorHistoryClient(tx.config) tx.ChannelMonitorRequestTemplate = NewChannelMonitorRequestTemplateClient(tx.config) + tx.EmailBroadcast = NewEmailBroadcastClient(tx.config) tx.ErrorPassthroughRule = NewErrorPassthroughRuleClient(tx.config) tx.Group = NewGroupClient(tx.config) tx.IdempotencyRecord = NewIdempotencyRecordClient(tx.config) diff --git a/backend/internal/domain/email_broadcast.go b/backend/internal/domain/email_broadcast.go new file mode 100644 index 00000000000..ad60c09d913 --- /dev/null +++ b/backend/internal/domain/email_broadcast.go @@ -0,0 +1,47 @@ +package domain + +import ( + infraerrors "github.com/Wei-Shaw/sub2api/internal/pkg/errors" +) + +// Email broadcast body formats. +const ( + EmailBroadcastBodyFormatHTML = "html" + EmailBroadcastBodyFormatText = "text" +) + +// Email broadcast recipient modes. +const ( + EmailBroadcastRecipientsModeAll = "all" + EmailBroadcastRecipientsModeSelected = "selected" +) + +// Email broadcast lifecycle statuses. +const ( + EmailBroadcastStatusPending = "pending" + EmailBroadcastStatusSending = "sending" + EmailBroadcastStatusCompleted = "completed" + EmailBroadcastStatusFailed = "failed" +) + +// EmailBroadcastSubjectMaxLen 邮件主题最大字符数 (与 schema 约束保持一致)。 +const EmailBroadcastSubjectMaxLen = 200 + +// EmailBroadcastBodyMaxLen 邮件正文最大字符数 (上限保护,防止 DoS)。 +const EmailBroadcastBodyMaxLen = 65536 + +// EmailBroadcastMaxSelectedRecipients selected 模式下单次最大收件人数量。 +const EmailBroadcastMaxSelectedRecipients = 5000 + +var ( + ErrEmailBroadcastNotFound = infraerrors.NotFound("EMAIL_BROADCAST_NOT_FOUND", "email broadcast not found") + ErrEmailBroadcastSubjectRequired = infraerrors.BadRequest("EMAIL_BROADCAST_SUBJECT_REQUIRED", "email broadcast subject is required") + ErrEmailBroadcastBodyRequired = infraerrors.BadRequest("EMAIL_BROADCAST_BODY_REQUIRED", "email broadcast body is required") + ErrEmailBroadcastSubjectTooLong = infraerrors.BadRequest("EMAIL_BROADCAST_SUBJECT_TOO_LONG", "email broadcast subject exceeds maximum length") + ErrEmailBroadcastBodyTooLong = infraerrors.BadRequest("EMAIL_BROADCAST_BODY_TOO_LONG", "email broadcast body exceeds maximum length") + ErrEmailBroadcastInvalidBodyFormat = infraerrors.BadRequest("EMAIL_BROADCAST_INVALID_BODY_FORMAT", "email broadcast body format must be html or text") + ErrEmailBroadcastInvalidMode = infraerrors.BadRequest("EMAIL_BROADCAST_INVALID_MODE", "email broadcast recipients mode must be all or selected") + ErrEmailBroadcastNoRecipients = infraerrors.BadRequest("EMAIL_BROADCAST_NO_RECIPIENTS", "email broadcast requires at least one recipient") + ErrEmailBroadcastTooManyRecipients = infraerrors.BadRequest("EMAIL_BROADCAST_TOO_MANY_RECIPIENTS", "email broadcast recipient count exceeds maximum") + ErrEmailBroadcastEmailNotConfigured = infraerrors.BadRequest("EMAIL_BROADCAST_EMAIL_NOT_CONFIGURED", "SMTP/email service is not configured") +) diff --git a/backend/migrations/145_email_broadcasts.sql b/backend/migrations/145_email_broadcasts.sql new file mode 100644 index 00000000000..950766d3a10 --- /dev/null +++ b/backend/migrations/145_email_broadcasts.sql @@ -0,0 +1,35 @@ +-- 管理员批量公告邮件记录表 / admin bulk-announcement email broadcasts. +-- 用途:记录每次管理员发起的"广播公告邮件"批次,包括正文、收件人、聚合状态与计数。 +-- Purpose: persist each admin-initiated broadcast for audit/history/retry. + +CREATE TABLE IF NOT EXISTS email_broadcasts ( + id BIGSERIAL PRIMARY KEY, + subject VARCHAR(200) NOT NULL, + body TEXT NOT NULL, + body_format VARCHAR(10) NOT NULL DEFAULT 'html', + recipients_mode VARCHAR(20) NOT NULL DEFAULT 'selected', + recipient_user_ids JSONB, + status VARCHAR(20) NOT NULL DEFAULT 'pending', + total_count INTEGER NOT NULL DEFAULT 0, + success_count INTEGER NOT NULL DEFAULT 0, + failed_count INTEGER NOT NULL DEFAULT 0, + error_message TEXT, + created_by BIGINT, + started_at TIMESTAMPTZ, + finished_at TIMESTAMPTZ, + created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), + updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), + + CONSTRAINT email_broadcasts_status_check + CHECK (status IN ('pending', 'sending', 'completed', 'failed')), + CONSTRAINT email_broadcasts_body_format_check + CHECK (body_format IN ('html', 'text')), + CONSTRAINT email_broadcasts_recipients_mode_check + CHECK (recipients_mode IN ('all', 'selected')), + CONSTRAINT email_broadcasts_counts_non_negative + CHECK (total_count >= 0 AND success_count >= 0 AND failed_count >= 0) +); + +CREATE INDEX IF NOT EXISTS idx_email_broadcasts_status ON email_broadcasts (status); +CREATE INDEX IF NOT EXISTS idx_email_broadcasts_created_at ON email_broadcasts (created_at DESC); +CREATE INDEX IF NOT EXISTS idx_email_broadcasts_created_by ON email_broadcasts (created_by); From 9b7bacb88527a51163444c27f8f046fbee38cdb7 Mon Sep 17 00:00:00 2001 From: hyrhyrh Date: Sat, 30 May 2026 00:11:46 +0000 Subject: [PATCH 02/10] feat(email-broadcast): add repository + broadcast service MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 新增 EmailBroadcastRepository(ent 后端) 与 EmailBroadcastService。 service 负责输入校验、SMTP 配置预检、bluemonday HTML sanitize、 异步执行收件人解析与逐封 SMTP 投递,并把成功 / 失败计数增量写回。 同时为 EmailService 增加 SendEmailWithConfigAndContentType, 允许调用方自定义 MIME Content-Type(纯文本广播会以 text/html 包装, 保持邮件 MIME 一致并启用基础排版)。 EmailBroadcastService validates inputs, pre-checks the SMTP config, sanitizes HTML through bluemonday, expands recipients (either all registered users or an explicit ID list) and dispatches each mail with a small per-message throttle. Counters are written back to the database incrementally so list views show live progress. EmailService gains SendEmailWithConfigAndContentType so callers can choose the MIME Content-Type (existing helpers keep their html default). --- backend/go.mod | 3 + backend/go.sum | 6 + .../repository/email_broadcast_repo.go | 185 ++++++++ backend/internal/repository/wire.go | 1 + backend/internal/service/email_broadcast.go | 99 ++++ .../service/email_broadcast_service.go | 422 ++++++++++++++++++ .../service/email_broadcast_service_test.go | 210 +++++++++ backend/internal/service/email_service.go | 19 +- backend/internal/service/wire.go | 1 + 9 files changed, 943 insertions(+), 3 deletions(-) create mode 100644 backend/internal/repository/email_broadcast_repo.go create mode 100644 backend/internal/service/email_broadcast.go create mode 100644 backend/internal/service/email_broadcast_service.go create mode 100644 backend/internal/service/email_broadcast_service_test.go diff --git a/backend/go.mod b/backend/go.mod index 587d53701f2..0ddc98c3ca9 100644 --- a/backend/go.mod +++ b/backend/go.mod @@ -73,6 +73,7 @@ require ( github.com/aws/aws-sdk-go-v2/service/sso v1.30.11 // indirect github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.15 // indirect github.com/aws/aws-sdk-go-v2/service/sts v1.41.7 // indirect + github.com/aymerick/douceur v0.2.0 // indirect github.com/bmatcuk/doublestar v1.3.4 // indirect github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc // indirect github.com/bytedance/sonic v1.9.1 // indirect @@ -106,6 +107,7 @@ require ( github.com/goccy/go-json v0.10.2 // indirect github.com/google/go-cmp v0.7.0 // indirect github.com/google/go-querystring v1.1.0 // indirect + github.com/gorilla/css v1.0.1 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.3 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/hashicorp/hcl/v2 v2.18.1 // indirect @@ -118,6 +120,7 @@ require ( github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mdelapenya/tlscert v0.2.0 // indirect + github.com/microcosm-cc/bluemonday v1.0.27 // indirect github.com/mitchellh/go-wordwrap v1.0.1 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect diff --git a/backend/go.sum b/backend/go.sum index 7735fda29e3..7a520e24a42 100644 --- a/backend/go.sum +++ b/backend/go.sum @@ -62,6 +62,8 @@ github.com/aws/aws-sdk-go-v2/service/sts v1.41.7 h1:NITQpgo9A5NrDZ57uOWj+abvXSb8 github.com/aws/aws-sdk-go-v2/service/sts v1.41.7/go.mod h1:sks5UWBhEuWYDPdwlnRFn1w7xWdH29Jcpe+/PJQefEs= github.com/aws/smithy-go v1.24.2 h1:FzA3bu/nt/vDvmnkg+R8Xl46gmzEDam6mZ1hzmwXFng= github.com/aws/smithy-go v1.24.2/go.mod h1:YE2RhdIuDbA5E5bTdciG9KrW3+TiEONeUWCqxX9i1Fc= +github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk= +github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4= github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/bmatcuk/doublestar v1.3.4 h1:gPypJ5xD31uhX6Tf54sDPUOBXTqKH4c9aPY66CyQrS0= @@ -168,6 +170,8 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/wire v0.7.0 h1:JxUKI6+CVBgCO2WToKy/nQk0sS+amI9z9EjVmdaocj4= github.com/google/wire v0.7.0/go.mod h1:n6YbUQD9cPKTnHXEBN2DXlOp/mVADhVErcMFb0v3J18= +github.com/gorilla/css v1.0.1 h1:ntNaBIghp6JmvWnxbZKANoLyuXTPZ4cAMlo6RyhlbO8= +github.com/gorilla/css v1.0.1/go.mod h1:BvnYkspnSzMmwRK+b8/xgNPLiIuNZr6vbZBTPQ2A3b0= github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.3 h1:NmZ1PKzSTQbuGHw9DGPFomqkkLWMC+vZCkfs+FHv1Vg= @@ -224,6 +228,8 @@ github.com/mattn/go-sqlite3 v1.14.17 h1:mCRHCLDUBXgpKAqIKsaAaAsrAlbkeomtRFKXh2L6 github.com/mattn/go-sqlite3 v1.14.17/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= github.com/mdelapenya/tlscert v0.2.0 h1:7H81W6Z/4weDvZBNOfQte5GpIMo0lGYEeWbkGp5LJHI= github.com/mdelapenya/tlscert v0.2.0/go.mod h1:O4njj3ELLnJjGdkN7M/vIVCpZ+Cf0L6muqOG4tLSl8o= +github.com/microcosm-cc/bluemonday v1.0.27 h1:MpEUotklkwCSLeH+Qdx1VJgNqLlpY2KXwXFM08ygZfk= +github.com/microcosm-cc/bluemonday v1.0.27/go.mod h1:jFi9vgW+H7c3V0lb6nR74Ib/DIB5OBs92Dimizgw2cA= github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0= github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= diff --git a/backend/internal/repository/email_broadcast_repo.go b/backend/internal/repository/email_broadcast_repo.go new file mode 100644 index 00000000000..6dad75cb5c5 --- /dev/null +++ b/backend/internal/repository/email_broadcast_repo.go @@ -0,0 +1,185 @@ +package repository + +import ( + "context" + + dbent "github.com/Wei-Shaw/sub2api/ent" + "github.com/Wei-Shaw/sub2api/ent/emailbroadcast" + "github.com/Wei-Shaw/sub2api/internal/service" +) + +type emailBroadcastRepository struct { + client *dbent.Client +} + +// NewEmailBroadcastRepository wires an ent-backed EmailBroadcastRepository. +func NewEmailBroadcastRepository(client *dbent.Client) service.EmailBroadcastRepository { + return &emailBroadcastRepository{client: client} +} + +func (r *emailBroadcastRepository) Create(ctx context.Context, b *service.EmailBroadcast) error { + client := clientFromContext(ctx, r.client) + builder := client.EmailBroadcast.Create(). + SetSubject(b.Subject). + SetBody(b.Body). + SetBodyFormat(b.BodyFormat). + SetRecipientsMode(b.RecipientsMode). + SetStatus(b.Status). + SetTotalCount(b.TotalCount). + SetSuccessCount(b.SuccessCount). + SetFailedCount(b.FailedCount) + + if len(b.RecipientUserIDs) > 0 { + builder.SetRecipientUserIds(b.RecipientUserIDs) + } + if b.CreatedBy != nil { + builder.SetCreatedBy(*b.CreatedBy) + } + if b.ErrorMessage != nil { + builder.SetErrorMessage(*b.ErrorMessage) + } + if b.StartedAt != nil { + builder.SetStartedAt(*b.StartedAt) + } + if b.FinishedAt != nil { + builder.SetFinishedAt(*b.FinishedAt) + } + + created, err := builder.Save(ctx) + if err != nil { + return err + } + applyEmailBroadcastEntityToService(b, created) + return nil +} + +func (r *emailBroadcastRepository) GetByID(ctx context.Context, id int64) (*service.EmailBroadcast, error) { + m, err := r.client.EmailBroadcast.Query(). + Where(emailbroadcast.IDEQ(id)). + Only(ctx) + if err != nil { + return nil, translatePersistenceError(err, service.ErrEmailBroadcastNotFound, nil) + } + return emailBroadcastEntityToService(m), nil +} + +func (r *emailBroadcastRepository) UpdateStatus(ctx context.Context, id int64, patch service.EmailBroadcastStatusUpdate) error { + client := clientFromContext(ctx, r.client) + upd := client.EmailBroadcast.UpdateOneID(id) + + if patch.Status != nil { + upd.SetStatus(*patch.Status) + } + if patch.TotalCount != nil { + upd.SetTotalCount(*patch.TotalCount) + } + if patch.SuccessCount != nil { + upd.SetSuccessCount(*patch.SuccessCount) + } + if patch.FailedCount != nil { + upd.SetFailedCount(*patch.FailedCount) + } + if patch.ErrorMessage != nil { + upd.SetErrorMessage(*patch.ErrorMessage) + } + if patch.StartedAt != nil { + upd.SetStartedAt(*patch.StartedAt) + } + if patch.FinishedAt != nil { + upd.SetFinishedAt(*patch.FinishedAt) + } + + _, err := upd.Save(ctx) + if err != nil { + return translatePersistenceError(err, service.ErrEmailBroadcastNotFound, nil) + } + return nil +} + +func (r *emailBroadcastRepository) List(ctx context.Context, params service.EmailBroadcastListParams) (*service.EmailBroadcastListResult, error) { + q := r.client.EmailBroadcast.Query() + if params.Status != "" { + q = q.Where(emailbroadcast.StatusEQ(params.Status)) + } + + total, err := q.Count(ctx) + if err != nil { + return nil, err + } + + page := params.Page + if page <= 0 { + page = 1 + } + pageSize := params.PageSize + if pageSize <= 0 { + pageSize = 20 + } + + items, err := q. + Order(dbent.Desc(emailbroadcast.FieldCreatedAt), dbent.Desc(emailbroadcast.FieldID)). + Offset((page - 1) * pageSize). + Limit(pageSize). + All(ctx) + if err != nil { + return nil, err + } + + out := make([]service.EmailBroadcast, 0, len(items)) + for _, m := range items { + out = append(out, *emailBroadcastEntityToService(m)) + } + + return &service.EmailBroadcastListResult{ + Items: out, + Total: int64(total), + Page: page, + PageSize: pageSize, + }, nil +} + +func emailBroadcastEntityToService(m *dbent.EmailBroadcast) *service.EmailBroadcast { + if m == nil { + return nil + } + out := &service.EmailBroadcast{ + ID: m.ID, + Subject: m.Subject, + Body: m.Body, + BodyFormat: m.BodyFormat, + RecipientsMode: m.RecipientsMode, + RecipientUserIDs: append([]int64(nil), m.RecipientUserIds...), + Status: m.Status, + TotalCount: m.TotalCount, + SuccessCount: m.SuccessCount, + FailedCount: m.FailedCount, + CreatedAt: m.CreatedAt, + UpdatedAt: m.UpdatedAt, + } + if m.ErrorMessage != nil { + v := *m.ErrorMessage + out.ErrorMessage = &v + } + if m.CreatedBy != nil { + v := *m.CreatedBy + out.CreatedBy = &v + } + if m.StartedAt != nil { + v := *m.StartedAt + out.StartedAt = &v + } + if m.FinishedAt != nil { + v := *m.FinishedAt + out.FinishedAt = &v + } + return out +} + +func applyEmailBroadcastEntityToService(b *service.EmailBroadcast, m *dbent.EmailBroadcast) { + if b == nil || m == nil { + return + } + b.ID = m.ID + b.CreatedAt = m.CreatedAt + b.UpdatedAt = m.UpdatedAt +} diff --git a/backend/internal/repository/wire.go b/backend/internal/repository/wire.go index 2d1b04e393b..a9e86f77d0c 100644 --- a/backend/internal/repository/wire.go +++ b/backend/internal/repository/wire.go @@ -75,6 +75,7 @@ var ProviderSet = wire.NewSet( NewPromoCodeRepository, NewAnnouncementRepository, NewAnnouncementReadRepository, + NewEmailBroadcastRepository, NewUsageLogRepository, NewUsageBillingRepository, NewIdempotencyRepository, diff --git a/backend/internal/service/email_broadcast.go b/backend/internal/service/email_broadcast.go new file mode 100644 index 00000000000..f5d47115543 --- /dev/null +++ b/backend/internal/service/email_broadcast.go @@ -0,0 +1,99 @@ +package service + +import ( + "context" + "time" + + "github.com/Wei-Shaw/sub2api/internal/domain" +) + +// Re-exported domain constants for service-layer consumers. +const ( + EmailBroadcastBodyFormatHTML = domain.EmailBroadcastBodyFormatHTML + EmailBroadcastBodyFormatText = domain.EmailBroadcastBodyFormatText + EmailBroadcastRecipientsModeAll = domain.EmailBroadcastRecipientsModeAll + EmailBroadcastRecipientsModeSelected = domain.EmailBroadcastRecipientsModeSelected + EmailBroadcastStatusPending = domain.EmailBroadcastStatusPending + EmailBroadcastStatusSending = domain.EmailBroadcastStatusSending + EmailBroadcastStatusCompleted = domain.EmailBroadcastStatusCompleted + EmailBroadcastStatusFailed = domain.EmailBroadcastStatusFailed +) + +// Re-exported domain errors. +var ( + ErrEmailBroadcastNotFound = domain.ErrEmailBroadcastNotFound + ErrEmailBroadcastSubjectRequired = domain.ErrEmailBroadcastSubjectRequired + ErrEmailBroadcastBodyRequired = domain.ErrEmailBroadcastBodyRequired + ErrEmailBroadcastSubjectTooLong = domain.ErrEmailBroadcastSubjectTooLong + ErrEmailBroadcastBodyTooLong = domain.ErrEmailBroadcastBodyTooLong + ErrEmailBroadcastInvalidBodyFormat = domain.ErrEmailBroadcastInvalidBodyFormat + ErrEmailBroadcastInvalidMode = domain.ErrEmailBroadcastInvalidMode + ErrEmailBroadcastNoRecipients = domain.ErrEmailBroadcastNoRecipients + ErrEmailBroadcastTooManyRecipients = domain.ErrEmailBroadcastTooManyRecipients + ErrEmailBroadcastEmailNotConfigured = domain.ErrEmailBroadcastEmailNotConfigured +) + +// EmailBroadcast 是 service 层暴露的批量公告邮件聚合状态。 +type EmailBroadcast struct { + ID int64 + Subject string + Body string + BodyFormat string + RecipientsMode string + RecipientUserIDs []int64 + Status string + TotalCount int + SuccessCount int + FailedCount int + ErrorMessage *string + CreatedBy *int64 + StartedAt *time.Time + FinishedAt *time.Time + CreatedAt time.Time + UpdatedAt time.Time +} + +// EmailBroadcastCreateInput 描述创建/发起一次批量邮件公告所需输入。 +type EmailBroadcastCreateInput struct { + Subject string + Body string + BodyFormat string + RecipientsMode string + RecipientUserIDs []int64 + CreatedBy *int64 +} + +// EmailBroadcastListParams 控制 ListBroadcasts 查询的分页与过滤。 +type EmailBroadcastListParams struct { + Page int + PageSize int + Status string // 可空:按状态过滤 +} + +// EmailBroadcastListResult 列表查询返回值。 +type EmailBroadcastListResult struct { + Items []EmailBroadcast + Total int64 + Page int + PageSize int +} + +// EmailBroadcastStatusUpdate 用于增量更新一次广播的执行状态。 +// nil 字段表示"不变",便于把 finished_at / counts 等部分字段一次提交。 +type EmailBroadcastStatusUpdate struct { + Status *string + TotalCount *int + SuccessCount *int + FailedCount *int + ErrorMessage *string + StartedAt *time.Time + FinishedAt *time.Time +} + +// EmailBroadcastRepository 定义批量邮件公告的持久化接口。 +type EmailBroadcastRepository interface { + Create(ctx context.Context, broadcast *EmailBroadcast) error + GetByID(ctx context.Context, id int64) (*EmailBroadcast, error) + UpdateStatus(ctx context.Context, id int64, patch EmailBroadcastStatusUpdate) error + List(ctx context.Context, params EmailBroadcastListParams) (*EmailBroadcastListResult, error) +} diff --git a/backend/internal/service/email_broadcast_service.go b/backend/internal/service/email_broadcast_service.go new file mode 100644 index 00000000000..54cb6f3fc1a --- /dev/null +++ b/backend/internal/service/email_broadcast_service.go @@ -0,0 +1,422 @@ +package service + +import ( + "context" + "fmt" + "html" + "strings" + "sync" + "time" + + "github.com/Wei-Shaw/sub2api/internal/domain" + "github.com/Wei-Shaw/sub2api/internal/pkg/logger" + "github.com/Wei-Shaw/sub2api/internal/pkg/pagination" + + "github.com/microcosm-cc/bluemonday" + "go.uber.org/zap" +) + +// EmailBroadcastService 提供管理员批量发送公告邮件的能力。 +// +// 设计要点: +// - HTTP 入口通过 Send() 立刻创建一条 broadcast 记录后异步发送,避免长时间占用请求 goroutine。 +// - 发送过程对单封邮件失败保持容错,整批的成功 / 失败计数会增量回写到 DB。 +// - HTML 正文使用 bluemonday UGCPolicy 做 sanitize,去除潜在 XSS 风险;纯文本正文会被 +// HTML-escape 并替换换行后再生成最终邮件,保证两种格式的最终 MIME 都是合法的 HTML 邮件。 +type EmailBroadcastService struct { + repo EmailBroadcastRepository + userRepo UserRepository + emailService *EmailService + settingRepo SettingRepository + htmlSanitizer *bluemonday.Policy + sendIntervalPerEmail time.Duration + + mu sync.Mutex + running map[int64]struct{} +} + +// EmailBroadcastSendInput 发送一次广播邮件所需的参数集合 (供 handler 调用)。 +type EmailBroadcastSendInput struct { + Subject string + Body string + BodyFormat string + RecipientsMode string + RecipientUserIDs []int64 + CreatedBy *int64 +} + +// NewEmailBroadcastService 创建广播邮件服务。 +func NewEmailBroadcastService( + repo EmailBroadcastRepository, + userRepo UserRepository, + emailService *EmailService, + settingRepo SettingRepository, +) *EmailBroadcastService { + policy := bluemonday.UGCPolicy() + // 允许 等公告里常用的属性。 + policy.AllowAttrs("target").OnElements("a") + policy.RequireNoReferrerOnLinks(true) + policy.RequireNoFollowOnLinks(true) + policy.AllowStandardURLs() + + return &EmailBroadcastService{ + repo: repo, + userRepo: userRepo, + emailService: emailService, + settingRepo: settingRepo, + htmlSanitizer: policy, + sendIntervalPerEmail: 200 * time.Millisecond, + running: make(map[int64]struct{}), + } +} + +// Send 校验输入、解析收件人、立刻持久化 broadcast 记录,然后异步触发批量发送。 +// 返回值是已创建的 broadcast (status=pending)。 +func (s *EmailBroadcastService) Send(ctx context.Context, input EmailBroadcastSendInput) (*EmailBroadcast, error) { + subject := strings.TrimSpace(input.Subject) + body := strings.TrimSpace(input.Body) + bodyFormat := strings.ToLower(strings.TrimSpace(input.BodyFormat)) + mode := strings.ToLower(strings.TrimSpace(input.RecipientsMode)) + + if subject == "" { + return nil, ErrEmailBroadcastSubjectRequired + } + if len([]rune(subject)) > domain.EmailBroadcastSubjectMaxLen { + return nil, ErrEmailBroadcastSubjectTooLong + } + if body == "" { + return nil, ErrEmailBroadcastBodyRequired + } + if len(body) > domain.EmailBroadcastBodyMaxLen { + return nil, ErrEmailBroadcastBodyTooLong + } + switch bodyFormat { + case EmailBroadcastBodyFormatHTML, EmailBroadcastBodyFormatText: + case "": + bodyFormat = EmailBroadcastBodyFormatHTML + default: + return nil, ErrEmailBroadcastInvalidBodyFormat + } + switch mode { + case EmailBroadcastRecipientsModeAll, EmailBroadcastRecipientsModeSelected: + case "": + mode = EmailBroadcastRecipientsModeSelected + default: + return nil, ErrEmailBroadcastInvalidMode + } + + dedupedIDs := dedupePositiveInt64s(input.RecipientUserIDs) + if mode == EmailBroadcastRecipientsModeSelected { + if len(dedupedIDs) == 0 { + return nil, ErrEmailBroadcastNoRecipients + } + if len(dedupedIDs) > domain.EmailBroadcastMaxSelectedRecipients { + return nil, ErrEmailBroadcastTooManyRecipients + } + } else { + // "all" 模式忽略用户传入的 IDs,避免歧义。 + dedupedIDs = nil + } + + // 提前校验 SMTP 配置存在 — 没配的话直接返回,不写脏数据。 + smtpConfig, err := s.emailService.GetSMTPConfig(ctx) + if err != nil { + return nil, ErrEmailBroadcastEmailNotConfigured + } + if smtpConfig == nil || strings.TrimSpace(smtpConfig.Host) == "" { + return nil, ErrEmailBroadcastEmailNotConfigured + } + + broadcast := &EmailBroadcast{ + Subject: subject, + Body: body, + BodyFormat: bodyFormat, + RecipientsMode: mode, + RecipientUserIDs: dedupedIDs, + Status: EmailBroadcastStatusPending, + CreatedBy: input.CreatedBy, + } + if err := s.repo.Create(ctx, broadcast); err != nil { + return nil, err + } + + go s.runBroadcast(broadcast.ID) + + return broadcast, nil +} + +// List 查询 broadcast 历史。 +func (s *EmailBroadcastService) List(ctx context.Context, params EmailBroadcastListParams) (*EmailBroadcastListResult, error) { + if params.Page <= 0 { + params.Page = 1 + } + if params.PageSize <= 0 || params.PageSize > 100 { + params.PageSize = 20 + } + return s.repo.List(ctx, params) +} + +// Get 取单条 broadcast 详情。 +func (s *EmailBroadcastService) Get(ctx context.Context, id int64) (*EmailBroadcast, error) { + if id <= 0 { + return nil, ErrEmailBroadcastNotFound + } + return s.repo.GetByID(ctx, id) +} + +// runBroadcast 是后台 goroutine 入口,对单次 broadcast 执行解析收件人 + 实际 SMTP 投递 + 状态回写。 +// 整个过程使用独立的 context.Background,避免 HTTP 请求结束导致中断。 +func (s *EmailBroadcastService) runBroadcast(id int64) { + if !s.markRunning(id) { + return + } + defer s.unmarkRunning(id) + + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Minute) + defer cancel() + + defer func() { + if r := recover(); r != nil { + logger.L().Error("email_broadcast.panic", zap.Int64("broadcast_id", id), zap.Any("panic", r)) + now := time.Now() + msg := fmt.Sprintf("panic: %v", r) + _ = s.repo.UpdateStatus(ctx, id, EmailBroadcastStatusUpdate{ + Status: ptrStr(EmailBroadcastStatusFailed), + ErrorMessage: &msg, + FinishedAt: &now, + }) + } + }() + + broadcast, err := s.repo.GetByID(ctx, id) + if err != nil || broadcast == nil { + logger.L().Error("email_broadcast.load_failed", zap.Int64("broadcast_id", id), zap.Error(err)) + return + } + + smtpConfig, err := s.emailService.GetSMTPConfig(ctx) + if err != nil || smtpConfig == nil { + now := time.Now() + msg := "SMTP config unavailable" + _ = s.repo.UpdateStatus(ctx, id, EmailBroadcastStatusUpdate{ + Status: ptrStr(EmailBroadcastStatusFailed), + ErrorMessage: &msg, + FinishedAt: &now, + }) + return + } + + emails, err := s.resolveRecipientEmails(ctx, broadcast) + if err != nil { + now := time.Now() + msg := err.Error() + _ = s.repo.UpdateStatus(ctx, id, EmailBroadcastStatusUpdate{ + Status: ptrStr(EmailBroadcastStatusFailed), + ErrorMessage: &msg, + FinishedAt: &now, + }) + return + } + if len(emails) == 0 { + now := time.Now() + msg := "no valid recipients found" + zero := 0 + _ = s.repo.UpdateStatus(ctx, id, EmailBroadcastStatusUpdate{ + Status: ptrStr(EmailBroadcastStatusFailed), + TotalCount: &zero, + ErrorMessage: &msg, + FinishedAt: &now, + }) + return + } + + htmlBody := s.composeHTMLBody(broadcast.Body, broadcast.BodyFormat) + + started := time.Now() + total := len(emails) + zero := 0 + _ = s.repo.UpdateStatus(ctx, id, EmailBroadcastStatusUpdate{ + Status: ptrStr(EmailBroadcastStatusSending), + TotalCount: &total, + SuccessCount: &zero, + FailedCount: &zero, + StartedAt: &started, + }) + + success, failed := 0, 0 + for idx, addr := range emails { + if err := s.emailService.SendEmailWithConfigAndContentType( + smtpConfig, + addr, + broadcast.Subject, + htmlBody, + "text/html; charset=UTF-8", + ); err != nil { + failed++ + logger.L().Warn("email_broadcast.send_failed", + zap.Int64("broadcast_id", id), + zap.String("recipient", addr), + zap.Error(err)) + } else { + success++ + } + + // Throttle to avoid SMTP rate limits; skip after last message. + if idx < total-1 && s.sendIntervalPerEmail > 0 { + select { + case <-ctx.Done(): + failed += total - idx - 1 + goto done + case <-time.After(s.sendIntervalPerEmail): + } + } + } + +done: + finished := time.Now() + finalStatus := EmailBroadcastStatusCompleted + if success == 0 && failed > 0 { + finalStatus = EmailBroadcastStatusFailed + } + _ = s.repo.UpdateStatus(ctx, id, EmailBroadcastStatusUpdate{ + Status: ptrStr(finalStatus), + SuccessCount: &success, + FailedCount: &failed, + FinishedAt: &finished, + }) + + logger.L().Info("email_broadcast.completed", + zap.Int64("broadcast_id", id), + zap.Int("total", total), + zap.Int("success", success), + zap.Int("failed", failed), + zap.String("status", finalStatus)) +} + +// resolveRecipientEmails 把 broadcast 描述的"全部用户 / 指定 IDs"展开为收件人邮箱列表。 +func (s *EmailBroadcastService) resolveRecipientEmails(ctx context.Context, b *EmailBroadcast) ([]string, error) { + emails := make([]string, 0) + seen := make(map[string]struct{}) + + collect := func(email string) { + email = strings.TrimSpace(email) + if email == "" { + return + } + key := strings.ToLower(email) + if _, ok := seen[key]; ok { + return + } + seen[key] = struct{}{} + emails = append(emails, email) + } + + switch b.RecipientsMode { + case EmailBroadcastRecipientsModeAll: + const pageSize = 500 + page := 1 + for { + users, pageResult, err := s.userRepo.List(ctx, paginationParams(page, pageSize)) + if err != nil { + return nil, fmt.Errorf("list users: %w", err) + } + for i := range users { + collect(users[i].Email) + } + if pageResult == nil || len(users) < pageSize { + break + } + // 防御性:避免无限循环 + if int64(page*pageSize) >= pageResult.Total { + break + } + page++ + } + case EmailBroadcastRecipientsModeSelected: + for _, id := range b.RecipientUserIDs { + user, err := s.userRepo.GetByID(ctx, id) + if err != nil { + logger.L().Warn("email_broadcast.user_lookup_failed", + zap.Int64("broadcast_id", b.ID), + zap.Int64("user_id", id), + zap.Error(err)) + continue + } + if user != nil { + collect(user.Email) + } + } + default: + return nil, fmt.Errorf("unknown recipients mode: %s", b.RecipientsMode) + } + + return emails, nil +} + +// composeHTMLBody 根据 broadcast 的 body_format 生成最终的 HTML 邮件正文。 +// 纯文本会被 HTML-escape 并
替换换行,HTML 会经过 bluemonday sanitize。 +func (s *EmailBroadcastService) composeHTMLBody(body, format string) string { + switch format { + case EmailBroadcastBodyFormatText: + escaped := html.EscapeString(body) + escaped = strings.ReplaceAll(escaped, "\r\n", "\n") + escaped = strings.ReplaceAll(escaped, "\n", "
") + return wrapBroadcastHTMLShell(escaped) + case EmailBroadcastBodyFormatHTML: + sanitized := s.htmlSanitizer.Sanitize(body) + return wrapBroadcastHTMLShell(sanitized) + default: + return wrapBroadcastHTMLShell(html.EscapeString(body)) + } +} + +// wrapBroadcastHTMLShell 给正文包一层最简单的 HTML 容器。 +// 故意不引入站点 brand / footer,让公告内容更"管理员发的纯邮件"。 +func wrapBroadcastHTMLShell(inner string) string { + return fmt.Sprintf(` + +%s +`, inner) +} + +// markRunning 防止同一个 broadcast 被并发触发两次。 +func (s *EmailBroadcastService) markRunning(id int64) bool { + s.mu.Lock() + defer s.mu.Unlock() + if _, ok := s.running[id]; ok { + return false + } + s.running[id] = struct{}{} + return true +} + +func (s *EmailBroadcastService) unmarkRunning(id int64) { + s.mu.Lock() + defer s.mu.Unlock() + delete(s.running, id) +} + +func ptrStr(s string) *string { return &s } + +func paginationParams(page, pageSize int) pagination.PaginationParams { + return pagination.PaginationParams{Page: page, PageSize: pageSize} +} + +func dedupePositiveInt64s(in []int64) []int64 { + if len(in) == 0 { + return nil + } + seen := make(map[int64]struct{}, len(in)) + out := make([]int64, 0, len(in)) + for _, v := range in { + if v <= 0 { + continue + } + if _, ok := seen[v]; ok { + continue + } + seen[v] = struct{}{} + out = append(out, v) + } + return out +} diff --git a/backend/internal/service/email_broadcast_service_test.go b/backend/internal/service/email_broadcast_service_test.go new file mode 100644 index 00000000000..da45fd91a30 --- /dev/null +++ b/backend/internal/service/email_broadcast_service_test.go @@ -0,0 +1,210 @@ +package service + +import ( + "context" + "errors" + "strings" + "testing" + + "github.com/Wei-Shaw/sub2api/internal/domain" + "github.com/stretchr/testify/require" +) + +type emailBroadcastRepoStub struct { + created *EmailBroadcast + listErr error + listOut *EmailBroadcastListResult + getErr error + getOut *EmailBroadcast + patches []EmailBroadcastStatusUpdate +} + +func (s *emailBroadcastRepoStub) Create(_ context.Context, b *EmailBroadcast) error { + cp := *b + cp.ID = 1 + s.created = &cp + b.ID = 1 + return nil +} + +func (s *emailBroadcastRepoStub) GetByID(_ context.Context, _ int64) (*EmailBroadcast, error) { + if s.getErr != nil { + return nil, s.getErr + } + if s.getOut != nil { + return s.getOut, nil + } + if s.created == nil { + return nil, ErrEmailBroadcastNotFound + } + cp := *s.created + return &cp, nil +} + +func (s *emailBroadcastRepoStub) UpdateStatus(_ context.Context, _ int64, patch EmailBroadcastStatusUpdate) error { + s.patches = append(s.patches, patch) + return nil +} + +func (s *emailBroadcastRepoStub) List(_ context.Context, _ EmailBroadcastListParams) (*EmailBroadcastListResult, error) { + if s.listErr != nil { + return nil, s.listErr + } + if s.listOut == nil { + return &EmailBroadcastListResult{Items: []EmailBroadcast{}}, nil + } + return s.listOut, nil +} + +// settingRepoStubNoSMTP returns no SMTP host so GetSMTPConfig fails with ErrEmailNotConfigured. +type settingRepoStubNoSMTP struct{} + +func (settingRepoStubNoSMTP) Get(context.Context, string) (*Setting, error) { + return nil, errors.New("not configured") +} +func (settingRepoStubNoSMTP) GetValue(context.Context, string) (string, error) { + return "", errors.New("not configured") +} +func (settingRepoStubNoSMTP) Set(context.Context, string, string) error { return nil } +func (settingRepoStubNoSMTP) GetMultiple(_ context.Context, keys []string) (map[string]string, error) { + out := make(map[string]string, len(keys)) + for _, k := range keys { + out[k] = "" + } + return out, nil +} +func (settingRepoStubNoSMTP) SetMultiple(context.Context, map[string]string) error { return nil } +func (settingRepoStubNoSMTP) GetAll(context.Context) (map[string]string, error) { + return map[string]string{}, nil +} +func (settingRepoStubNoSMTP) Delete(context.Context, string) error { return nil } + +func newTestEmailBroadcastService() (*EmailBroadcastService, *emailBroadcastRepoStub) { + repo := &emailBroadcastRepoStub{} + emailSvc := NewEmailService(settingRepoStubNoSMTP{}, nil) + svc := NewEmailBroadcastService(repo, nil, emailSvc, settingRepoStubNoSMTP{}) + return svc, repo +} + +func TestEmailBroadcastSend_RejectsEmptySubject(t *testing.T) { + svc, _ := newTestEmailBroadcastService() + _, err := svc.Send(context.Background(), EmailBroadcastSendInput{ + Subject: " ", + Body: "hello", + RecipientsMode: EmailBroadcastRecipientsModeSelected, + RecipientUserIDs: []int64{1}, + }) + require.ErrorIs(t, err, ErrEmailBroadcastSubjectRequired) +} + +func TestEmailBroadcastSend_RejectsEmptyBody(t *testing.T) { + svc, _ := newTestEmailBroadcastService() + _, err := svc.Send(context.Background(), EmailBroadcastSendInput{ + Subject: "subject", + Body: "", + RecipientsMode: EmailBroadcastRecipientsModeSelected, + RecipientUserIDs: []int64{1}, + }) + require.ErrorIs(t, err, ErrEmailBroadcastBodyRequired) +} + +func TestEmailBroadcastSend_RejectsSubjectTooLong(t *testing.T) { + svc, _ := newTestEmailBroadcastService() + _, err := svc.Send(context.Background(), EmailBroadcastSendInput{ + Subject: strings.Repeat("a", domain.EmailBroadcastSubjectMaxLen+1), + Body: "hello", + RecipientsMode: EmailBroadcastRecipientsModeSelected, + RecipientUserIDs: []int64{1}, + }) + require.ErrorIs(t, err, ErrEmailBroadcastSubjectTooLong) +} + +func TestEmailBroadcastSend_RejectsBodyTooLong(t *testing.T) { + svc, _ := newTestEmailBroadcastService() + _, err := svc.Send(context.Background(), EmailBroadcastSendInput{ + Subject: "subject", + Body: strings.Repeat("a", domain.EmailBroadcastBodyMaxLen+1), + RecipientsMode: EmailBroadcastRecipientsModeSelected, + RecipientUserIDs: []int64{1}, + }) + require.ErrorIs(t, err, ErrEmailBroadcastBodyTooLong) +} + +func TestEmailBroadcastSend_RejectsBadFormat(t *testing.T) { + svc, _ := newTestEmailBroadcastService() + _, err := svc.Send(context.Background(), EmailBroadcastSendInput{ + Subject: "s", + Body: "b", + BodyFormat: "markdown", + RecipientsMode: EmailBroadcastRecipientsModeSelected, + RecipientUserIDs: []int64{1}, + }) + require.ErrorIs(t, err, ErrEmailBroadcastInvalidBodyFormat) +} + +func TestEmailBroadcastSend_RejectsBadMode(t *testing.T) { + svc, _ := newTestEmailBroadcastService() + _, err := svc.Send(context.Background(), EmailBroadcastSendInput{ + Subject: "s", + Body: "b", + RecipientsMode: "everyone", + }) + require.ErrorIs(t, err, ErrEmailBroadcastInvalidMode) +} + +func TestEmailBroadcastSend_RejectsSelectedWithoutRecipients(t *testing.T) { + svc, _ := newTestEmailBroadcastService() + _, err := svc.Send(context.Background(), EmailBroadcastSendInput{ + Subject: "s", + Body: "b", + RecipientsMode: EmailBroadcastRecipientsModeSelected, + }) + require.ErrorIs(t, err, ErrEmailBroadcastNoRecipients) +} + +func TestEmailBroadcastSend_RejectsTooManyRecipients(t *testing.T) { + svc, _ := newTestEmailBroadcastService() + ids := make([]int64, 0, domain.EmailBroadcastMaxSelectedRecipients+1) + for i := 0; i < domain.EmailBroadcastMaxSelectedRecipients+1; i++ { + ids = append(ids, int64(i+1)) + } + _, err := svc.Send(context.Background(), EmailBroadcastSendInput{ + Subject: "s", + Body: "b", + RecipientsMode: EmailBroadcastRecipientsModeSelected, + RecipientUserIDs: ids, + }) + require.ErrorIs(t, err, ErrEmailBroadcastTooManyRecipients) +} + +func TestEmailBroadcastSend_RejectsWhenSMTPNotConfigured(t *testing.T) { + svc, _ := newTestEmailBroadcastService() + _, err := svc.Send(context.Background(), EmailBroadcastSendInput{ + Subject: "s", + Body: "b", + RecipientsMode: EmailBroadcastRecipientsModeSelected, + RecipientUserIDs: []int64{1, 2, 3}, + }) + require.ErrorIs(t, err, ErrEmailBroadcastEmailNotConfigured) +} + +func TestDedupePositiveInt64s(t *testing.T) { + in := []int64{0, 1, 1, 2, -3, 2, 4} + out := dedupePositiveInt64s(in) + require.Equal(t, []int64{1, 2, 4}, out) +} + +func TestComposeHTMLBody_PlainTextEscapesAndPreservesNewlines(t *testing.T) { + svc, _ := newTestEmailBroadcastService() + got := svc.composeHTMLBody("\nline2", EmailBroadcastBodyFormatText) + require.Contains(t, got, "<script>") + require.Contains(t, got, "
") +} + +func TestComposeHTMLBody_HTMLStripsDangerousTags(t *testing.T) { + svc, _ := newTestEmailBroadcastService() + got := svc.composeHTMLBody(`

safe

link`, EmailBroadcastBodyFormatHTML) + require.Contains(t, got, "

safe

") + require.NotContains(t, got, " diff --git a/frontend/src/i18n/locales/en.ts b/frontend/src/i18n/locales/en.ts index 6735029c7c3..14a26d77999 100644 --- a/frontend/src/i18n/locales/en.ts +++ b/frontend/src/i18n/locales/en.ts @@ -4424,6 +4424,49 @@ export default { deleteConfirm: 'Are you sure you want to delete this announcement? This action cannot be undone.' }, + // Bulk announcement email broadcasts + emailBroadcast: { + title: 'Announcement Email Broadcast', + description: 'Compose and bulk-send an announcement email to selected users or all registered users, useful when users cannot see in-app popups before they log in.', + openComposer: 'Compose announcement email', + form: { + subject: 'Subject', + subjectPlaceholder: 'e.g. Scheduled maintenance this Sunday', + body: 'Body', + bodyFormat: 'Format', + bodyFormatText: 'Plain text', + bodyPlaceholderHtml: 'Basic HTML allowed:

, , ,