From a29642599446f89e5962ae36d492a70673c53749 Mon Sep 17 00:00:00 2001 From: erio Date: Tue, 21 Apr 2026 14:14:49 +0800 Subject: [PATCH] feat(channel-monitor): request templates with snapshot apply + headers/body override MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Problem: Upstream channels can reject monitor probes based on client fingerprint (e.g. "only Claude Code clients allowed"). The monitor had no way to customize the outgoing request to bypass such restrictions. Solution: Introduce reusable request templates that carry extra_headers plus an optional body override; monitors reference a template and receive a snapshot copy on apply. Template edits do NOT auto-propagate — users must click "apply to associated monitors" to refresh snapshots, so a bad template edit cannot instantly break all production monitors. Data model (migration 112): - channel_monitor_request_templates: id, name, provider, description, extra_headers jsonb, body_override_mode ('off'|'merge'|'replace'), body_override jsonb. Unique (provider, name). - channel_monitors: +template_id (FK, ON DELETE SET NULL), +extra_headers, +body_override_mode, +body_override (the three runtime snapshot fields). Checker (channel_monitor_checker.go): - callProvider + runCheckForModel accept a CheckOptions carrying the snapshot fields. mergeHeaders applies user headers on top of adapter defaults (forbidden list: Host / Content-Length / Transfer-Encoding / Connection / Content-Encoding). - buildRequestBody: off -> adapter default body merge -> shallow-merge over default; per-provider deny list (model/messages/contents) protects the challenge contract replace -> user body verbatim - Replace mode skips challenge validation; instead HTTP 2xx + non-empty extracted response text = operational, empty = failed. - 4 new unit tests cover all three modes + replace/empty-response case. Admin API: - /admin/channel-monitor-templates CRUD + /:id/apply (overwrite snapshot on all template_id=id monitors, returns affected count). - channel_monitor request/response DTOs gain the 4 new fields. Frontend: - channelMonitorTemplate.ts API client. - MonitorAdvancedRequestConfig.vue shared component for headers textarea + body mode radio + body JSON editor; used by both template and monitor forms. - MonitorTemplateManagerDialog.vue: provider tabs, list/create/edit/ delete/apply, live "associated monitors" count per row. - MonitorFiltersBar: new 模板管理 button next to 新增监控. - MonitorFormDialog: collapsible 高级 section with template dropdown (filtered by form.provider, clears on provider change) + embedded AdvancedRequestConfig. Picking a template copies its fields into the form (snapshot semantics mirrored on the client). - i18n zh/en entries for all new copy. chore: bump version to 0.1.114.32 --- _parse_upstream.py | 78 + backend/cmd/server/wire_gen.go | 5 +- backend/ent/channelmonitor.go | 78 +- backend/ent/channelmonitor/channelmonitor.go | 51 + backend/ent/channelmonitor/where.go | 138 ++ backend/ent/channelmonitor_create.go | 308 ++++ backend/ent/channelmonitor_query.go | 108 +- backend/ent/channelmonitor_update.go | 247 ++++ backend/ent/channelmonitorrequesttemplate.go | 216 +++ .../channelmonitorrequesttemplate.go | 172 +++ .../channelmonitorrequesttemplate/where.go | 434 ++++++ .../channelmonitorrequesttemplate_create.go | 942 ++++++++++++ .../channelmonitorrequesttemplate_delete.go | 88 ++ .../channelmonitorrequesttemplate_query.go | 648 +++++++++ .../channelmonitorrequesttemplate_update.go | 639 ++++++++ backend/ent/client.go | 347 +++-- backend/ent/ent.go | 68 +- backend/ent/hook/hook.go | 12 + backend/ent/intercept/intercept.go | 30 + backend/ent/migrate/schema.go | 47 + backend/ent/mutation.go | 1285 ++++++++++++++++- backend/ent/predicate/predicate.go | 3 + backend/ent/runtime/runtime.go | 60 + backend/ent/schema/channel_monitor.go | 27 + .../channel_monitor_request_template.go | 80 + backend/ent/tx.go | 3 + .../handler/admin/channel_monitor_handler.go | 105 +- .../admin/channel_monitor_template_handler.go | 195 +++ backend/internal/handler/handler.go | 55 +- backend/internal/handler/wire.go | 57 +- .../repository/channel_monitor_repo.go | 83 +- .../channel_monitor_template_repo.go | 168 +++ backend/internal/repository/wire.go | 1 + backend/internal/server/routes/admin.go | 10 + .../service/channel_monitor_checker.go | 134 +- .../channel_monitor_checker_body_test.go | 173 +++ .../service/channel_monitor_service.go | 72 +- .../channel_monitor_template_service.go | 225 +++ .../service/channel_monitor_template_types.go | 74 + .../internal/service/channel_monitor_types.go | 51 +- backend/internal/service/wire.go | 1 + ..._add_channel_monitor_request_templates.sql | 70 + frontend/src/api/admin/channelMonitor.ts | 16 +- .../src/api/admin/channelMonitorTemplate.ts | 108 ++ frontend/src/api/admin/index.ts | 3 + .../monitor/MonitorAdvancedRequestConfig.vue | 205 +++ .../admin/monitor/MonitorFiltersBar.vue | 9 + .../admin/monitor/MonitorFormDialog.vue | 118 +- .../monitor/MonitorTemplateManagerDialog.vue | 465 ++++++ .../components/user/monitor/MonitorHero.vue | 87 +- frontend/src/i18n/locales/en.ts | 52 +- frontend/src/i18n/locales/zh.ts | 52 +- .../src/views/admin/ChannelMonitorView.vue | 9 + 53 files changed, 8318 insertions(+), 394 deletions(-) create mode 100644 _parse_upstream.py create mode 100644 backend/ent/channelmonitorrequesttemplate.go create mode 100644 backend/ent/channelmonitorrequesttemplate/channelmonitorrequesttemplate.go create mode 100644 backend/ent/channelmonitorrequesttemplate/where.go create mode 100644 backend/ent/channelmonitorrequesttemplate_create.go create mode 100644 backend/ent/channelmonitorrequesttemplate_delete.go create mode 100644 backend/ent/channelmonitorrequesttemplate_query.go create mode 100644 backend/ent/channelmonitorrequesttemplate_update.go create mode 100644 backend/ent/schema/channel_monitor_request_template.go create mode 100644 backend/internal/handler/admin/channel_monitor_template_handler.go create mode 100644 backend/internal/repository/channel_monitor_template_repo.go create mode 100644 backend/internal/service/channel_monitor_checker_body_test.go create mode 100644 backend/internal/service/channel_monitor_template_service.go create mode 100644 backend/internal/service/channel_monitor_template_types.go create mode 100644 backend/migrations/128_add_channel_monitor_request_templates.sql create mode 100644 frontend/src/api/admin/channelMonitorTemplate.ts create mode 100644 frontend/src/components/admin/monitor/MonitorAdvancedRequestConfig.vue create mode 100644 frontend/src/components/admin/monitor/MonitorTemplateManagerDialog.vue diff --git a/_parse_upstream.py b/_parse_upstream.py new file mode 100644 index 00000000..807d1cac --- /dev/null +++ b/_parse_upstream.py @@ -0,0 +1,78 @@ +""" +严格按模型拆分 upstream 的 token 和 quota;并按【我们的定价表】重算每个模型的 token 应得金额。 +对比 upstream provider-side (/group_ratio) 与我们 Anthropic 官方价的计算结果。 +""" +import re +import json +from collections import defaultdict + +# 按账号(token_name) + 模型拆 +by_key = defaultdict(lambda: { + 'count': 0, + 'prompt': 0, + 'completion': 0, + 'cache_create': 0, + 'cache_read': 0, + 'quota_pre_group_sum': 0.0, + 'flat_price_reqs': 0, + 'flat_price_value': 0.0, + 'model_ratios': set(), + 'model_prices': set(), +}) + +with open(r"C:\Users\16790\xwechat_files\wxid_8tc8tfooo5rs22_fef8\msg\file\2026-04\asakifeng_consume.txt", 'r', encoding='utf-8') as f: + for line in f: + m = re.match(r'\[INFO\] (\d{4}/\d{2}/\d{2} - \d{2}:\d{2}:\d{2}) \|.*params=(\{.*\})\s*$', line.strip()) + if not m: continue + try: p = json.loads(m.group(2)) + except Exception: continue + tn = p.get('token_name', '') + model = p.get('model_name', '') + other = p.get('other') or {} + gr = other.get('group_ratio', 1.0) or 1.0 + q = p.get('quota', 0) or 0 + k = (tn, model) + d = by_key[k] + d['count'] += 1 + d['prompt'] += p.get('prompt_tokens', 0) or 0 + d['completion'] += p.get('completion_tokens', 0) or 0 + d['cache_create'] += other.get('cache_creation_tokens', 0) or 0 + d['cache_read'] += other.get('cache_tokens', 0) or 0 + d['quota_pre_group_sum'] += q / gr if gr else q + mp = other.get('model_price') or 0 + mr = other.get('model_ratio') + if mr is not None: d['model_ratios'].add(mr) + d['model_prices'].add(mp) + if mp and mp > 0: + d['flat_price_reqs'] += 1 + d['flat_price_value'] += mp # flat $ per request + +# 我们定价表(从 backend/resources/.../model_prices_and_context_window.json 读的真实值) +OUR_PRICE = { + 'claude-haiku-4-5-20251001': {'input': 1e-6, 'output': 5e-6, 'cc5m': 1.25e-6, 'cr': 1e-7}, + 'claude-sonnet-4-6': {'input': 3e-6, 'output': 1.5e-5, 'cc5m': 3.75e-6, 'cr': 3e-7}, + 'claude-sonnet-4-5-20250929': {'input': 3e-6, 'output': 1.5e-5, 'cc5m': 3.75e-6, 'cr': 3e-7}, + 'claude-opus-4-6': {'input': 5e-6, 'output': 2.5e-5, 'cc5m': 6.25e-6, 'cr': 5e-7}, + 'claude-opus-4-5-20251101': {'input': 5e-6, 'output': 2.5e-5, 'cc5m': 6.25e-6, 'cr': 5e-7}, + 'claude-opus-4-7': {'input': 5e-6, 'output': 2.5e-5, 'cc5m': 6.25e-6, 'cr': 5e-7}, # 我们回退到 opus-4-6 价 +} + +print("%-40s %-28s %5s %12s %12s %12s %12s" % ("TOKEN", "MODEL", "req", "upstream$", "our_calc$", "diff$", "note")) +print("-" * 150) +total_up = 0.0; total_ours = 0.0 +for (tn, model), d in sorted(by_key.items()): + up = d['quota_pre_group_sum'] / 500000 + p = OUR_PRICE.get(model) + if p: + ours = (d['prompt']*p['input'] + d['completion']*p['output'] + + d['cache_create']*p['cc5m'] + d['cache_read']*p['cr']) + else: + ours = 0.0 + diff = up - ours + note = "" + if d['flat_price_reqs']: + note = f"flat_price {d['flat_price_reqs']}/{d['count']}" + total_up += up; total_ours += ours + print("%-40s %-28s %5d %12.4f %12.4f %+12.4f %s" % (tn[:40], model, d['count'], up, ours, diff, note)) +print("-" * 150) +print("%-40s %-28s %5s %12.4f %12.4f %+12.4f" % ("TOTAL", "", "", total_up, total_ours, total_up - total_ours)) diff --git a/backend/cmd/server/wire_gen.go b/backend/cmd/server/wire_gen.go index a878ea68..4e95035a 100644 --- a/backend/cmd/server/wire_gen.go +++ b/backend/cmd/server/wire_gen.go @@ -215,6 +215,9 @@ func initializeApplication(buildInfo handler.BuildInfo) (*Application, error) { return nil, err } channelMonitorRepository := repository.NewChannelMonitorRepository(client, sqlDB) + channelMonitorRequestTemplateRepository := repository.NewChannelMonitorRequestTemplateRepository(client, sqlDB) + channelMonitorRequestTemplateService := service.NewChannelMonitorRequestTemplateService(channelMonitorRequestTemplateRepository) + channelMonitorRequestTemplateHandler := admin.NewChannelMonitorRequestTemplateHandler(channelMonitorRequestTemplateService) channelMonitorService := service.ProvideChannelMonitorService(channelMonitorRepository, secretEncryptor) channelMonitorHandler := admin.NewChannelMonitorHandler(channelMonitorService) channelMonitorUserHandler := handler.NewChannelMonitorUserHandler(channelMonitorService, settingService) @@ -231,7 +234,7 @@ func initializeApplication(buildInfo handler.BuildInfo) (*Application, error) { settingHandler := admin.NewSettingHandler(settingService, emailService, turnstileService, opsService, paymentConfigService, paymentService) paymentOrderExpiryService := service.ProvidePaymentOrderExpiryService(paymentService) paymentHandler := admin.NewPaymentHandler(paymentService, paymentConfigService) - adminHandlers := handler.ProvideAdminHandlers(dashboardHandler, adminUserHandler, groupHandler, accountHandler, adminAnnouncementHandler, dataManagementHandler, backupHandler, oAuthHandler, openAIOAuthHandler, geminiOAuthHandler, antigravityOAuthHandler, proxyHandler, adminRedeemHandler, promoHandler, settingHandler, opsHandler, systemHandler, adminSubscriptionHandler, adminUsageHandler, userAttributeHandler, errorPassthroughHandler, tlsFingerprintProfileHandler, adminAPIKeyHandler, scheduledTestHandler, channelHandler, channelMonitorHandler, paymentHandler) + adminHandlers := handler.ProvideAdminHandlers(dashboardHandler, adminUserHandler, groupHandler, accountHandler, adminAnnouncementHandler, dataManagementHandler, backupHandler, oAuthHandler, openAIOAuthHandler, geminiOAuthHandler, antigravityOAuthHandler, proxyHandler, adminRedeemHandler, promoHandler, settingHandler, opsHandler, systemHandler, adminSubscriptionHandler, adminUsageHandler, userAttributeHandler, errorPassthroughHandler, tlsFingerprintProfileHandler, adminAPIKeyHandler, scheduledTestHandler, channelHandler, channelMonitorHandler, channelMonitorRequestTemplateHandler, paymentHandler) usageRecordWorkerPool := service.NewUsageRecordWorkerPool(configConfig) userMsgQueueCache := repository.NewUserMsgQueueCache(redisClient) userMessageQueueService := service.ProvideUserMessageQueueService(userMsgQueueCache, rpmCache, configConfig) diff --git a/backend/ent/channelmonitor.go b/backend/ent/channelmonitor.go index 58886884..dbb73362 100644 --- a/backend/ent/channelmonitor.go +++ b/backend/ent/channelmonitor.go @@ -11,6 +11,7 @@ import ( "entgo.io/ent" "entgo.io/ent/dialect/sql" "github.com/Wei-Shaw/sub2api/ent/channelmonitor" + "github.com/Wei-Shaw/sub2api/ent/channelmonitorrequesttemplate" ) // ChannelMonitor is the model entity for the ChannelMonitor schema. @@ -44,6 +45,14 @@ type ChannelMonitor struct { LastCheckedAt *time.Time `json:"last_checked_at,omitempty"` // CreatedBy holds the value of the "created_by" field. CreatedBy int64 `json:"created_by,omitempty"` + // TemplateID holds the value of the "template_id" field. + TemplateID *int64 `json:"template_id,omitempty"` + // ExtraHeaders holds the value of the "extra_headers" field. + ExtraHeaders map[string]string `json:"extra_headers,omitempty"` + // BodyOverrideMode holds the value of the "body_override_mode" field. + BodyOverrideMode string `json:"body_override_mode,omitempty"` + // BodyOverride holds the value of the "body_override" field. + BodyOverride map[string]interface{} `json:"body_override,omitempty"` // Edges holds the relations/edges for other nodes in the graph. // The values are being populated by the ChannelMonitorQuery when eager-loading is set. Edges ChannelMonitorEdges `json:"edges"` @@ -56,9 +65,11 @@ type ChannelMonitorEdges struct { History []*ChannelMonitorHistory `json:"history,omitempty"` // DailyRollups holds the value of the daily_rollups edge. DailyRollups []*ChannelMonitorDailyRollup `json:"daily_rollups,omitempty"` + // RequestTemplate holds the value of the request_template edge. + RequestTemplate *ChannelMonitorRequestTemplate `json:"request_template,omitempty"` // loadedTypes holds the information for reporting if a // type was loaded (or requested) in eager-loading or not. - loadedTypes [2]bool + loadedTypes [3]bool } // HistoryOrErr returns the History value or an error if the edge @@ -79,18 +90,29 @@ func (e ChannelMonitorEdges) DailyRollupsOrErr() ([]*ChannelMonitorDailyRollup, return nil, &NotLoadedError{edge: "daily_rollups"} } +// RequestTemplateOrErr returns the RequestTemplate value or an error if the edge +// was not loaded in eager-loading, or loaded but was not found. +func (e ChannelMonitorEdges) RequestTemplateOrErr() (*ChannelMonitorRequestTemplate, error) { + if e.RequestTemplate != nil { + return e.RequestTemplate, nil + } else if e.loadedTypes[2] { + return nil, &NotFoundError{label: channelmonitorrequesttemplate.Label} + } + return nil, &NotLoadedError{edge: "request_template"} +} + // scanValues returns the types for scanning values from sql.Rows. func (*ChannelMonitor) scanValues(columns []string) ([]any, error) { values := make([]any, len(columns)) for i := range columns { switch columns[i] { - case channelmonitor.FieldExtraModels: + case channelmonitor.FieldExtraModels, channelmonitor.FieldExtraHeaders, channelmonitor.FieldBodyOverride: values[i] = new([]byte) case channelmonitor.FieldEnabled: values[i] = new(sql.NullBool) - case channelmonitor.FieldID, channelmonitor.FieldIntervalSeconds, channelmonitor.FieldCreatedBy: + case channelmonitor.FieldID, channelmonitor.FieldIntervalSeconds, channelmonitor.FieldCreatedBy, channelmonitor.FieldTemplateID: values[i] = new(sql.NullInt64) - case channelmonitor.FieldName, channelmonitor.FieldProvider, channelmonitor.FieldEndpoint, channelmonitor.FieldAPIKeyEncrypted, channelmonitor.FieldPrimaryModel, channelmonitor.FieldGroupName: + case channelmonitor.FieldName, channelmonitor.FieldProvider, channelmonitor.FieldEndpoint, channelmonitor.FieldAPIKeyEncrypted, channelmonitor.FieldPrimaryModel, channelmonitor.FieldGroupName, channelmonitor.FieldBodyOverrideMode: values[i] = new(sql.NullString) case channelmonitor.FieldCreatedAt, channelmonitor.FieldUpdatedAt, channelmonitor.FieldLastCheckedAt: values[i] = new(sql.NullTime) @@ -196,6 +218,35 @@ func (_m *ChannelMonitor) assignValues(columns []string, values []any) error { } else if value.Valid { _m.CreatedBy = value.Int64 } + case channelmonitor.FieldTemplateID: + if value, ok := values[i].(*sql.NullInt64); !ok { + return fmt.Errorf("unexpected type %T for field template_id", values[i]) + } else if value.Valid { + _m.TemplateID = new(int64) + *_m.TemplateID = value.Int64 + } + case channelmonitor.FieldExtraHeaders: + if value, ok := values[i].(*[]byte); !ok { + return fmt.Errorf("unexpected type %T for field extra_headers", values[i]) + } else if value != nil && len(*value) > 0 { + if err := json.Unmarshal(*value, &_m.ExtraHeaders); err != nil { + return fmt.Errorf("unmarshal field extra_headers: %w", err) + } + } + case channelmonitor.FieldBodyOverrideMode: + if value, ok := values[i].(*sql.NullString); !ok { + return fmt.Errorf("unexpected type %T for field body_override_mode", values[i]) + } else if value.Valid { + _m.BodyOverrideMode = value.String + } + case channelmonitor.FieldBodyOverride: + if value, ok := values[i].(*[]byte); !ok { + return fmt.Errorf("unexpected type %T for field body_override", values[i]) + } else if value != nil && len(*value) > 0 { + if err := json.Unmarshal(*value, &_m.BodyOverride); err != nil { + return fmt.Errorf("unmarshal field body_override: %w", err) + } + } default: _m.selectValues.Set(columns[i], values[i]) } @@ -219,6 +270,11 @@ func (_m *ChannelMonitor) QueryDailyRollups() *ChannelMonitorDailyRollupQuery { return NewChannelMonitorClient(_m.config).QueryDailyRollups(_m) } +// QueryRequestTemplate queries the "request_template" edge of the ChannelMonitor entity. +func (_m *ChannelMonitor) QueryRequestTemplate() *ChannelMonitorRequestTemplateQuery { + return NewChannelMonitorClient(_m.config).QueryRequestTemplate(_m) +} + // Update returns a builder for updating this ChannelMonitor. // Note that you need to call ChannelMonitor.Unwrap() before calling this method if this ChannelMonitor // was returned from a transaction, and the transaction was committed or rolled back. @@ -281,6 +337,20 @@ func (_m *ChannelMonitor) String() string { builder.WriteString(", ") builder.WriteString("created_by=") builder.WriteString(fmt.Sprintf("%v", _m.CreatedBy)) + builder.WriteString(", ") + if v := _m.TemplateID; v != nil { + builder.WriteString("template_id=") + builder.WriteString(fmt.Sprintf("%v", *v)) + } + builder.WriteString(", ") + builder.WriteString("extra_headers=") + builder.WriteString(fmt.Sprintf("%v", _m.ExtraHeaders)) + builder.WriteString(", ") + builder.WriteString("body_override_mode=") + builder.WriteString(_m.BodyOverrideMode) + builder.WriteString(", ") + builder.WriteString("body_override=") + builder.WriteString(fmt.Sprintf("%v", _m.BodyOverride)) builder.WriteByte(')') return builder.String() } diff --git a/backend/ent/channelmonitor/channelmonitor.go b/backend/ent/channelmonitor/channelmonitor.go index ff6d7105..e5a6bfe7 100644 --- a/backend/ent/channelmonitor/channelmonitor.go +++ b/backend/ent/channelmonitor/channelmonitor.go @@ -41,10 +41,20 @@ const ( FieldLastCheckedAt = "last_checked_at" // FieldCreatedBy holds the string denoting the created_by field in the database. FieldCreatedBy = "created_by" + // FieldTemplateID holds the string denoting the template_id field in the database. + FieldTemplateID = "template_id" + // FieldExtraHeaders holds the string denoting the extra_headers field in the database. + FieldExtraHeaders = "extra_headers" + // FieldBodyOverrideMode holds the string denoting the body_override_mode field in the database. + FieldBodyOverrideMode = "body_override_mode" + // FieldBodyOverride holds the string denoting the body_override field in the database. + FieldBodyOverride = "body_override" // EdgeHistory holds the string denoting the history edge name in mutations. EdgeHistory = "history" // EdgeDailyRollups holds the string denoting the daily_rollups edge name in mutations. EdgeDailyRollups = "daily_rollups" + // EdgeRequestTemplate holds the string denoting the request_template edge name in mutations. + EdgeRequestTemplate = "request_template" // Table holds the table name of the channelmonitor in the database. Table = "channel_monitors" // HistoryTable is the table that holds the history relation/edge. @@ -61,6 +71,13 @@ const ( DailyRollupsInverseTable = "channel_monitor_daily_rollups" // DailyRollupsColumn is the table column denoting the daily_rollups relation/edge. DailyRollupsColumn = "monitor_id" + // RequestTemplateTable is the table that holds the request_template relation/edge. + RequestTemplateTable = "channel_monitors" + // RequestTemplateInverseTable is the table name for the ChannelMonitorRequestTemplate entity. + // It exists in this package in order to avoid circular dependency with the "channelmonitorrequesttemplate" package. + RequestTemplateInverseTable = "channel_monitor_request_templates" + // RequestTemplateColumn is the table column denoting the request_template relation/edge. + RequestTemplateColumn = "template_id" ) // Columns holds all SQL columns for channelmonitor fields. @@ -79,6 +96,10 @@ var Columns = []string{ FieldIntervalSeconds, FieldLastCheckedAt, FieldCreatedBy, + FieldTemplateID, + FieldExtraHeaders, + FieldBodyOverrideMode, + FieldBodyOverride, } // ValidColumn reports if the column name is valid (part of the table columns). @@ -116,6 +137,12 @@ var ( DefaultEnabled bool // IntervalSecondsValidator is a validator for the "interval_seconds" field. It is called by the builders before save. IntervalSecondsValidator func(int) error + // DefaultExtraHeaders holds the default value on creation for the "extra_headers" field. + DefaultExtraHeaders map[string]string + // DefaultBodyOverrideMode holds the default value on creation for the "body_override_mode" field. + DefaultBodyOverrideMode string + // BodyOverrideModeValidator is a validator for the "body_override_mode" field. It is called by the builders before save. + BodyOverrideModeValidator func(string) error ) // Provider defines the type for the "provider" enum field. @@ -210,6 +237,16 @@ func ByCreatedBy(opts ...sql.OrderTermOption) OrderOption { return sql.OrderByField(FieldCreatedBy, opts...).ToFunc() } +// ByTemplateID orders the results by the template_id field. +func ByTemplateID(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldTemplateID, opts...).ToFunc() +} + +// ByBodyOverrideMode orders the results by the body_override_mode field. +func ByBodyOverrideMode(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldBodyOverrideMode, opts...).ToFunc() +} + // ByHistoryCount orders the results by history count. func ByHistoryCount(opts ...sql.OrderTermOption) OrderOption { return func(s *sql.Selector) { @@ -237,6 +274,13 @@ func ByDailyRollups(term sql.OrderTerm, terms ...sql.OrderTerm) OrderOption { sqlgraph.OrderByNeighborTerms(s, newDailyRollupsStep(), append([]sql.OrderTerm{term}, terms...)...) } } + +// ByRequestTemplateField orders the results by request_template field. +func ByRequestTemplateField(field string, opts ...sql.OrderTermOption) OrderOption { + return func(s *sql.Selector) { + sqlgraph.OrderByNeighborTerms(s, newRequestTemplateStep(), sql.OrderByField(field, opts...)) + } +} func newHistoryStep() *sqlgraph.Step { return sqlgraph.NewStep( sqlgraph.From(Table, FieldID), @@ -251,3 +295,10 @@ func newDailyRollupsStep() *sqlgraph.Step { sqlgraph.Edge(sqlgraph.O2M, false, DailyRollupsTable, DailyRollupsColumn), ) } +func newRequestTemplateStep() *sqlgraph.Step { + return sqlgraph.NewStep( + sqlgraph.From(Table, FieldID), + sqlgraph.To(RequestTemplateInverseTable, FieldID), + sqlgraph.Edge(sqlgraph.M2O, false, RequestTemplateTable, RequestTemplateColumn), + ) +} diff --git a/backend/ent/channelmonitor/where.go b/backend/ent/channelmonitor/where.go index abb8484d..755d83a3 100644 --- a/backend/ent/channelmonitor/where.go +++ b/backend/ent/channelmonitor/where.go @@ -110,6 +110,16 @@ func CreatedBy(v int64) predicate.ChannelMonitor { return predicate.ChannelMonitor(sql.FieldEQ(FieldCreatedBy, v)) } +// TemplateID applies equality check predicate on the "template_id" field. It's identical to TemplateIDEQ. +func TemplateID(v int64) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldEQ(FieldTemplateID, v)) +} + +// BodyOverrideMode applies equality check predicate on the "body_override_mode" field. It's identical to BodyOverrideModeEQ. +func BodyOverrideMode(v string) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldEQ(FieldBodyOverrideMode, v)) +} + // CreatedAtEQ applies the EQ predicate on the "created_at" field. func CreatedAtEQ(v time.Time) predicate.ChannelMonitor { return predicate.ChannelMonitor(sql.FieldEQ(FieldCreatedAt, v)) @@ -685,6 +695,111 @@ func CreatedByLTE(v int64) predicate.ChannelMonitor { return predicate.ChannelMonitor(sql.FieldLTE(FieldCreatedBy, v)) } +// TemplateIDEQ applies the EQ predicate on the "template_id" field. +func TemplateIDEQ(v int64) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldEQ(FieldTemplateID, v)) +} + +// TemplateIDNEQ applies the NEQ predicate on the "template_id" field. +func TemplateIDNEQ(v int64) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldNEQ(FieldTemplateID, v)) +} + +// TemplateIDIn applies the In predicate on the "template_id" field. +func TemplateIDIn(vs ...int64) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldIn(FieldTemplateID, vs...)) +} + +// TemplateIDNotIn applies the NotIn predicate on the "template_id" field. +func TemplateIDNotIn(vs ...int64) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldNotIn(FieldTemplateID, vs...)) +} + +// TemplateIDIsNil applies the IsNil predicate on the "template_id" field. +func TemplateIDIsNil() predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldIsNull(FieldTemplateID)) +} + +// TemplateIDNotNil applies the NotNil predicate on the "template_id" field. +func TemplateIDNotNil() predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldNotNull(FieldTemplateID)) +} + +// BodyOverrideModeEQ applies the EQ predicate on the "body_override_mode" field. +func BodyOverrideModeEQ(v string) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldEQ(FieldBodyOverrideMode, v)) +} + +// BodyOverrideModeNEQ applies the NEQ predicate on the "body_override_mode" field. +func BodyOverrideModeNEQ(v string) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldNEQ(FieldBodyOverrideMode, v)) +} + +// BodyOverrideModeIn applies the In predicate on the "body_override_mode" field. +func BodyOverrideModeIn(vs ...string) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldIn(FieldBodyOverrideMode, vs...)) +} + +// BodyOverrideModeNotIn applies the NotIn predicate on the "body_override_mode" field. +func BodyOverrideModeNotIn(vs ...string) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldNotIn(FieldBodyOverrideMode, vs...)) +} + +// BodyOverrideModeGT applies the GT predicate on the "body_override_mode" field. +func BodyOverrideModeGT(v string) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldGT(FieldBodyOverrideMode, v)) +} + +// BodyOverrideModeGTE applies the GTE predicate on the "body_override_mode" field. +func BodyOverrideModeGTE(v string) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldGTE(FieldBodyOverrideMode, v)) +} + +// BodyOverrideModeLT applies the LT predicate on the "body_override_mode" field. +func BodyOverrideModeLT(v string) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldLT(FieldBodyOverrideMode, v)) +} + +// BodyOverrideModeLTE applies the LTE predicate on the "body_override_mode" field. +func BodyOverrideModeLTE(v string) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldLTE(FieldBodyOverrideMode, v)) +} + +// BodyOverrideModeContains applies the Contains predicate on the "body_override_mode" field. +func BodyOverrideModeContains(v string) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldContains(FieldBodyOverrideMode, v)) +} + +// BodyOverrideModeHasPrefix applies the HasPrefix predicate on the "body_override_mode" field. +func BodyOverrideModeHasPrefix(v string) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldHasPrefix(FieldBodyOverrideMode, v)) +} + +// BodyOverrideModeHasSuffix applies the HasSuffix predicate on the "body_override_mode" field. +func BodyOverrideModeHasSuffix(v string) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldHasSuffix(FieldBodyOverrideMode, v)) +} + +// BodyOverrideModeEqualFold applies the EqualFold predicate on the "body_override_mode" field. +func BodyOverrideModeEqualFold(v string) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldEqualFold(FieldBodyOverrideMode, v)) +} + +// BodyOverrideModeContainsFold applies the ContainsFold predicate on the "body_override_mode" field. +func BodyOverrideModeContainsFold(v string) predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldContainsFold(FieldBodyOverrideMode, v)) +} + +// BodyOverrideIsNil applies the IsNil predicate on the "body_override" field. +func BodyOverrideIsNil() predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldIsNull(FieldBodyOverride)) +} + +// BodyOverrideNotNil applies the NotNil predicate on the "body_override" field. +func BodyOverrideNotNil() predicate.ChannelMonitor { + return predicate.ChannelMonitor(sql.FieldNotNull(FieldBodyOverride)) +} + // HasHistory applies the HasEdge predicate on the "history" edge. func HasHistory() predicate.ChannelMonitor { return predicate.ChannelMonitor(func(s *sql.Selector) { @@ -731,6 +846,29 @@ func HasDailyRollupsWith(preds ...predicate.ChannelMonitorDailyRollup) predicate }) } +// HasRequestTemplate applies the HasEdge predicate on the "request_template" edge. +func HasRequestTemplate() predicate.ChannelMonitor { + return predicate.ChannelMonitor(func(s *sql.Selector) { + step := sqlgraph.NewStep( + sqlgraph.From(Table, FieldID), + sqlgraph.Edge(sqlgraph.M2O, false, RequestTemplateTable, RequestTemplateColumn), + ) + sqlgraph.HasNeighbors(s, step) + }) +} + +// HasRequestTemplateWith applies the HasEdge predicate on the "request_template" edge with a given conditions (other predicates). +func HasRequestTemplateWith(preds ...predicate.ChannelMonitorRequestTemplate) predicate.ChannelMonitor { + return predicate.ChannelMonitor(func(s *sql.Selector) { + step := newRequestTemplateStep() + sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) { + for _, p := range preds { + p(s) + } + }) + }) +} + // And groups predicates with the AND operator between them. func And(predicates ...predicate.ChannelMonitor) predicate.ChannelMonitor { return predicate.ChannelMonitor(sql.AndPredicates(predicates...)) diff --git a/backend/ent/channelmonitor_create.go b/backend/ent/channelmonitor_create.go index 30a7b40d..2f70c300 100644 --- a/backend/ent/channelmonitor_create.go +++ b/backend/ent/channelmonitor_create.go @@ -14,6 +14,7 @@ import ( "github.com/Wei-Shaw/sub2api/ent/channelmonitor" "github.com/Wei-Shaw/sub2api/ent/channelmonitordailyrollup" "github.com/Wei-Shaw/sub2api/ent/channelmonitorhistory" + "github.com/Wei-Shaw/sub2api/ent/channelmonitorrequesttemplate" ) // ChannelMonitorCreate is the builder for creating a ChannelMonitor entity. @@ -142,6 +143,46 @@ func (_c *ChannelMonitorCreate) SetCreatedBy(v int64) *ChannelMonitorCreate { return _c } +// SetTemplateID sets the "template_id" field. +func (_c *ChannelMonitorCreate) SetTemplateID(v int64) *ChannelMonitorCreate { + _c.mutation.SetTemplateID(v) + return _c +} + +// SetNillableTemplateID sets the "template_id" field if the given value is not nil. +func (_c *ChannelMonitorCreate) SetNillableTemplateID(v *int64) *ChannelMonitorCreate { + if v != nil { + _c.SetTemplateID(*v) + } + return _c +} + +// SetExtraHeaders sets the "extra_headers" field. +func (_c *ChannelMonitorCreate) SetExtraHeaders(v map[string]string) *ChannelMonitorCreate { + _c.mutation.SetExtraHeaders(v) + return _c +} + +// SetBodyOverrideMode sets the "body_override_mode" field. +func (_c *ChannelMonitorCreate) SetBodyOverrideMode(v string) *ChannelMonitorCreate { + _c.mutation.SetBodyOverrideMode(v) + return _c +} + +// SetNillableBodyOverrideMode sets the "body_override_mode" field if the given value is not nil. +func (_c *ChannelMonitorCreate) SetNillableBodyOverrideMode(v *string) *ChannelMonitorCreate { + if v != nil { + _c.SetBodyOverrideMode(*v) + } + return _c +} + +// SetBodyOverride sets the "body_override" field. +func (_c *ChannelMonitorCreate) SetBodyOverride(v map[string]interface{}) *ChannelMonitorCreate { + _c.mutation.SetBodyOverride(v) + return _c +} + // AddHistoryIDs adds the "history" edge to the ChannelMonitorHistory entity by IDs. func (_c *ChannelMonitorCreate) AddHistoryIDs(ids ...int64) *ChannelMonitorCreate { _c.mutation.AddHistoryIDs(ids...) @@ -172,6 +213,25 @@ func (_c *ChannelMonitorCreate) AddDailyRollups(v ...*ChannelMonitorDailyRollup) return _c.AddDailyRollupIDs(ids...) } +// SetRequestTemplateID sets the "request_template" edge to the ChannelMonitorRequestTemplate entity by ID. +func (_c *ChannelMonitorCreate) SetRequestTemplateID(id int64) *ChannelMonitorCreate { + _c.mutation.SetRequestTemplateID(id) + return _c +} + +// SetNillableRequestTemplateID sets the "request_template" edge to the ChannelMonitorRequestTemplate entity by ID if the given value is not nil. +func (_c *ChannelMonitorCreate) SetNillableRequestTemplateID(id *int64) *ChannelMonitorCreate { + if id != nil { + _c = _c.SetRequestTemplateID(*id) + } + return _c +} + +// SetRequestTemplate sets the "request_template" edge to the ChannelMonitorRequestTemplate entity. +func (_c *ChannelMonitorCreate) SetRequestTemplate(v *ChannelMonitorRequestTemplate) *ChannelMonitorCreate { + return _c.SetRequestTemplateID(v.ID) +} + // Mutation returns the ChannelMonitorMutation object of the builder. func (_c *ChannelMonitorCreate) Mutation() *ChannelMonitorMutation { return _c.mutation @@ -227,6 +287,14 @@ func (_c *ChannelMonitorCreate) defaults() { v := channelmonitor.DefaultEnabled _c.mutation.SetEnabled(v) } + if _, ok := _c.mutation.ExtraHeaders(); !ok { + v := channelmonitor.DefaultExtraHeaders + _c.mutation.SetExtraHeaders(v) + } + if _, ok := _c.mutation.BodyOverrideMode(); !ok { + v := channelmonitor.DefaultBodyOverrideMode + _c.mutation.SetBodyOverrideMode(v) + } } // check runs all checks and user-defined validators on the builder. @@ -299,6 +367,17 @@ func (_c *ChannelMonitorCreate) check() error { if _, ok := _c.mutation.CreatedBy(); !ok { return &ValidationError{Name: "created_by", err: errors.New(`ent: missing required field "ChannelMonitor.created_by"`)} } + if _, ok := _c.mutation.ExtraHeaders(); !ok { + return &ValidationError{Name: "extra_headers", err: errors.New(`ent: missing required field "ChannelMonitor.extra_headers"`)} + } + if _, ok := _c.mutation.BodyOverrideMode(); !ok { + return &ValidationError{Name: "body_override_mode", err: errors.New(`ent: missing required field "ChannelMonitor.body_override_mode"`)} + } + if v, ok := _c.mutation.BodyOverrideMode(); ok { + if err := channelmonitor.BodyOverrideModeValidator(v); err != nil { + return &ValidationError{Name: "body_override_mode", err: fmt.Errorf(`ent: validator failed for field "ChannelMonitor.body_override_mode": %w`, err)} + } + } return nil } @@ -378,6 +457,18 @@ func (_c *ChannelMonitorCreate) createSpec() (*ChannelMonitor, *sqlgraph.CreateS _spec.SetField(channelmonitor.FieldCreatedBy, field.TypeInt64, value) _node.CreatedBy = value } + if value, ok := _c.mutation.ExtraHeaders(); ok { + _spec.SetField(channelmonitor.FieldExtraHeaders, field.TypeJSON, value) + _node.ExtraHeaders = value + } + if value, ok := _c.mutation.BodyOverrideMode(); ok { + _spec.SetField(channelmonitor.FieldBodyOverrideMode, field.TypeString, value) + _node.BodyOverrideMode = value + } + if value, ok := _c.mutation.BodyOverride(); ok { + _spec.SetField(channelmonitor.FieldBodyOverride, field.TypeJSON, value) + _node.BodyOverride = value + } if nodes := _c.mutation.HistoryIDs(); len(nodes) > 0 { edge := &sqlgraph.EdgeSpec{ Rel: sqlgraph.O2M, @@ -410,6 +501,23 @@ func (_c *ChannelMonitorCreate) createSpec() (*ChannelMonitor, *sqlgraph.CreateS } _spec.Edges = append(_spec.Edges, edge) } + if nodes := _c.mutation.RequestTemplateIDs(); len(nodes) > 0 { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2O, + Inverse: false, + Table: channelmonitor.RequestTemplateTable, + Columns: []string{channelmonitor.RequestTemplateColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(channelmonitorrequesttemplate.FieldID, field.TypeInt64), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _node.TemplateID = &nodes[0] + _spec.Edges = append(_spec.Edges, edge) + } return _node, _spec } @@ -630,6 +738,66 @@ func (u *ChannelMonitorUpsert) AddCreatedBy(v int64) *ChannelMonitorUpsert { return u } +// SetTemplateID sets the "template_id" field. +func (u *ChannelMonitorUpsert) SetTemplateID(v int64) *ChannelMonitorUpsert { + u.Set(channelmonitor.FieldTemplateID, v) + return u +} + +// UpdateTemplateID sets the "template_id" field to the value that was provided on create. +func (u *ChannelMonitorUpsert) UpdateTemplateID() *ChannelMonitorUpsert { + u.SetExcluded(channelmonitor.FieldTemplateID) + return u +} + +// ClearTemplateID clears the value of the "template_id" field. +func (u *ChannelMonitorUpsert) ClearTemplateID() *ChannelMonitorUpsert { + u.SetNull(channelmonitor.FieldTemplateID) + return u +} + +// SetExtraHeaders sets the "extra_headers" field. +func (u *ChannelMonitorUpsert) SetExtraHeaders(v map[string]string) *ChannelMonitorUpsert { + u.Set(channelmonitor.FieldExtraHeaders, v) + return u +} + +// UpdateExtraHeaders sets the "extra_headers" field to the value that was provided on create. +func (u *ChannelMonitorUpsert) UpdateExtraHeaders() *ChannelMonitorUpsert { + u.SetExcluded(channelmonitor.FieldExtraHeaders) + return u +} + +// SetBodyOverrideMode sets the "body_override_mode" field. +func (u *ChannelMonitorUpsert) SetBodyOverrideMode(v string) *ChannelMonitorUpsert { + u.Set(channelmonitor.FieldBodyOverrideMode, v) + return u +} + +// UpdateBodyOverrideMode sets the "body_override_mode" field to the value that was provided on create. +func (u *ChannelMonitorUpsert) UpdateBodyOverrideMode() *ChannelMonitorUpsert { + u.SetExcluded(channelmonitor.FieldBodyOverrideMode) + return u +} + +// SetBodyOverride sets the "body_override" field. +func (u *ChannelMonitorUpsert) SetBodyOverride(v map[string]interface{}) *ChannelMonitorUpsert { + u.Set(channelmonitor.FieldBodyOverride, v) + return u +} + +// UpdateBodyOverride sets the "body_override" field to the value that was provided on create. +func (u *ChannelMonitorUpsert) UpdateBodyOverride() *ChannelMonitorUpsert { + u.SetExcluded(channelmonitor.FieldBodyOverride) + return u +} + +// ClearBodyOverride clears the value of the "body_override" field. +func (u *ChannelMonitorUpsert) ClearBodyOverride() *ChannelMonitorUpsert { + u.SetNull(channelmonitor.FieldBodyOverride) + return u +} + // UpdateNewValues updates the mutable fields using the new values that were set on create. // Using this option is equivalent to using: // @@ -871,6 +1039,76 @@ func (u *ChannelMonitorUpsertOne) UpdateCreatedBy() *ChannelMonitorUpsertOne { }) } +// SetTemplateID sets the "template_id" field. +func (u *ChannelMonitorUpsertOne) SetTemplateID(v int64) *ChannelMonitorUpsertOne { + return u.Update(func(s *ChannelMonitorUpsert) { + s.SetTemplateID(v) + }) +} + +// UpdateTemplateID sets the "template_id" field to the value that was provided on create. +func (u *ChannelMonitorUpsertOne) UpdateTemplateID() *ChannelMonitorUpsertOne { + return u.Update(func(s *ChannelMonitorUpsert) { + s.UpdateTemplateID() + }) +} + +// ClearTemplateID clears the value of the "template_id" field. +func (u *ChannelMonitorUpsertOne) ClearTemplateID() *ChannelMonitorUpsertOne { + return u.Update(func(s *ChannelMonitorUpsert) { + s.ClearTemplateID() + }) +} + +// SetExtraHeaders sets the "extra_headers" field. +func (u *ChannelMonitorUpsertOne) SetExtraHeaders(v map[string]string) *ChannelMonitorUpsertOne { + return u.Update(func(s *ChannelMonitorUpsert) { + s.SetExtraHeaders(v) + }) +} + +// UpdateExtraHeaders sets the "extra_headers" field to the value that was provided on create. +func (u *ChannelMonitorUpsertOne) UpdateExtraHeaders() *ChannelMonitorUpsertOne { + return u.Update(func(s *ChannelMonitorUpsert) { + s.UpdateExtraHeaders() + }) +} + +// SetBodyOverrideMode sets the "body_override_mode" field. +func (u *ChannelMonitorUpsertOne) SetBodyOverrideMode(v string) *ChannelMonitorUpsertOne { + return u.Update(func(s *ChannelMonitorUpsert) { + s.SetBodyOverrideMode(v) + }) +} + +// UpdateBodyOverrideMode sets the "body_override_mode" field to the value that was provided on create. +func (u *ChannelMonitorUpsertOne) UpdateBodyOverrideMode() *ChannelMonitorUpsertOne { + return u.Update(func(s *ChannelMonitorUpsert) { + s.UpdateBodyOverrideMode() + }) +} + +// SetBodyOverride sets the "body_override" field. +func (u *ChannelMonitorUpsertOne) SetBodyOverride(v map[string]interface{}) *ChannelMonitorUpsertOne { + return u.Update(func(s *ChannelMonitorUpsert) { + s.SetBodyOverride(v) + }) +} + +// UpdateBodyOverride sets the "body_override" field to the value that was provided on create. +func (u *ChannelMonitorUpsertOne) UpdateBodyOverride() *ChannelMonitorUpsertOne { + return u.Update(func(s *ChannelMonitorUpsert) { + s.UpdateBodyOverride() + }) +} + +// ClearBodyOverride clears the value of the "body_override" field. +func (u *ChannelMonitorUpsertOne) ClearBodyOverride() *ChannelMonitorUpsertOne { + return u.Update(func(s *ChannelMonitorUpsert) { + s.ClearBodyOverride() + }) +} + // Exec executes the query. func (u *ChannelMonitorUpsertOne) Exec(ctx context.Context) error { if len(u.create.conflict) == 0 { @@ -1278,6 +1516,76 @@ func (u *ChannelMonitorUpsertBulk) UpdateCreatedBy() *ChannelMonitorUpsertBulk { }) } +// SetTemplateID sets the "template_id" field. +func (u *ChannelMonitorUpsertBulk) SetTemplateID(v int64) *ChannelMonitorUpsertBulk { + return u.Update(func(s *ChannelMonitorUpsert) { + s.SetTemplateID(v) + }) +} + +// UpdateTemplateID sets the "template_id" field to the value that was provided on create. +func (u *ChannelMonitorUpsertBulk) UpdateTemplateID() *ChannelMonitorUpsertBulk { + return u.Update(func(s *ChannelMonitorUpsert) { + s.UpdateTemplateID() + }) +} + +// ClearTemplateID clears the value of the "template_id" field. +func (u *ChannelMonitorUpsertBulk) ClearTemplateID() *ChannelMonitorUpsertBulk { + return u.Update(func(s *ChannelMonitorUpsert) { + s.ClearTemplateID() + }) +} + +// SetExtraHeaders sets the "extra_headers" field. +func (u *ChannelMonitorUpsertBulk) SetExtraHeaders(v map[string]string) *ChannelMonitorUpsertBulk { + return u.Update(func(s *ChannelMonitorUpsert) { + s.SetExtraHeaders(v) + }) +} + +// UpdateExtraHeaders sets the "extra_headers" field to the value that was provided on create. +func (u *ChannelMonitorUpsertBulk) UpdateExtraHeaders() *ChannelMonitorUpsertBulk { + return u.Update(func(s *ChannelMonitorUpsert) { + s.UpdateExtraHeaders() + }) +} + +// SetBodyOverrideMode sets the "body_override_mode" field. +func (u *ChannelMonitorUpsertBulk) SetBodyOverrideMode(v string) *ChannelMonitorUpsertBulk { + return u.Update(func(s *ChannelMonitorUpsert) { + s.SetBodyOverrideMode(v) + }) +} + +// UpdateBodyOverrideMode sets the "body_override_mode" field to the value that was provided on create. +func (u *ChannelMonitorUpsertBulk) UpdateBodyOverrideMode() *ChannelMonitorUpsertBulk { + return u.Update(func(s *ChannelMonitorUpsert) { + s.UpdateBodyOverrideMode() + }) +} + +// SetBodyOverride sets the "body_override" field. +func (u *ChannelMonitorUpsertBulk) SetBodyOverride(v map[string]interface{}) *ChannelMonitorUpsertBulk { + return u.Update(func(s *ChannelMonitorUpsert) { + s.SetBodyOverride(v) + }) +} + +// UpdateBodyOverride sets the "body_override" field to the value that was provided on create. +func (u *ChannelMonitorUpsertBulk) UpdateBodyOverride() *ChannelMonitorUpsertBulk { + return u.Update(func(s *ChannelMonitorUpsert) { + s.UpdateBodyOverride() + }) +} + +// ClearBodyOverride clears the value of the "body_override" field. +func (u *ChannelMonitorUpsertBulk) ClearBodyOverride() *ChannelMonitorUpsertBulk { + return u.Update(func(s *ChannelMonitorUpsert) { + s.ClearBodyOverride() + }) +} + // Exec executes the query. func (u *ChannelMonitorUpsertBulk) Exec(ctx context.Context) error { if u.create.err != nil { diff --git a/backend/ent/channelmonitor_query.go b/backend/ent/channelmonitor_query.go index 2ebd95bb..b6722e78 100644 --- a/backend/ent/channelmonitor_query.go +++ b/backend/ent/channelmonitor_query.go @@ -16,19 +16,21 @@ import ( "github.com/Wei-Shaw/sub2api/ent/channelmonitor" "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/predicate" ) // ChannelMonitorQuery is the builder for querying ChannelMonitor entities. type ChannelMonitorQuery struct { config - ctx *QueryContext - order []channelmonitor.OrderOption - inters []Interceptor - predicates []predicate.ChannelMonitor - withHistory *ChannelMonitorHistoryQuery - withDailyRollups *ChannelMonitorDailyRollupQuery - modifiers []func(*sql.Selector) + ctx *QueryContext + order []channelmonitor.OrderOption + inters []Interceptor + predicates []predicate.ChannelMonitor + withHistory *ChannelMonitorHistoryQuery + withDailyRollups *ChannelMonitorDailyRollupQuery + withRequestTemplate *ChannelMonitorRequestTemplateQuery + modifiers []func(*sql.Selector) // intermediate query (i.e. traversal path). sql *sql.Selector path func(context.Context) (*sql.Selector, error) @@ -109,6 +111,28 @@ func (_q *ChannelMonitorQuery) QueryDailyRollups() *ChannelMonitorDailyRollupQue return query } +// QueryRequestTemplate chains the current query on the "request_template" edge. +func (_q *ChannelMonitorQuery) QueryRequestTemplate() *ChannelMonitorRequestTemplateQuery { + query := (&ChannelMonitorRequestTemplateClient{config: _q.config}).Query() + query.path = func(ctx context.Context) (fromU *sql.Selector, err error) { + if err := _q.prepareQuery(ctx); err != nil { + return nil, err + } + selector := _q.sqlQuery(ctx) + if err := selector.Err(); err != nil { + return nil, err + } + step := sqlgraph.NewStep( + sqlgraph.From(channelmonitor.Table, channelmonitor.FieldID, selector), + sqlgraph.To(channelmonitorrequesttemplate.Table, channelmonitorrequesttemplate.FieldID), + sqlgraph.Edge(sqlgraph.M2O, false, channelmonitor.RequestTemplateTable, channelmonitor.RequestTemplateColumn), + ) + fromU = sqlgraph.SetNeighbors(_q.driver.Dialect(), step) + return fromU, nil + } + return query +} + // First returns the first ChannelMonitor entity from the query. // Returns a *NotFoundError when no ChannelMonitor was found. func (_q *ChannelMonitorQuery) First(ctx context.Context) (*ChannelMonitor, error) { @@ -296,13 +320,14 @@ func (_q *ChannelMonitorQuery) Clone() *ChannelMonitorQuery { return nil } return &ChannelMonitorQuery{ - config: _q.config, - ctx: _q.ctx.Clone(), - order: append([]channelmonitor.OrderOption{}, _q.order...), - inters: append([]Interceptor{}, _q.inters...), - predicates: append([]predicate.ChannelMonitor{}, _q.predicates...), - withHistory: _q.withHistory.Clone(), - withDailyRollups: _q.withDailyRollups.Clone(), + config: _q.config, + ctx: _q.ctx.Clone(), + order: append([]channelmonitor.OrderOption{}, _q.order...), + inters: append([]Interceptor{}, _q.inters...), + predicates: append([]predicate.ChannelMonitor{}, _q.predicates...), + withHistory: _q.withHistory.Clone(), + withDailyRollups: _q.withDailyRollups.Clone(), + withRequestTemplate: _q.withRequestTemplate.Clone(), // clone intermediate query. sql: _q.sql.Clone(), path: _q.path, @@ -331,6 +356,17 @@ func (_q *ChannelMonitorQuery) WithDailyRollups(opts ...func(*ChannelMonitorDail return _q } +// WithRequestTemplate tells the query-builder to eager-load the nodes that are connected to +// the "request_template" edge. The optional arguments are used to configure the query builder of the edge. +func (_q *ChannelMonitorQuery) WithRequestTemplate(opts ...func(*ChannelMonitorRequestTemplateQuery)) *ChannelMonitorQuery { + query := (&ChannelMonitorRequestTemplateClient{config: _q.config}).Query() + for _, opt := range opts { + opt(query) + } + _q.withRequestTemplate = query + return _q +} + // 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. // @@ -409,9 +445,10 @@ func (_q *ChannelMonitorQuery) sqlAll(ctx context.Context, hooks ...queryHook) ( var ( nodes = []*ChannelMonitor{} _spec = _q.querySpec() - loadedTypes = [2]bool{ + loadedTypes = [3]bool{ _q.withHistory != nil, _q.withDailyRollups != nil, + _q.withRequestTemplate != nil, } ) _spec.ScanValues = func(columns []string) ([]any, error) { @@ -451,6 +488,12 @@ func (_q *ChannelMonitorQuery) sqlAll(ctx context.Context, hooks ...queryHook) ( return nil, err } } + if query := _q.withRequestTemplate; query != nil { + if err := _q.loadRequestTemplate(ctx, query, nodes, nil, + func(n *ChannelMonitor, e *ChannelMonitorRequestTemplate) { n.Edges.RequestTemplate = e }); err != nil { + return nil, err + } + } return nodes, nil } @@ -514,6 +557,38 @@ func (_q *ChannelMonitorQuery) loadDailyRollups(ctx context.Context, query *Chan } return nil } +func (_q *ChannelMonitorQuery) loadRequestTemplate(ctx context.Context, query *ChannelMonitorRequestTemplateQuery, nodes []*ChannelMonitor, init func(*ChannelMonitor), assign func(*ChannelMonitor, *ChannelMonitorRequestTemplate)) error { + ids := make([]int64, 0, len(nodes)) + nodeids := make(map[int64][]*ChannelMonitor) + for i := range nodes { + if nodes[i].TemplateID == nil { + continue + } + fk := *nodes[i].TemplateID + if _, ok := nodeids[fk]; !ok { + ids = append(ids, fk) + } + nodeids[fk] = append(nodeids[fk], nodes[i]) + } + if len(ids) == 0 { + return nil + } + query.Where(channelmonitorrequesttemplate.IDIn(ids...)) + neighbors, err := query.All(ctx) + if err != nil { + return err + } + for _, n := range neighbors { + nodes, ok := nodeids[n.ID] + if !ok { + return fmt.Errorf(`unexpected foreign-key "template_id" returned %v`, n.ID) + } + for i := range nodes { + assign(nodes[i], n) + } + } + return nil +} func (_q *ChannelMonitorQuery) sqlCount(ctx context.Context) (int, error) { _spec := _q.querySpec() @@ -543,6 +618,9 @@ func (_q *ChannelMonitorQuery) querySpec() *sqlgraph.QuerySpec { _spec.Node.Columns = append(_spec.Node.Columns, fields[i]) } } + if _q.withRequestTemplate != nil { + _spec.Node.AddColumnOnce(channelmonitor.FieldTemplateID) + } } if ps := _q.predicates; len(ps) > 0 { _spec.Predicate = func(selector *sql.Selector) { diff --git a/backend/ent/channelmonitor_update.go b/backend/ent/channelmonitor_update.go index 7ba4e449..4bbcd564 100644 --- a/backend/ent/channelmonitor_update.go +++ b/backend/ent/channelmonitor_update.go @@ -15,6 +15,7 @@ import ( "github.com/Wei-Shaw/sub2api/ent/channelmonitor" "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/predicate" ) @@ -215,6 +216,58 @@ func (_u *ChannelMonitorUpdate) AddCreatedBy(v int64) *ChannelMonitorUpdate { return _u } +// SetTemplateID sets the "template_id" field. +func (_u *ChannelMonitorUpdate) SetTemplateID(v int64) *ChannelMonitorUpdate { + _u.mutation.SetTemplateID(v) + return _u +} + +// SetNillableTemplateID sets the "template_id" field if the given value is not nil. +func (_u *ChannelMonitorUpdate) SetNillableTemplateID(v *int64) *ChannelMonitorUpdate { + if v != nil { + _u.SetTemplateID(*v) + } + return _u +} + +// ClearTemplateID clears the value of the "template_id" field. +func (_u *ChannelMonitorUpdate) ClearTemplateID() *ChannelMonitorUpdate { + _u.mutation.ClearTemplateID() + return _u +} + +// SetExtraHeaders sets the "extra_headers" field. +func (_u *ChannelMonitorUpdate) SetExtraHeaders(v map[string]string) *ChannelMonitorUpdate { + _u.mutation.SetExtraHeaders(v) + return _u +} + +// SetBodyOverrideMode sets the "body_override_mode" field. +func (_u *ChannelMonitorUpdate) SetBodyOverrideMode(v string) *ChannelMonitorUpdate { + _u.mutation.SetBodyOverrideMode(v) + return _u +} + +// SetNillableBodyOverrideMode sets the "body_override_mode" field if the given value is not nil. +func (_u *ChannelMonitorUpdate) SetNillableBodyOverrideMode(v *string) *ChannelMonitorUpdate { + if v != nil { + _u.SetBodyOverrideMode(*v) + } + return _u +} + +// SetBodyOverride sets the "body_override" field. +func (_u *ChannelMonitorUpdate) SetBodyOverride(v map[string]interface{}) *ChannelMonitorUpdate { + _u.mutation.SetBodyOverride(v) + return _u +} + +// ClearBodyOverride clears the value of the "body_override" field. +func (_u *ChannelMonitorUpdate) ClearBodyOverride() *ChannelMonitorUpdate { + _u.mutation.ClearBodyOverride() + return _u +} + // AddHistoryIDs adds the "history" edge to the ChannelMonitorHistory entity by IDs. func (_u *ChannelMonitorUpdate) AddHistoryIDs(ids ...int64) *ChannelMonitorUpdate { _u.mutation.AddHistoryIDs(ids...) @@ -245,6 +298,25 @@ func (_u *ChannelMonitorUpdate) AddDailyRollups(v ...*ChannelMonitorDailyRollup) return _u.AddDailyRollupIDs(ids...) } +// SetRequestTemplateID sets the "request_template" edge to the ChannelMonitorRequestTemplate entity by ID. +func (_u *ChannelMonitorUpdate) SetRequestTemplateID(id int64) *ChannelMonitorUpdate { + _u.mutation.SetRequestTemplateID(id) + return _u +} + +// SetNillableRequestTemplateID sets the "request_template" edge to the ChannelMonitorRequestTemplate entity by ID if the given value is not nil. +func (_u *ChannelMonitorUpdate) SetNillableRequestTemplateID(id *int64) *ChannelMonitorUpdate { + if id != nil { + _u = _u.SetRequestTemplateID(*id) + } + return _u +} + +// SetRequestTemplate sets the "request_template" edge to the ChannelMonitorRequestTemplate entity. +func (_u *ChannelMonitorUpdate) SetRequestTemplate(v *ChannelMonitorRequestTemplate) *ChannelMonitorUpdate { + return _u.SetRequestTemplateID(v.ID) +} + // Mutation returns the ChannelMonitorMutation object of the builder. func (_u *ChannelMonitorUpdate) Mutation() *ChannelMonitorMutation { return _u.mutation @@ -292,6 +364,12 @@ func (_u *ChannelMonitorUpdate) RemoveDailyRollups(v ...*ChannelMonitorDailyRoll return _u.RemoveDailyRollupIDs(ids...) } +// ClearRequestTemplate clears the "request_template" edge to the ChannelMonitorRequestTemplate entity. +func (_u *ChannelMonitorUpdate) ClearRequestTemplate() *ChannelMonitorUpdate { + _u.mutation.ClearRequestTemplate() + return _u +} + // Save executes the query and returns the number of nodes affected by the update operation. func (_u *ChannelMonitorUpdate) Save(ctx context.Context) (int, error) { _u.defaults() @@ -365,6 +443,11 @@ func (_u *ChannelMonitorUpdate) check() error { return &ValidationError{Name: "interval_seconds", err: fmt.Errorf(`ent: validator failed for field "ChannelMonitor.interval_seconds": %w`, err)} } } + if v, ok := _u.mutation.BodyOverrideMode(); ok { + if err := channelmonitor.BodyOverrideModeValidator(v); err != nil { + return &ValidationError{Name: "body_override_mode", err: fmt.Errorf(`ent: validator failed for field "ChannelMonitor.body_override_mode": %w`, err)} + } + } return nil } @@ -433,6 +516,18 @@ func (_u *ChannelMonitorUpdate) sqlSave(ctx context.Context) (_node int, err err if value, ok := _u.mutation.AddedCreatedBy(); ok { _spec.AddField(channelmonitor.FieldCreatedBy, field.TypeInt64, value) } + if value, ok := _u.mutation.ExtraHeaders(); ok { + _spec.SetField(channelmonitor.FieldExtraHeaders, field.TypeJSON, value) + } + if value, ok := _u.mutation.BodyOverrideMode(); ok { + _spec.SetField(channelmonitor.FieldBodyOverrideMode, field.TypeString, value) + } + if value, ok := _u.mutation.BodyOverride(); ok { + _spec.SetField(channelmonitor.FieldBodyOverride, field.TypeJSON, value) + } + if _u.mutation.BodyOverrideCleared() { + _spec.ClearField(channelmonitor.FieldBodyOverride, field.TypeJSON) + } if _u.mutation.HistoryCleared() { edge := &sqlgraph.EdgeSpec{ Rel: sqlgraph.O2M, @@ -523,6 +618,35 @@ func (_u *ChannelMonitorUpdate) sqlSave(ctx context.Context) (_node int, err err } _spec.Edges.Add = append(_spec.Edges.Add, edge) } + if _u.mutation.RequestTemplateCleared() { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2O, + Inverse: false, + Table: channelmonitor.RequestTemplateTable, + Columns: []string{channelmonitor.RequestTemplateColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(channelmonitorrequesttemplate.FieldID, field.TypeInt64), + }, + } + _spec.Edges.Clear = append(_spec.Edges.Clear, edge) + } + if nodes := _u.mutation.RequestTemplateIDs(); len(nodes) > 0 { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2O, + Inverse: false, + Table: channelmonitor.RequestTemplateTable, + Columns: []string{channelmonitor.RequestTemplateColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(channelmonitorrequesttemplate.FieldID, field.TypeInt64), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _spec.Edges.Add = append(_spec.Edges.Add, edge) + } if _node, err = sqlgraph.UpdateNodes(ctx, _u.driver, _spec); err != nil { if _, ok := err.(*sqlgraph.NotFoundError); ok { err = &NotFoundError{channelmonitor.Label} @@ -727,6 +851,58 @@ func (_u *ChannelMonitorUpdateOne) AddCreatedBy(v int64) *ChannelMonitorUpdateOn return _u } +// SetTemplateID sets the "template_id" field. +func (_u *ChannelMonitorUpdateOne) SetTemplateID(v int64) *ChannelMonitorUpdateOne { + _u.mutation.SetTemplateID(v) + return _u +} + +// SetNillableTemplateID sets the "template_id" field if the given value is not nil. +func (_u *ChannelMonitorUpdateOne) SetNillableTemplateID(v *int64) *ChannelMonitorUpdateOne { + if v != nil { + _u.SetTemplateID(*v) + } + return _u +} + +// ClearTemplateID clears the value of the "template_id" field. +func (_u *ChannelMonitorUpdateOne) ClearTemplateID() *ChannelMonitorUpdateOne { + _u.mutation.ClearTemplateID() + return _u +} + +// SetExtraHeaders sets the "extra_headers" field. +func (_u *ChannelMonitorUpdateOne) SetExtraHeaders(v map[string]string) *ChannelMonitorUpdateOne { + _u.mutation.SetExtraHeaders(v) + return _u +} + +// SetBodyOverrideMode sets the "body_override_mode" field. +func (_u *ChannelMonitorUpdateOne) SetBodyOverrideMode(v string) *ChannelMonitorUpdateOne { + _u.mutation.SetBodyOverrideMode(v) + return _u +} + +// SetNillableBodyOverrideMode sets the "body_override_mode" field if the given value is not nil. +func (_u *ChannelMonitorUpdateOne) SetNillableBodyOverrideMode(v *string) *ChannelMonitorUpdateOne { + if v != nil { + _u.SetBodyOverrideMode(*v) + } + return _u +} + +// SetBodyOverride sets the "body_override" field. +func (_u *ChannelMonitorUpdateOne) SetBodyOverride(v map[string]interface{}) *ChannelMonitorUpdateOne { + _u.mutation.SetBodyOverride(v) + return _u +} + +// ClearBodyOverride clears the value of the "body_override" field. +func (_u *ChannelMonitorUpdateOne) ClearBodyOverride() *ChannelMonitorUpdateOne { + _u.mutation.ClearBodyOverride() + return _u +} + // AddHistoryIDs adds the "history" edge to the ChannelMonitorHistory entity by IDs. func (_u *ChannelMonitorUpdateOne) AddHistoryIDs(ids ...int64) *ChannelMonitorUpdateOne { _u.mutation.AddHistoryIDs(ids...) @@ -757,6 +933,25 @@ func (_u *ChannelMonitorUpdateOne) AddDailyRollups(v ...*ChannelMonitorDailyRoll return _u.AddDailyRollupIDs(ids...) } +// SetRequestTemplateID sets the "request_template" edge to the ChannelMonitorRequestTemplate entity by ID. +func (_u *ChannelMonitorUpdateOne) SetRequestTemplateID(id int64) *ChannelMonitorUpdateOne { + _u.mutation.SetRequestTemplateID(id) + return _u +} + +// SetNillableRequestTemplateID sets the "request_template" edge to the ChannelMonitorRequestTemplate entity by ID if the given value is not nil. +func (_u *ChannelMonitorUpdateOne) SetNillableRequestTemplateID(id *int64) *ChannelMonitorUpdateOne { + if id != nil { + _u = _u.SetRequestTemplateID(*id) + } + return _u +} + +// SetRequestTemplate sets the "request_template" edge to the ChannelMonitorRequestTemplate entity. +func (_u *ChannelMonitorUpdateOne) SetRequestTemplate(v *ChannelMonitorRequestTemplate) *ChannelMonitorUpdateOne { + return _u.SetRequestTemplateID(v.ID) +} + // Mutation returns the ChannelMonitorMutation object of the builder. func (_u *ChannelMonitorUpdateOne) Mutation() *ChannelMonitorMutation { return _u.mutation @@ -804,6 +999,12 @@ func (_u *ChannelMonitorUpdateOne) RemoveDailyRollups(v ...*ChannelMonitorDailyR return _u.RemoveDailyRollupIDs(ids...) } +// ClearRequestTemplate clears the "request_template" edge to the ChannelMonitorRequestTemplate entity. +func (_u *ChannelMonitorUpdateOne) ClearRequestTemplate() *ChannelMonitorUpdateOne { + _u.mutation.ClearRequestTemplate() + return _u +} + // Where appends a list predicates to the ChannelMonitorUpdate builder. func (_u *ChannelMonitorUpdateOne) Where(ps ...predicate.ChannelMonitor) *ChannelMonitorUpdateOne { _u.mutation.Where(ps...) @@ -890,6 +1091,11 @@ func (_u *ChannelMonitorUpdateOne) check() error { return &ValidationError{Name: "interval_seconds", err: fmt.Errorf(`ent: validator failed for field "ChannelMonitor.interval_seconds": %w`, err)} } } + if v, ok := _u.mutation.BodyOverrideMode(); ok { + if err := channelmonitor.BodyOverrideModeValidator(v); err != nil { + return &ValidationError{Name: "body_override_mode", err: fmt.Errorf(`ent: validator failed for field "ChannelMonitor.body_override_mode": %w`, err)} + } + } return nil } @@ -975,6 +1181,18 @@ func (_u *ChannelMonitorUpdateOne) sqlSave(ctx context.Context) (_node *ChannelM if value, ok := _u.mutation.AddedCreatedBy(); ok { _spec.AddField(channelmonitor.FieldCreatedBy, field.TypeInt64, value) } + if value, ok := _u.mutation.ExtraHeaders(); ok { + _spec.SetField(channelmonitor.FieldExtraHeaders, field.TypeJSON, value) + } + if value, ok := _u.mutation.BodyOverrideMode(); ok { + _spec.SetField(channelmonitor.FieldBodyOverrideMode, field.TypeString, value) + } + if value, ok := _u.mutation.BodyOverride(); ok { + _spec.SetField(channelmonitor.FieldBodyOverride, field.TypeJSON, value) + } + if _u.mutation.BodyOverrideCleared() { + _spec.ClearField(channelmonitor.FieldBodyOverride, field.TypeJSON) + } if _u.mutation.HistoryCleared() { edge := &sqlgraph.EdgeSpec{ Rel: sqlgraph.O2M, @@ -1065,6 +1283,35 @@ func (_u *ChannelMonitorUpdateOne) sqlSave(ctx context.Context) (_node *ChannelM } _spec.Edges.Add = append(_spec.Edges.Add, edge) } + if _u.mutation.RequestTemplateCleared() { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2O, + Inverse: false, + Table: channelmonitor.RequestTemplateTable, + Columns: []string{channelmonitor.RequestTemplateColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(channelmonitorrequesttemplate.FieldID, field.TypeInt64), + }, + } + _spec.Edges.Clear = append(_spec.Edges.Clear, edge) + } + if nodes := _u.mutation.RequestTemplateIDs(); len(nodes) > 0 { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2O, + Inverse: false, + Table: channelmonitor.RequestTemplateTable, + Columns: []string{channelmonitor.RequestTemplateColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(channelmonitorrequesttemplate.FieldID, field.TypeInt64), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _spec.Edges.Add = append(_spec.Edges.Add, edge) + } _node = &ChannelMonitor{config: _u.config} _spec.Assign = _node.assignValues _spec.ScanValues = _node.scanValues diff --git a/backend/ent/channelmonitorrequesttemplate.go b/backend/ent/channelmonitorrequesttemplate.go new file mode 100644 index 00000000..b8429a4d --- /dev/null +++ b/backend/ent/channelmonitorrequesttemplate.go @@ -0,0 +1,216 @@ +// 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/channelmonitorrequesttemplate" +) + +// ChannelMonitorRequestTemplate is the model entity for the ChannelMonitorRequestTemplate schema. +type ChannelMonitorRequestTemplate struct { + config `json:"-"` + // ID of the ent. + ID int64 `json:"id,omitempty"` + // CreatedAt holds the value of the "created_at" field. + CreatedAt time.Time `json:"created_at,omitempty"` + // UpdatedAt holds the value of the "updated_at" field. + UpdatedAt time.Time `json:"updated_at,omitempty"` + // Name holds the value of the "name" field. + Name string `json:"name,omitempty"` + // Provider holds the value of the "provider" field. + Provider channelmonitorrequesttemplate.Provider `json:"provider,omitempty"` + // Description holds the value of the "description" field. + Description string `json:"description,omitempty"` + // ExtraHeaders holds the value of the "extra_headers" field. + ExtraHeaders map[string]string `json:"extra_headers,omitempty"` + // BodyOverrideMode holds the value of the "body_override_mode" field. + BodyOverrideMode string `json:"body_override_mode,omitempty"` + // BodyOverride holds the value of the "body_override" field. + BodyOverride map[string]interface{} `json:"body_override,omitempty"` + // Edges holds the relations/edges for other nodes in the graph. + // The values are being populated by the ChannelMonitorRequestTemplateQuery when eager-loading is set. + Edges ChannelMonitorRequestTemplateEdges `json:"edges"` + selectValues sql.SelectValues +} + +// ChannelMonitorRequestTemplateEdges holds the relations/edges for other nodes in the graph. +type ChannelMonitorRequestTemplateEdges struct { + // Monitors holds the value of the monitors edge. + Monitors []*ChannelMonitor `json:"monitors,omitempty"` + // loadedTypes holds the information for reporting if a + // type was loaded (or requested) in eager-loading or not. + loadedTypes [1]bool +} + +// MonitorsOrErr returns the Monitors value or an error if the edge +// was not loaded in eager-loading. +func (e ChannelMonitorRequestTemplateEdges) MonitorsOrErr() ([]*ChannelMonitor, error) { + if e.loadedTypes[0] { + return e.Monitors, nil + } + return nil, &NotLoadedError{edge: "monitors"} +} + +// scanValues returns the types for scanning values from sql.Rows. +func (*ChannelMonitorRequestTemplate) scanValues(columns []string) ([]any, error) { + values := make([]any, len(columns)) + for i := range columns { + switch columns[i] { + case channelmonitorrequesttemplate.FieldExtraHeaders, channelmonitorrequesttemplate.FieldBodyOverride: + values[i] = new([]byte) + case channelmonitorrequesttemplate.FieldID: + values[i] = new(sql.NullInt64) + case channelmonitorrequesttemplate.FieldName, channelmonitorrequesttemplate.FieldProvider, channelmonitorrequesttemplate.FieldDescription, channelmonitorrequesttemplate.FieldBodyOverrideMode: + values[i] = new(sql.NullString) + case channelmonitorrequesttemplate.FieldCreatedAt, channelmonitorrequesttemplate.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 ChannelMonitorRequestTemplate fields. +func (_m *ChannelMonitorRequestTemplate) 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 channelmonitorrequesttemplate.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 channelmonitorrequesttemplate.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 channelmonitorrequesttemplate.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 + } + case channelmonitorrequesttemplate.FieldName: + if value, ok := values[i].(*sql.NullString); !ok { + return fmt.Errorf("unexpected type %T for field name", values[i]) + } else if value.Valid { + _m.Name = value.String + } + case channelmonitorrequesttemplate.FieldProvider: + if value, ok := values[i].(*sql.NullString); !ok { + return fmt.Errorf("unexpected type %T for field provider", values[i]) + } else if value.Valid { + _m.Provider = channelmonitorrequesttemplate.Provider(value.String) + } + case channelmonitorrequesttemplate.FieldDescription: + if value, ok := values[i].(*sql.NullString); !ok { + return fmt.Errorf("unexpected type %T for field description", values[i]) + } else if value.Valid { + _m.Description = value.String + } + case channelmonitorrequesttemplate.FieldExtraHeaders: + if value, ok := values[i].(*[]byte); !ok { + return fmt.Errorf("unexpected type %T for field extra_headers", values[i]) + } else if value != nil && len(*value) > 0 { + if err := json.Unmarshal(*value, &_m.ExtraHeaders); err != nil { + return fmt.Errorf("unmarshal field extra_headers: %w", err) + } + } + case channelmonitorrequesttemplate.FieldBodyOverrideMode: + if value, ok := values[i].(*sql.NullString); !ok { + return fmt.Errorf("unexpected type %T for field body_override_mode", values[i]) + } else if value.Valid { + _m.BodyOverrideMode = value.String + } + case channelmonitorrequesttemplate.FieldBodyOverride: + if value, ok := values[i].(*[]byte); !ok { + return fmt.Errorf("unexpected type %T for field body_override", values[i]) + } else if value != nil && len(*value) > 0 { + if err := json.Unmarshal(*value, &_m.BodyOverride); err != nil { + return fmt.Errorf("unmarshal field body_override: %w", err) + } + } + default: + _m.selectValues.Set(columns[i], values[i]) + } + } + return nil +} + +// Value returns the ent.Value that was dynamically selected and assigned to the ChannelMonitorRequestTemplate. +// This includes values selected through modifiers, order, etc. +func (_m *ChannelMonitorRequestTemplate) Value(name string) (ent.Value, error) { + return _m.selectValues.Get(name) +} + +// QueryMonitors queries the "monitors" edge of the ChannelMonitorRequestTemplate entity. +func (_m *ChannelMonitorRequestTemplate) QueryMonitors() *ChannelMonitorQuery { + return NewChannelMonitorRequestTemplateClient(_m.config).QueryMonitors(_m) +} + +// Update returns a builder for updating this ChannelMonitorRequestTemplate. +// Note that you need to call ChannelMonitorRequestTemplate.Unwrap() before calling this method if this ChannelMonitorRequestTemplate +// was returned from a transaction, and the transaction was committed or rolled back. +func (_m *ChannelMonitorRequestTemplate) Update() *ChannelMonitorRequestTemplateUpdateOne { + return NewChannelMonitorRequestTemplateClient(_m.config).UpdateOne(_m) +} + +// Unwrap unwraps the ChannelMonitorRequestTemplate 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 *ChannelMonitorRequestTemplate) Unwrap() *ChannelMonitorRequestTemplate { + _tx, ok := _m.config.driver.(*txDriver) + if !ok { + panic("ent: ChannelMonitorRequestTemplate is not a transactional entity") + } + _m.config.driver = _tx.drv + return _m +} + +// String implements the fmt.Stringer. +func (_m *ChannelMonitorRequestTemplate) String() string { + var builder strings.Builder + builder.WriteString("ChannelMonitorRequestTemplate(") + builder.WriteString(fmt.Sprintf("id=%v, ", _m.ID)) + 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.WriteString(", ") + builder.WriteString("name=") + builder.WriteString(_m.Name) + builder.WriteString(", ") + builder.WriteString("provider=") + builder.WriteString(fmt.Sprintf("%v", _m.Provider)) + builder.WriteString(", ") + builder.WriteString("description=") + builder.WriteString(_m.Description) + builder.WriteString(", ") + builder.WriteString("extra_headers=") + builder.WriteString(fmt.Sprintf("%v", _m.ExtraHeaders)) + builder.WriteString(", ") + builder.WriteString("body_override_mode=") + builder.WriteString(_m.BodyOverrideMode) + builder.WriteString(", ") + builder.WriteString("body_override=") + builder.WriteString(fmt.Sprintf("%v", _m.BodyOverride)) + builder.WriteByte(')') + return builder.String() +} + +// ChannelMonitorRequestTemplates is a parsable slice of ChannelMonitorRequestTemplate. +type ChannelMonitorRequestTemplates []*ChannelMonitorRequestTemplate diff --git a/backend/ent/channelmonitorrequesttemplate/channelmonitorrequesttemplate.go b/backend/ent/channelmonitorrequesttemplate/channelmonitorrequesttemplate.go new file mode 100644 index 00000000..65b8d641 --- /dev/null +++ b/backend/ent/channelmonitorrequesttemplate/channelmonitorrequesttemplate.go @@ -0,0 +1,172 @@ +// Code generated by ent, DO NOT EDIT. + +package channelmonitorrequesttemplate + +import ( + "fmt" + "time" + + "entgo.io/ent/dialect/sql" + "entgo.io/ent/dialect/sql/sqlgraph" +) + +const ( + // Label holds the string label denoting the channelmonitorrequesttemplate type in the database. + Label = "channel_monitor_request_template" + // FieldID holds the string denoting the id field in the database. + FieldID = "id" + // FieldCreatedAt holds the string denoting the created_at field in the database. + FieldCreatedAt = "created_at" + // FieldUpdatedAt holds the string denoting the updated_at field in the database. + FieldUpdatedAt = "updated_at" + // FieldName holds the string denoting the name field in the database. + FieldName = "name" + // FieldProvider holds the string denoting the provider field in the database. + FieldProvider = "provider" + // FieldDescription holds the string denoting the description field in the database. + FieldDescription = "description" + // FieldExtraHeaders holds the string denoting the extra_headers field in the database. + FieldExtraHeaders = "extra_headers" + // FieldBodyOverrideMode holds the string denoting the body_override_mode field in the database. + FieldBodyOverrideMode = "body_override_mode" + // FieldBodyOverride holds the string denoting the body_override field in the database. + FieldBodyOverride = "body_override" + // EdgeMonitors holds the string denoting the monitors edge name in mutations. + EdgeMonitors = "monitors" + // Table holds the table name of the channelmonitorrequesttemplate in the database. + Table = "channel_monitor_request_templates" + // MonitorsTable is the table that holds the monitors relation/edge. + MonitorsTable = "channel_monitors" + // MonitorsInverseTable is the table name for the ChannelMonitor entity. + // It exists in this package in order to avoid circular dependency with the "channelmonitor" package. + MonitorsInverseTable = "channel_monitors" + // MonitorsColumn is the table column denoting the monitors relation/edge. + MonitorsColumn = "template_id" +) + +// Columns holds all SQL columns for channelmonitorrequesttemplate fields. +var Columns = []string{ + FieldID, + FieldCreatedAt, + FieldUpdatedAt, + FieldName, + FieldProvider, + FieldDescription, + FieldExtraHeaders, + FieldBodyOverrideMode, + FieldBodyOverride, +} + +// 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 ( + // 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 + // NameValidator is a validator for the "name" field. It is called by the builders before save. + NameValidator func(string) error + // DefaultDescription holds the default value on creation for the "description" field. + DefaultDescription string + // DescriptionValidator is a validator for the "description" field. It is called by the builders before save. + DescriptionValidator func(string) error + // DefaultExtraHeaders holds the default value on creation for the "extra_headers" field. + DefaultExtraHeaders map[string]string + // DefaultBodyOverrideMode holds the default value on creation for the "body_override_mode" field. + DefaultBodyOverrideMode string + // BodyOverrideModeValidator is a validator for the "body_override_mode" field. It is called by the builders before save. + BodyOverrideModeValidator func(string) error +) + +// Provider defines the type for the "provider" enum field. +type Provider string + +// Provider values. +const ( + ProviderOpenai Provider = "openai" + ProviderAnthropic Provider = "anthropic" + ProviderGemini Provider = "gemini" +) + +func (pr Provider) String() string { + return string(pr) +} + +// ProviderValidator is a validator for the "provider" field enum values. It is called by the builders before save. +func ProviderValidator(pr Provider) error { + switch pr { + case ProviderOpenai, ProviderAnthropic, ProviderGemini: + return nil + default: + return fmt.Errorf("channelmonitorrequesttemplate: invalid enum value for provider field: %q", pr) + } +} + +// OrderOption defines the ordering options for the ChannelMonitorRequestTemplate queries. +type OrderOption func(*sql.Selector) + +// ByID orders the results by the id field. +func ByID(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldID, opts...).ToFunc() +} + +// ByCreatedAt orders the results by the created_at field. +func ByCreatedAt(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldCreatedAt, opts...).ToFunc() +} + +// ByUpdatedAt orders the results by the updated_at field. +func ByUpdatedAt(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldUpdatedAt, opts...).ToFunc() +} + +// ByName orders the results by the name field. +func ByName(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldName, opts...).ToFunc() +} + +// ByProvider orders the results by the provider field. +func ByProvider(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldProvider, opts...).ToFunc() +} + +// ByDescription orders the results by the description field. +func ByDescription(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldDescription, opts...).ToFunc() +} + +// ByBodyOverrideMode orders the results by the body_override_mode field. +func ByBodyOverrideMode(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldBodyOverrideMode, opts...).ToFunc() +} + +// ByMonitorsCount orders the results by monitors count. +func ByMonitorsCount(opts ...sql.OrderTermOption) OrderOption { + return func(s *sql.Selector) { + sqlgraph.OrderByNeighborsCount(s, newMonitorsStep(), opts...) + } +} + +// ByMonitors orders the results by monitors terms. +func ByMonitors(term sql.OrderTerm, terms ...sql.OrderTerm) OrderOption { + return func(s *sql.Selector) { + sqlgraph.OrderByNeighborTerms(s, newMonitorsStep(), append([]sql.OrderTerm{term}, terms...)...) + } +} +func newMonitorsStep() *sqlgraph.Step { + return sqlgraph.NewStep( + sqlgraph.From(Table, FieldID), + sqlgraph.To(MonitorsInverseTable, FieldID), + sqlgraph.Edge(sqlgraph.O2M, true, MonitorsTable, MonitorsColumn), + ) +} diff --git a/backend/ent/channelmonitorrequesttemplate/where.go b/backend/ent/channelmonitorrequesttemplate/where.go new file mode 100644 index 00000000..b95e5df0 --- /dev/null +++ b/backend/ent/channelmonitorrequesttemplate/where.go @@ -0,0 +1,434 @@ +// Code generated by ent, DO NOT EDIT. + +package channelmonitorrequesttemplate + +import ( + "time" + + "entgo.io/ent/dialect/sql" + "entgo.io/ent/dialect/sql/sqlgraph" + "github.com/Wei-Shaw/sub2api/ent/predicate" +) + +// ID filters vertices based on their ID field. +func ID(id int64) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldEQ(FieldID, id)) +} + +// IDEQ applies the EQ predicate on the ID field. +func IDEQ(id int64) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldEQ(FieldID, id)) +} + +// IDNEQ applies the NEQ predicate on the ID field. +func IDNEQ(id int64) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldNEQ(FieldID, id)) +} + +// IDIn applies the In predicate on the ID field. +func IDIn(ids ...int64) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldIn(FieldID, ids...)) +} + +// IDNotIn applies the NotIn predicate on the ID field. +func IDNotIn(ids ...int64) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldNotIn(FieldID, ids...)) +} + +// IDGT applies the GT predicate on the ID field. +func IDGT(id int64) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldGT(FieldID, id)) +} + +// IDGTE applies the GTE predicate on the ID field. +func IDGTE(id int64) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldGTE(FieldID, id)) +} + +// IDLT applies the LT predicate on the ID field. +func IDLT(id int64) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldLT(FieldID, id)) +} + +// IDLTE applies the LTE predicate on the ID field. +func IDLTE(id int64) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldLTE(FieldID, id)) +} + +// CreatedAt applies equality check predicate on the "created_at" field. It's identical to CreatedAtEQ. +func CreatedAt(v time.Time) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(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.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldEQ(FieldUpdatedAt, v)) +} + +// Name applies equality check predicate on the "name" field. It's identical to NameEQ. +func Name(v string) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldEQ(FieldName, v)) +} + +// Description applies equality check predicate on the "description" field. It's identical to DescriptionEQ. +func Description(v string) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldEQ(FieldDescription, v)) +} + +// BodyOverrideMode applies equality check predicate on the "body_override_mode" field. It's identical to BodyOverrideModeEQ. +func BodyOverrideMode(v string) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldEQ(FieldBodyOverrideMode, v)) +} + +// CreatedAtEQ applies the EQ predicate on the "created_at" field. +func CreatedAtEQ(v time.Time) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldEQ(FieldCreatedAt, v)) +} + +// CreatedAtNEQ applies the NEQ predicate on the "created_at" field. +func CreatedAtNEQ(v time.Time) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldNEQ(FieldCreatedAt, v)) +} + +// CreatedAtIn applies the In predicate on the "created_at" field. +func CreatedAtIn(vs ...time.Time) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldIn(FieldCreatedAt, vs...)) +} + +// CreatedAtNotIn applies the NotIn predicate on the "created_at" field. +func CreatedAtNotIn(vs ...time.Time) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldNotIn(FieldCreatedAt, vs...)) +} + +// CreatedAtGT applies the GT predicate on the "created_at" field. +func CreatedAtGT(v time.Time) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldGT(FieldCreatedAt, v)) +} + +// CreatedAtGTE applies the GTE predicate on the "created_at" field. +func CreatedAtGTE(v time.Time) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldGTE(FieldCreatedAt, v)) +} + +// CreatedAtLT applies the LT predicate on the "created_at" field. +func CreatedAtLT(v time.Time) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldLT(FieldCreatedAt, v)) +} + +// CreatedAtLTE applies the LTE predicate on the "created_at" field. +func CreatedAtLTE(v time.Time) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldLTE(FieldCreatedAt, v)) +} + +// UpdatedAtEQ applies the EQ predicate on the "updated_at" field. +func UpdatedAtEQ(v time.Time) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldEQ(FieldUpdatedAt, v)) +} + +// UpdatedAtNEQ applies the NEQ predicate on the "updated_at" field. +func UpdatedAtNEQ(v time.Time) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldNEQ(FieldUpdatedAt, v)) +} + +// UpdatedAtIn applies the In predicate on the "updated_at" field. +func UpdatedAtIn(vs ...time.Time) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldIn(FieldUpdatedAt, vs...)) +} + +// UpdatedAtNotIn applies the NotIn predicate on the "updated_at" field. +func UpdatedAtNotIn(vs ...time.Time) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldNotIn(FieldUpdatedAt, vs...)) +} + +// UpdatedAtGT applies the GT predicate on the "updated_at" field. +func UpdatedAtGT(v time.Time) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldGT(FieldUpdatedAt, v)) +} + +// UpdatedAtGTE applies the GTE predicate on the "updated_at" field. +func UpdatedAtGTE(v time.Time) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldGTE(FieldUpdatedAt, v)) +} + +// UpdatedAtLT applies the LT predicate on the "updated_at" field. +func UpdatedAtLT(v time.Time) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldLT(FieldUpdatedAt, v)) +} + +// UpdatedAtLTE applies the LTE predicate on the "updated_at" field. +func UpdatedAtLTE(v time.Time) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldLTE(FieldUpdatedAt, v)) +} + +// NameEQ applies the EQ predicate on the "name" field. +func NameEQ(v string) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldEQ(FieldName, v)) +} + +// NameNEQ applies the NEQ predicate on the "name" field. +func NameNEQ(v string) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldNEQ(FieldName, v)) +} + +// NameIn applies the In predicate on the "name" field. +func NameIn(vs ...string) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldIn(FieldName, vs...)) +} + +// NameNotIn applies the NotIn predicate on the "name" field. +func NameNotIn(vs ...string) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldNotIn(FieldName, vs...)) +} + +// NameGT applies the GT predicate on the "name" field. +func NameGT(v string) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldGT(FieldName, v)) +} + +// NameGTE applies the GTE predicate on the "name" field. +func NameGTE(v string) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldGTE(FieldName, v)) +} + +// NameLT applies the LT predicate on the "name" field. +func NameLT(v string) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldLT(FieldName, v)) +} + +// NameLTE applies the LTE predicate on the "name" field. +func NameLTE(v string) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldLTE(FieldName, v)) +} + +// NameContains applies the Contains predicate on the "name" field. +func NameContains(v string) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldContains(FieldName, v)) +} + +// NameHasPrefix applies the HasPrefix predicate on the "name" field. +func NameHasPrefix(v string) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldHasPrefix(FieldName, v)) +} + +// NameHasSuffix applies the HasSuffix predicate on the "name" field. +func NameHasSuffix(v string) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldHasSuffix(FieldName, v)) +} + +// NameEqualFold applies the EqualFold predicate on the "name" field. +func NameEqualFold(v string) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldEqualFold(FieldName, v)) +} + +// NameContainsFold applies the ContainsFold predicate on the "name" field. +func NameContainsFold(v string) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldContainsFold(FieldName, v)) +} + +// ProviderEQ applies the EQ predicate on the "provider" field. +func ProviderEQ(v Provider) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldEQ(FieldProvider, v)) +} + +// ProviderNEQ applies the NEQ predicate on the "provider" field. +func ProviderNEQ(v Provider) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldNEQ(FieldProvider, v)) +} + +// ProviderIn applies the In predicate on the "provider" field. +func ProviderIn(vs ...Provider) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldIn(FieldProvider, vs...)) +} + +// ProviderNotIn applies the NotIn predicate on the "provider" field. +func ProviderNotIn(vs ...Provider) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldNotIn(FieldProvider, vs...)) +} + +// DescriptionEQ applies the EQ predicate on the "description" field. +func DescriptionEQ(v string) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldEQ(FieldDescription, v)) +} + +// DescriptionNEQ applies the NEQ predicate on the "description" field. +func DescriptionNEQ(v string) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldNEQ(FieldDescription, v)) +} + +// DescriptionIn applies the In predicate on the "description" field. +func DescriptionIn(vs ...string) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldIn(FieldDescription, vs...)) +} + +// DescriptionNotIn applies the NotIn predicate on the "description" field. +func DescriptionNotIn(vs ...string) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldNotIn(FieldDescription, vs...)) +} + +// DescriptionGT applies the GT predicate on the "description" field. +func DescriptionGT(v string) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldGT(FieldDescription, v)) +} + +// DescriptionGTE applies the GTE predicate on the "description" field. +func DescriptionGTE(v string) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldGTE(FieldDescription, v)) +} + +// DescriptionLT applies the LT predicate on the "description" field. +func DescriptionLT(v string) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldLT(FieldDescription, v)) +} + +// DescriptionLTE applies the LTE predicate on the "description" field. +func DescriptionLTE(v string) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldLTE(FieldDescription, v)) +} + +// DescriptionContains applies the Contains predicate on the "description" field. +func DescriptionContains(v string) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldContains(FieldDescription, v)) +} + +// DescriptionHasPrefix applies the HasPrefix predicate on the "description" field. +func DescriptionHasPrefix(v string) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldHasPrefix(FieldDescription, v)) +} + +// DescriptionHasSuffix applies the HasSuffix predicate on the "description" field. +func DescriptionHasSuffix(v string) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldHasSuffix(FieldDescription, v)) +} + +// DescriptionIsNil applies the IsNil predicate on the "description" field. +func DescriptionIsNil() predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldIsNull(FieldDescription)) +} + +// DescriptionNotNil applies the NotNil predicate on the "description" field. +func DescriptionNotNil() predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldNotNull(FieldDescription)) +} + +// DescriptionEqualFold applies the EqualFold predicate on the "description" field. +func DescriptionEqualFold(v string) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldEqualFold(FieldDescription, v)) +} + +// DescriptionContainsFold applies the ContainsFold predicate on the "description" field. +func DescriptionContainsFold(v string) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldContainsFold(FieldDescription, v)) +} + +// BodyOverrideModeEQ applies the EQ predicate on the "body_override_mode" field. +func BodyOverrideModeEQ(v string) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldEQ(FieldBodyOverrideMode, v)) +} + +// BodyOverrideModeNEQ applies the NEQ predicate on the "body_override_mode" field. +func BodyOverrideModeNEQ(v string) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldNEQ(FieldBodyOverrideMode, v)) +} + +// BodyOverrideModeIn applies the In predicate on the "body_override_mode" field. +func BodyOverrideModeIn(vs ...string) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldIn(FieldBodyOverrideMode, vs...)) +} + +// BodyOverrideModeNotIn applies the NotIn predicate on the "body_override_mode" field. +func BodyOverrideModeNotIn(vs ...string) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldNotIn(FieldBodyOverrideMode, vs...)) +} + +// BodyOverrideModeGT applies the GT predicate on the "body_override_mode" field. +func BodyOverrideModeGT(v string) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldGT(FieldBodyOverrideMode, v)) +} + +// BodyOverrideModeGTE applies the GTE predicate on the "body_override_mode" field. +func BodyOverrideModeGTE(v string) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldGTE(FieldBodyOverrideMode, v)) +} + +// BodyOverrideModeLT applies the LT predicate on the "body_override_mode" field. +func BodyOverrideModeLT(v string) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldLT(FieldBodyOverrideMode, v)) +} + +// BodyOverrideModeLTE applies the LTE predicate on the "body_override_mode" field. +func BodyOverrideModeLTE(v string) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldLTE(FieldBodyOverrideMode, v)) +} + +// BodyOverrideModeContains applies the Contains predicate on the "body_override_mode" field. +func BodyOverrideModeContains(v string) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldContains(FieldBodyOverrideMode, v)) +} + +// BodyOverrideModeHasPrefix applies the HasPrefix predicate on the "body_override_mode" field. +func BodyOverrideModeHasPrefix(v string) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldHasPrefix(FieldBodyOverrideMode, v)) +} + +// BodyOverrideModeHasSuffix applies the HasSuffix predicate on the "body_override_mode" field. +func BodyOverrideModeHasSuffix(v string) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldHasSuffix(FieldBodyOverrideMode, v)) +} + +// BodyOverrideModeEqualFold applies the EqualFold predicate on the "body_override_mode" field. +func BodyOverrideModeEqualFold(v string) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldEqualFold(FieldBodyOverrideMode, v)) +} + +// BodyOverrideModeContainsFold applies the ContainsFold predicate on the "body_override_mode" field. +func BodyOverrideModeContainsFold(v string) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldContainsFold(FieldBodyOverrideMode, v)) +} + +// BodyOverrideIsNil applies the IsNil predicate on the "body_override" field. +func BodyOverrideIsNil() predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldIsNull(FieldBodyOverride)) +} + +// BodyOverrideNotNil applies the NotNil predicate on the "body_override" field. +func BodyOverrideNotNil() predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.FieldNotNull(FieldBodyOverride)) +} + +// HasMonitors applies the HasEdge predicate on the "monitors" edge. +func HasMonitors() predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(func(s *sql.Selector) { + step := sqlgraph.NewStep( + sqlgraph.From(Table, FieldID), + sqlgraph.Edge(sqlgraph.O2M, true, MonitorsTable, MonitorsColumn), + ) + sqlgraph.HasNeighbors(s, step) + }) +} + +// HasMonitorsWith applies the HasEdge predicate on the "monitors" edge with a given conditions (other predicates). +func HasMonitorsWith(preds ...predicate.ChannelMonitor) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(func(s *sql.Selector) { + step := newMonitorsStep() + sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) { + for _, p := range preds { + p(s) + } + }) + }) +} + +// And groups predicates with the AND operator between them. +func And(predicates ...predicate.ChannelMonitorRequestTemplate) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.AndPredicates(predicates...)) +} + +// Or groups predicates with the OR operator between them. +func Or(predicates ...predicate.ChannelMonitorRequestTemplate) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.OrPredicates(predicates...)) +} + +// Not applies the not operator on the given predicate. +func Not(p predicate.ChannelMonitorRequestTemplate) predicate.ChannelMonitorRequestTemplate { + return predicate.ChannelMonitorRequestTemplate(sql.NotPredicates(p)) +} diff --git a/backend/ent/channelmonitorrequesttemplate_create.go b/backend/ent/channelmonitorrequesttemplate_create.go new file mode 100644 index 00000000..1ba842cd --- /dev/null +++ b/backend/ent/channelmonitorrequesttemplate_create.go @@ -0,0 +1,942 @@ +// 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/channelmonitor" + "github.com/Wei-Shaw/sub2api/ent/channelmonitorrequesttemplate" +) + +// ChannelMonitorRequestTemplateCreate is the builder for creating a ChannelMonitorRequestTemplate entity. +type ChannelMonitorRequestTemplateCreate struct { + config + mutation *ChannelMonitorRequestTemplateMutation + hooks []Hook + conflict []sql.ConflictOption +} + +// SetCreatedAt sets the "created_at" field. +func (_c *ChannelMonitorRequestTemplateCreate) SetCreatedAt(v time.Time) *ChannelMonitorRequestTemplateCreate { + _c.mutation.SetCreatedAt(v) + return _c +} + +// SetNillableCreatedAt sets the "created_at" field if the given value is not nil. +func (_c *ChannelMonitorRequestTemplateCreate) SetNillableCreatedAt(v *time.Time) *ChannelMonitorRequestTemplateCreate { + if v != nil { + _c.SetCreatedAt(*v) + } + return _c +} + +// SetUpdatedAt sets the "updated_at" field. +func (_c *ChannelMonitorRequestTemplateCreate) SetUpdatedAt(v time.Time) *ChannelMonitorRequestTemplateCreate { + _c.mutation.SetUpdatedAt(v) + return _c +} + +// SetNillableUpdatedAt sets the "updated_at" field if the given value is not nil. +func (_c *ChannelMonitorRequestTemplateCreate) SetNillableUpdatedAt(v *time.Time) *ChannelMonitorRequestTemplateCreate { + if v != nil { + _c.SetUpdatedAt(*v) + } + return _c +} + +// SetName sets the "name" field. +func (_c *ChannelMonitorRequestTemplateCreate) SetName(v string) *ChannelMonitorRequestTemplateCreate { + _c.mutation.SetName(v) + return _c +} + +// SetProvider sets the "provider" field. +func (_c *ChannelMonitorRequestTemplateCreate) SetProvider(v channelmonitorrequesttemplate.Provider) *ChannelMonitorRequestTemplateCreate { + _c.mutation.SetProvider(v) + return _c +} + +// SetDescription sets the "description" field. +func (_c *ChannelMonitorRequestTemplateCreate) SetDescription(v string) *ChannelMonitorRequestTemplateCreate { + _c.mutation.SetDescription(v) + return _c +} + +// SetNillableDescription sets the "description" field if the given value is not nil. +func (_c *ChannelMonitorRequestTemplateCreate) SetNillableDescription(v *string) *ChannelMonitorRequestTemplateCreate { + if v != nil { + _c.SetDescription(*v) + } + return _c +} + +// SetExtraHeaders sets the "extra_headers" field. +func (_c *ChannelMonitorRequestTemplateCreate) SetExtraHeaders(v map[string]string) *ChannelMonitorRequestTemplateCreate { + _c.mutation.SetExtraHeaders(v) + return _c +} + +// SetBodyOverrideMode sets the "body_override_mode" field. +func (_c *ChannelMonitorRequestTemplateCreate) SetBodyOverrideMode(v string) *ChannelMonitorRequestTemplateCreate { + _c.mutation.SetBodyOverrideMode(v) + return _c +} + +// SetNillableBodyOverrideMode sets the "body_override_mode" field if the given value is not nil. +func (_c *ChannelMonitorRequestTemplateCreate) SetNillableBodyOverrideMode(v *string) *ChannelMonitorRequestTemplateCreate { + if v != nil { + _c.SetBodyOverrideMode(*v) + } + return _c +} + +// SetBodyOverride sets the "body_override" field. +func (_c *ChannelMonitorRequestTemplateCreate) SetBodyOverride(v map[string]interface{}) *ChannelMonitorRequestTemplateCreate { + _c.mutation.SetBodyOverride(v) + return _c +} + +// AddMonitorIDs adds the "monitors" edge to the ChannelMonitor entity by IDs. +func (_c *ChannelMonitorRequestTemplateCreate) AddMonitorIDs(ids ...int64) *ChannelMonitorRequestTemplateCreate { + _c.mutation.AddMonitorIDs(ids...) + return _c +} + +// AddMonitors adds the "monitors" edges to the ChannelMonitor entity. +func (_c *ChannelMonitorRequestTemplateCreate) AddMonitors(v ...*ChannelMonitor) *ChannelMonitorRequestTemplateCreate { + ids := make([]int64, len(v)) + for i := range v { + ids[i] = v[i].ID + } + return _c.AddMonitorIDs(ids...) +} + +// Mutation returns the ChannelMonitorRequestTemplateMutation object of the builder. +func (_c *ChannelMonitorRequestTemplateCreate) Mutation() *ChannelMonitorRequestTemplateMutation { + return _c.mutation +} + +// Save creates the ChannelMonitorRequestTemplate in the database. +func (_c *ChannelMonitorRequestTemplateCreate) Save(ctx context.Context) (*ChannelMonitorRequestTemplate, error) { + _c.defaults() + return withHooks(ctx, _c.sqlSave, _c.mutation, _c.hooks) +} + +// SaveX calls Save and panics if Save returns an error. +func (_c *ChannelMonitorRequestTemplateCreate) SaveX(ctx context.Context) *ChannelMonitorRequestTemplate { + v, err := _c.Save(ctx) + if err != nil { + panic(err) + } + return v +} + +// Exec executes the query. +func (_c *ChannelMonitorRequestTemplateCreate) Exec(ctx context.Context) error { + _, err := _c.Save(ctx) + return err +} + +// ExecX is like Exec, but panics if an error occurs. +func (_c *ChannelMonitorRequestTemplateCreate) 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 *ChannelMonitorRequestTemplateCreate) defaults() { + if _, ok := _c.mutation.CreatedAt(); !ok { + v := channelmonitorrequesttemplate.DefaultCreatedAt() + _c.mutation.SetCreatedAt(v) + } + if _, ok := _c.mutation.UpdatedAt(); !ok { + v := channelmonitorrequesttemplate.DefaultUpdatedAt() + _c.mutation.SetUpdatedAt(v) + } + if _, ok := _c.mutation.Description(); !ok { + v := channelmonitorrequesttemplate.DefaultDescription + _c.mutation.SetDescription(v) + } + if _, ok := _c.mutation.ExtraHeaders(); !ok { + v := channelmonitorrequesttemplate.DefaultExtraHeaders + _c.mutation.SetExtraHeaders(v) + } + if _, ok := _c.mutation.BodyOverrideMode(); !ok { + v := channelmonitorrequesttemplate.DefaultBodyOverrideMode + _c.mutation.SetBodyOverrideMode(v) + } +} + +// check runs all checks and user-defined validators on the builder. +func (_c *ChannelMonitorRequestTemplateCreate) check() error { + if _, ok := _c.mutation.CreatedAt(); !ok { + return &ValidationError{Name: "created_at", err: errors.New(`ent: missing required field "ChannelMonitorRequestTemplate.created_at"`)} + } + if _, ok := _c.mutation.UpdatedAt(); !ok { + return &ValidationError{Name: "updated_at", err: errors.New(`ent: missing required field "ChannelMonitorRequestTemplate.updated_at"`)} + } + if _, ok := _c.mutation.Name(); !ok { + return &ValidationError{Name: "name", err: errors.New(`ent: missing required field "ChannelMonitorRequestTemplate.name"`)} + } + if v, ok := _c.mutation.Name(); ok { + if err := channelmonitorrequesttemplate.NameValidator(v); err != nil { + return &ValidationError{Name: "name", err: fmt.Errorf(`ent: validator failed for field "ChannelMonitorRequestTemplate.name": %w`, err)} + } + } + if _, ok := _c.mutation.Provider(); !ok { + return &ValidationError{Name: "provider", err: errors.New(`ent: missing required field "ChannelMonitorRequestTemplate.provider"`)} + } + if v, ok := _c.mutation.Provider(); ok { + if err := channelmonitorrequesttemplate.ProviderValidator(v); err != nil { + return &ValidationError{Name: "provider", err: fmt.Errorf(`ent: validator failed for field "ChannelMonitorRequestTemplate.provider": %w`, err)} + } + } + if v, ok := _c.mutation.Description(); ok { + if err := channelmonitorrequesttemplate.DescriptionValidator(v); err != nil { + return &ValidationError{Name: "description", err: fmt.Errorf(`ent: validator failed for field "ChannelMonitorRequestTemplate.description": %w`, err)} + } + } + if _, ok := _c.mutation.ExtraHeaders(); !ok { + return &ValidationError{Name: "extra_headers", err: errors.New(`ent: missing required field "ChannelMonitorRequestTemplate.extra_headers"`)} + } + if _, ok := _c.mutation.BodyOverrideMode(); !ok { + return &ValidationError{Name: "body_override_mode", err: errors.New(`ent: missing required field "ChannelMonitorRequestTemplate.body_override_mode"`)} + } + if v, ok := _c.mutation.BodyOverrideMode(); ok { + if err := channelmonitorrequesttemplate.BodyOverrideModeValidator(v); err != nil { + return &ValidationError{Name: "body_override_mode", err: fmt.Errorf(`ent: validator failed for field "ChannelMonitorRequestTemplate.body_override_mode": %w`, err)} + } + } + return nil +} + +func (_c *ChannelMonitorRequestTemplateCreate) sqlSave(ctx context.Context) (*ChannelMonitorRequestTemplate, 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 *ChannelMonitorRequestTemplateCreate) createSpec() (*ChannelMonitorRequestTemplate, *sqlgraph.CreateSpec) { + var ( + _node = &ChannelMonitorRequestTemplate{config: _c.config} + _spec = sqlgraph.NewCreateSpec(channelmonitorrequesttemplate.Table, sqlgraph.NewFieldSpec(channelmonitorrequesttemplate.FieldID, field.TypeInt64)) + ) + _spec.OnConflict = _c.conflict + if value, ok := _c.mutation.CreatedAt(); ok { + _spec.SetField(channelmonitorrequesttemplate.FieldCreatedAt, field.TypeTime, value) + _node.CreatedAt = value + } + if value, ok := _c.mutation.UpdatedAt(); ok { + _spec.SetField(channelmonitorrequesttemplate.FieldUpdatedAt, field.TypeTime, value) + _node.UpdatedAt = value + } + if value, ok := _c.mutation.Name(); ok { + _spec.SetField(channelmonitorrequesttemplate.FieldName, field.TypeString, value) + _node.Name = value + } + if value, ok := _c.mutation.Provider(); ok { + _spec.SetField(channelmonitorrequesttemplate.FieldProvider, field.TypeEnum, value) + _node.Provider = value + } + if value, ok := _c.mutation.Description(); ok { + _spec.SetField(channelmonitorrequesttemplate.FieldDescription, field.TypeString, value) + _node.Description = value + } + if value, ok := _c.mutation.ExtraHeaders(); ok { + _spec.SetField(channelmonitorrequesttemplate.FieldExtraHeaders, field.TypeJSON, value) + _node.ExtraHeaders = value + } + if value, ok := _c.mutation.BodyOverrideMode(); ok { + _spec.SetField(channelmonitorrequesttemplate.FieldBodyOverrideMode, field.TypeString, value) + _node.BodyOverrideMode = value + } + if value, ok := _c.mutation.BodyOverride(); ok { + _spec.SetField(channelmonitorrequesttemplate.FieldBodyOverride, field.TypeJSON, value) + _node.BodyOverride = value + } + if nodes := _c.mutation.MonitorsIDs(); len(nodes) > 0 { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.O2M, + Inverse: true, + Table: channelmonitorrequesttemplate.MonitorsTable, + Columns: []string{channelmonitorrequesttemplate.MonitorsColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(channelmonitor.FieldID, field.TypeInt64), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _spec.Edges = append(_spec.Edges, edge) + } + return _node, _spec +} + +// OnConflict allows configuring the `ON CONFLICT` / `ON DUPLICATE KEY` clause +// of the `INSERT` statement. For example: +// +// client.ChannelMonitorRequestTemplate.Create(). +// SetCreatedAt(v). +// OnConflict( +// // Update the row with the new values +// // the was proposed for insertion. +// sql.ResolveWithNewValues(), +// ). +// // Override some of the fields with custom +// // update values. +// Update(func(u *ent.ChannelMonitorRequestTemplateUpsert) { +// SetCreatedAt(v+v). +// }). +// Exec(ctx) +func (_c *ChannelMonitorRequestTemplateCreate) OnConflict(opts ...sql.ConflictOption) *ChannelMonitorRequestTemplateUpsertOne { + _c.conflict = opts + return &ChannelMonitorRequestTemplateUpsertOne{ + create: _c, + } +} + +// OnConflictColumns calls `OnConflict` and configures the columns +// as conflict target. Using this option is equivalent to using: +// +// client.ChannelMonitorRequestTemplate.Create(). +// OnConflict(sql.ConflictColumns(columns...)). +// Exec(ctx) +func (_c *ChannelMonitorRequestTemplateCreate) OnConflictColumns(columns ...string) *ChannelMonitorRequestTemplateUpsertOne { + _c.conflict = append(_c.conflict, sql.ConflictColumns(columns...)) + return &ChannelMonitorRequestTemplateUpsertOne{ + create: _c, + } +} + +type ( + // ChannelMonitorRequestTemplateUpsertOne is the builder for "upsert"-ing + // one ChannelMonitorRequestTemplate node. + ChannelMonitorRequestTemplateUpsertOne struct { + create *ChannelMonitorRequestTemplateCreate + } + + // ChannelMonitorRequestTemplateUpsert is the "OnConflict" setter. + ChannelMonitorRequestTemplateUpsert struct { + *sql.UpdateSet + } +) + +// SetUpdatedAt sets the "updated_at" field. +func (u *ChannelMonitorRequestTemplateUpsert) SetUpdatedAt(v time.Time) *ChannelMonitorRequestTemplateUpsert { + u.Set(channelmonitorrequesttemplate.FieldUpdatedAt, v) + return u +} + +// UpdateUpdatedAt sets the "updated_at" field to the value that was provided on create. +func (u *ChannelMonitorRequestTemplateUpsert) UpdateUpdatedAt() *ChannelMonitorRequestTemplateUpsert { + u.SetExcluded(channelmonitorrequesttemplate.FieldUpdatedAt) + return u +} + +// SetName sets the "name" field. +func (u *ChannelMonitorRequestTemplateUpsert) SetName(v string) *ChannelMonitorRequestTemplateUpsert { + u.Set(channelmonitorrequesttemplate.FieldName, v) + return u +} + +// UpdateName sets the "name" field to the value that was provided on create. +func (u *ChannelMonitorRequestTemplateUpsert) UpdateName() *ChannelMonitorRequestTemplateUpsert { + u.SetExcluded(channelmonitorrequesttemplate.FieldName) + return u +} + +// SetProvider sets the "provider" field. +func (u *ChannelMonitorRequestTemplateUpsert) SetProvider(v channelmonitorrequesttemplate.Provider) *ChannelMonitorRequestTemplateUpsert { + u.Set(channelmonitorrequesttemplate.FieldProvider, v) + return u +} + +// UpdateProvider sets the "provider" field to the value that was provided on create. +func (u *ChannelMonitorRequestTemplateUpsert) UpdateProvider() *ChannelMonitorRequestTemplateUpsert { + u.SetExcluded(channelmonitorrequesttemplate.FieldProvider) + return u +} + +// SetDescription sets the "description" field. +func (u *ChannelMonitorRequestTemplateUpsert) SetDescription(v string) *ChannelMonitorRequestTemplateUpsert { + u.Set(channelmonitorrequesttemplate.FieldDescription, v) + return u +} + +// UpdateDescription sets the "description" field to the value that was provided on create. +func (u *ChannelMonitorRequestTemplateUpsert) UpdateDescription() *ChannelMonitorRequestTemplateUpsert { + u.SetExcluded(channelmonitorrequesttemplate.FieldDescription) + return u +} + +// ClearDescription clears the value of the "description" field. +func (u *ChannelMonitorRequestTemplateUpsert) ClearDescription() *ChannelMonitorRequestTemplateUpsert { + u.SetNull(channelmonitorrequesttemplate.FieldDescription) + return u +} + +// SetExtraHeaders sets the "extra_headers" field. +func (u *ChannelMonitorRequestTemplateUpsert) SetExtraHeaders(v map[string]string) *ChannelMonitorRequestTemplateUpsert { + u.Set(channelmonitorrequesttemplate.FieldExtraHeaders, v) + return u +} + +// UpdateExtraHeaders sets the "extra_headers" field to the value that was provided on create. +func (u *ChannelMonitorRequestTemplateUpsert) UpdateExtraHeaders() *ChannelMonitorRequestTemplateUpsert { + u.SetExcluded(channelmonitorrequesttemplate.FieldExtraHeaders) + return u +} + +// SetBodyOverrideMode sets the "body_override_mode" field. +func (u *ChannelMonitorRequestTemplateUpsert) SetBodyOverrideMode(v string) *ChannelMonitorRequestTemplateUpsert { + u.Set(channelmonitorrequesttemplate.FieldBodyOverrideMode, v) + return u +} + +// UpdateBodyOverrideMode sets the "body_override_mode" field to the value that was provided on create. +func (u *ChannelMonitorRequestTemplateUpsert) UpdateBodyOverrideMode() *ChannelMonitorRequestTemplateUpsert { + u.SetExcluded(channelmonitorrequesttemplate.FieldBodyOverrideMode) + return u +} + +// SetBodyOverride sets the "body_override" field. +func (u *ChannelMonitorRequestTemplateUpsert) SetBodyOverride(v map[string]interface{}) *ChannelMonitorRequestTemplateUpsert { + u.Set(channelmonitorrequesttemplate.FieldBodyOverride, v) + return u +} + +// UpdateBodyOverride sets the "body_override" field to the value that was provided on create. +func (u *ChannelMonitorRequestTemplateUpsert) UpdateBodyOverride() *ChannelMonitorRequestTemplateUpsert { + u.SetExcluded(channelmonitorrequesttemplate.FieldBodyOverride) + return u +} + +// ClearBodyOverride clears the value of the "body_override" field. +func (u *ChannelMonitorRequestTemplateUpsert) ClearBodyOverride() *ChannelMonitorRequestTemplateUpsert { + u.SetNull(channelmonitorrequesttemplate.FieldBodyOverride) + return u +} + +// UpdateNewValues updates the mutable fields using the new values that were set on create. +// Using this option is equivalent to using: +// +// client.ChannelMonitorRequestTemplate.Create(). +// OnConflict( +// sql.ResolveWithNewValues(), +// ). +// Exec(ctx) +func (u *ChannelMonitorRequestTemplateUpsertOne) UpdateNewValues() *ChannelMonitorRequestTemplateUpsertOne { + 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(channelmonitorrequesttemplate.FieldCreatedAt) + } + })) + return u +} + +// Ignore sets each column to itself in case of conflict. +// Using this option is equivalent to using: +// +// client.ChannelMonitorRequestTemplate.Create(). +// OnConflict(sql.ResolveWithIgnore()). +// Exec(ctx) +func (u *ChannelMonitorRequestTemplateUpsertOne) Ignore() *ChannelMonitorRequestTemplateUpsertOne { + 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 *ChannelMonitorRequestTemplateUpsertOne) DoNothing() *ChannelMonitorRequestTemplateUpsertOne { + u.create.conflict = append(u.create.conflict, sql.DoNothing()) + return u +} + +// Update allows overriding fields `UPDATE` values. See the ChannelMonitorRequestTemplateCreate.OnConflict +// documentation for more info. +func (u *ChannelMonitorRequestTemplateUpsertOne) Update(set func(*ChannelMonitorRequestTemplateUpsert)) *ChannelMonitorRequestTemplateUpsertOne { + u.create.conflict = append(u.create.conflict, sql.ResolveWith(func(update *sql.UpdateSet) { + set(&ChannelMonitorRequestTemplateUpsert{UpdateSet: update}) + })) + return u +} + +// SetUpdatedAt sets the "updated_at" field. +func (u *ChannelMonitorRequestTemplateUpsertOne) SetUpdatedAt(v time.Time) *ChannelMonitorRequestTemplateUpsertOne { + return u.Update(func(s *ChannelMonitorRequestTemplateUpsert) { + s.SetUpdatedAt(v) + }) +} + +// UpdateUpdatedAt sets the "updated_at" field to the value that was provided on create. +func (u *ChannelMonitorRequestTemplateUpsertOne) UpdateUpdatedAt() *ChannelMonitorRequestTemplateUpsertOne { + return u.Update(func(s *ChannelMonitorRequestTemplateUpsert) { + s.UpdateUpdatedAt() + }) +} + +// SetName sets the "name" field. +func (u *ChannelMonitorRequestTemplateUpsertOne) SetName(v string) *ChannelMonitorRequestTemplateUpsertOne { + return u.Update(func(s *ChannelMonitorRequestTemplateUpsert) { + s.SetName(v) + }) +} + +// UpdateName sets the "name" field to the value that was provided on create. +func (u *ChannelMonitorRequestTemplateUpsertOne) UpdateName() *ChannelMonitorRequestTemplateUpsertOne { + return u.Update(func(s *ChannelMonitorRequestTemplateUpsert) { + s.UpdateName() + }) +} + +// SetProvider sets the "provider" field. +func (u *ChannelMonitorRequestTemplateUpsertOne) SetProvider(v channelmonitorrequesttemplate.Provider) *ChannelMonitorRequestTemplateUpsertOne { + return u.Update(func(s *ChannelMonitorRequestTemplateUpsert) { + s.SetProvider(v) + }) +} + +// UpdateProvider sets the "provider" field to the value that was provided on create. +func (u *ChannelMonitorRequestTemplateUpsertOne) UpdateProvider() *ChannelMonitorRequestTemplateUpsertOne { + return u.Update(func(s *ChannelMonitorRequestTemplateUpsert) { + s.UpdateProvider() + }) +} + +// SetDescription sets the "description" field. +func (u *ChannelMonitorRequestTemplateUpsertOne) SetDescription(v string) *ChannelMonitorRequestTemplateUpsertOne { + return u.Update(func(s *ChannelMonitorRequestTemplateUpsert) { + s.SetDescription(v) + }) +} + +// UpdateDescription sets the "description" field to the value that was provided on create. +func (u *ChannelMonitorRequestTemplateUpsertOne) UpdateDescription() *ChannelMonitorRequestTemplateUpsertOne { + return u.Update(func(s *ChannelMonitorRequestTemplateUpsert) { + s.UpdateDescription() + }) +} + +// ClearDescription clears the value of the "description" field. +func (u *ChannelMonitorRequestTemplateUpsertOne) ClearDescription() *ChannelMonitorRequestTemplateUpsertOne { + return u.Update(func(s *ChannelMonitorRequestTemplateUpsert) { + s.ClearDescription() + }) +} + +// SetExtraHeaders sets the "extra_headers" field. +func (u *ChannelMonitorRequestTemplateUpsertOne) SetExtraHeaders(v map[string]string) *ChannelMonitorRequestTemplateUpsertOne { + return u.Update(func(s *ChannelMonitorRequestTemplateUpsert) { + s.SetExtraHeaders(v) + }) +} + +// UpdateExtraHeaders sets the "extra_headers" field to the value that was provided on create. +func (u *ChannelMonitorRequestTemplateUpsertOne) UpdateExtraHeaders() *ChannelMonitorRequestTemplateUpsertOne { + return u.Update(func(s *ChannelMonitorRequestTemplateUpsert) { + s.UpdateExtraHeaders() + }) +} + +// SetBodyOverrideMode sets the "body_override_mode" field. +func (u *ChannelMonitorRequestTemplateUpsertOne) SetBodyOverrideMode(v string) *ChannelMonitorRequestTemplateUpsertOne { + return u.Update(func(s *ChannelMonitorRequestTemplateUpsert) { + s.SetBodyOverrideMode(v) + }) +} + +// UpdateBodyOverrideMode sets the "body_override_mode" field to the value that was provided on create. +func (u *ChannelMonitorRequestTemplateUpsertOne) UpdateBodyOverrideMode() *ChannelMonitorRequestTemplateUpsertOne { + return u.Update(func(s *ChannelMonitorRequestTemplateUpsert) { + s.UpdateBodyOverrideMode() + }) +} + +// SetBodyOverride sets the "body_override" field. +func (u *ChannelMonitorRequestTemplateUpsertOne) SetBodyOverride(v map[string]interface{}) *ChannelMonitorRequestTemplateUpsertOne { + return u.Update(func(s *ChannelMonitorRequestTemplateUpsert) { + s.SetBodyOverride(v) + }) +} + +// UpdateBodyOverride sets the "body_override" field to the value that was provided on create. +func (u *ChannelMonitorRequestTemplateUpsertOne) UpdateBodyOverride() *ChannelMonitorRequestTemplateUpsertOne { + return u.Update(func(s *ChannelMonitorRequestTemplateUpsert) { + s.UpdateBodyOverride() + }) +} + +// ClearBodyOverride clears the value of the "body_override" field. +func (u *ChannelMonitorRequestTemplateUpsertOne) ClearBodyOverride() *ChannelMonitorRequestTemplateUpsertOne { + return u.Update(func(s *ChannelMonitorRequestTemplateUpsert) { + s.ClearBodyOverride() + }) +} + +// Exec executes the query. +func (u *ChannelMonitorRequestTemplateUpsertOne) Exec(ctx context.Context) error { + if len(u.create.conflict) == 0 { + return errors.New("ent: missing options for ChannelMonitorRequestTemplateCreate.OnConflict") + } + return u.create.Exec(ctx) +} + +// ExecX is like Exec, but panics if an error occurs. +func (u *ChannelMonitorRequestTemplateUpsertOne) 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 *ChannelMonitorRequestTemplateUpsertOne) 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 *ChannelMonitorRequestTemplateUpsertOne) IDX(ctx context.Context) int64 { + id, err := u.ID(ctx) + if err != nil { + panic(err) + } + return id +} + +// ChannelMonitorRequestTemplateCreateBulk is the builder for creating many ChannelMonitorRequestTemplate entities in bulk. +type ChannelMonitorRequestTemplateCreateBulk struct { + config + err error + builders []*ChannelMonitorRequestTemplateCreate + conflict []sql.ConflictOption +} + +// Save creates the ChannelMonitorRequestTemplate entities in the database. +func (_c *ChannelMonitorRequestTemplateCreateBulk) Save(ctx context.Context) ([]*ChannelMonitorRequestTemplate, error) { + if _c.err != nil { + return nil, _c.err + } + specs := make([]*sqlgraph.CreateSpec, len(_c.builders)) + nodes := make([]*ChannelMonitorRequestTemplate, 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.(*ChannelMonitorRequestTemplateMutation) + 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 *ChannelMonitorRequestTemplateCreateBulk) SaveX(ctx context.Context) []*ChannelMonitorRequestTemplate { + v, err := _c.Save(ctx) + if err != nil { + panic(err) + } + return v +} + +// Exec executes the query. +func (_c *ChannelMonitorRequestTemplateCreateBulk) Exec(ctx context.Context) error { + _, err := _c.Save(ctx) + return err +} + +// ExecX is like Exec, but panics if an error occurs. +func (_c *ChannelMonitorRequestTemplateCreateBulk) 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.ChannelMonitorRequestTemplate.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.ChannelMonitorRequestTemplateUpsert) { +// SetCreatedAt(v+v). +// }). +// Exec(ctx) +func (_c *ChannelMonitorRequestTemplateCreateBulk) OnConflict(opts ...sql.ConflictOption) *ChannelMonitorRequestTemplateUpsertBulk { + _c.conflict = opts + return &ChannelMonitorRequestTemplateUpsertBulk{ + create: _c, + } +} + +// OnConflictColumns calls `OnConflict` and configures the columns +// as conflict target. Using this option is equivalent to using: +// +// client.ChannelMonitorRequestTemplate.Create(). +// OnConflict(sql.ConflictColumns(columns...)). +// Exec(ctx) +func (_c *ChannelMonitorRequestTemplateCreateBulk) OnConflictColumns(columns ...string) *ChannelMonitorRequestTemplateUpsertBulk { + _c.conflict = append(_c.conflict, sql.ConflictColumns(columns...)) + return &ChannelMonitorRequestTemplateUpsertBulk{ + create: _c, + } +} + +// ChannelMonitorRequestTemplateUpsertBulk is the builder for "upsert"-ing +// a bulk of ChannelMonitorRequestTemplate nodes. +type ChannelMonitorRequestTemplateUpsertBulk struct { + create *ChannelMonitorRequestTemplateCreateBulk +} + +// UpdateNewValues updates the mutable fields using the new values that +// were set on create. Using this option is equivalent to using: +// +// client.ChannelMonitorRequestTemplate.Create(). +// OnConflict( +// sql.ResolveWithNewValues(), +// ). +// Exec(ctx) +func (u *ChannelMonitorRequestTemplateUpsertBulk) UpdateNewValues() *ChannelMonitorRequestTemplateUpsertBulk { + 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(channelmonitorrequesttemplate.FieldCreatedAt) + } + } + })) + return u +} + +// Ignore sets each column to itself in case of conflict. +// Using this option is equivalent to using: +// +// client.ChannelMonitorRequestTemplate.Create(). +// OnConflict(sql.ResolveWithIgnore()). +// Exec(ctx) +func (u *ChannelMonitorRequestTemplateUpsertBulk) Ignore() *ChannelMonitorRequestTemplateUpsertBulk { + 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 *ChannelMonitorRequestTemplateUpsertBulk) DoNothing() *ChannelMonitorRequestTemplateUpsertBulk { + u.create.conflict = append(u.create.conflict, sql.DoNothing()) + return u +} + +// Update allows overriding fields `UPDATE` values. See the ChannelMonitorRequestTemplateCreateBulk.OnConflict +// documentation for more info. +func (u *ChannelMonitorRequestTemplateUpsertBulk) Update(set func(*ChannelMonitorRequestTemplateUpsert)) *ChannelMonitorRequestTemplateUpsertBulk { + u.create.conflict = append(u.create.conflict, sql.ResolveWith(func(update *sql.UpdateSet) { + set(&ChannelMonitorRequestTemplateUpsert{UpdateSet: update}) + })) + return u +} + +// SetUpdatedAt sets the "updated_at" field. +func (u *ChannelMonitorRequestTemplateUpsertBulk) SetUpdatedAt(v time.Time) *ChannelMonitorRequestTemplateUpsertBulk { + return u.Update(func(s *ChannelMonitorRequestTemplateUpsert) { + s.SetUpdatedAt(v) + }) +} + +// UpdateUpdatedAt sets the "updated_at" field to the value that was provided on create. +func (u *ChannelMonitorRequestTemplateUpsertBulk) UpdateUpdatedAt() *ChannelMonitorRequestTemplateUpsertBulk { + return u.Update(func(s *ChannelMonitorRequestTemplateUpsert) { + s.UpdateUpdatedAt() + }) +} + +// SetName sets the "name" field. +func (u *ChannelMonitorRequestTemplateUpsertBulk) SetName(v string) *ChannelMonitorRequestTemplateUpsertBulk { + return u.Update(func(s *ChannelMonitorRequestTemplateUpsert) { + s.SetName(v) + }) +} + +// UpdateName sets the "name" field to the value that was provided on create. +func (u *ChannelMonitorRequestTemplateUpsertBulk) UpdateName() *ChannelMonitorRequestTemplateUpsertBulk { + return u.Update(func(s *ChannelMonitorRequestTemplateUpsert) { + s.UpdateName() + }) +} + +// SetProvider sets the "provider" field. +func (u *ChannelMonitorRequestTemplateUpsertBulk) SetProvider(v channelmonitorrequesttemplate.Provider) *ChannelMonitorRequestTemplateUpsertBulk { + return u.Update(func(s *ChannelMonitorRequestTemplateUpsert) { + s.SetProvider(v) + }) +} + +// UpdateProvider sets the "provider" field to the value that was provided on create. +func (u *ChannelMonitorRequestTemplateUpsertBulk) UpdateProvider() *ChannelMonitorRequestTemplateUpsertBulk { + return u.Update(func(s *ChannelMonitorRequestTemplateUpsert) { + s.UpdateProvider() + }) +} + +// SetDescription sets the "description" field. +func (u *ChannelMonitorRequestTemplateUpsertBulk) SetDescription(v string) *ChannelMonitorRequestTemplateUpsertBulk { + return u.Update(func(s *ChannelMonitorRequestTemplateUpsert) { + s.SetDescription(v) + }) +} + +// UpdateDescription sets the "description" field to the value that was provided on create. +func (u *ChannelMonitorRequestTemplateUpsertBulk) UpdateDescription() *ChannelMonitorRequestTemplateUpsertBulk { + return u.Update(func(s *ChannelMonitorRequestTemplateUpsert) { + s.UpdateDescription() + }) +} + +// ClearDescription clears the value of the "description" field. +func (u *ChannelMonitorRequestTemplateUpsertBulk) ClearDescription() *ChannelMonitorRequestTemplateUpsertBulk { + return u.Update(func(s *ChannelMonitorRequestTemplateUpsert) { + s.ClearDescription() + }) +} + +// SetExtraHeaders sets the "extra_headers" field. +func (u *ChannelMonitorRequestTemplateUpsertBulk) SetExtraHeaders(v map[string]string) *ChannelMonitorRequestTemplateUpsertBulk { + return u.Update(func(s *ChannelMonitorRequestTemplateUpsert) { + s.SetExtraHeaders(v) + }) +} + +// UpdateExtraHeaders sets the "extra_headers" field to the value that was provided on create. +func (u *ChannelMonitorRequestTemplateUpsertBulk) UpdateExtraHeaders() *ChannelMonitorRequestTemplateUpsertBulk { + return u.Update(func(s *ChannelMonitorRequestTemplateUpsert) { + s.UpdateExtraHeaders() + }) +} + +// SetBodyOverrideMode sets the "body_override_mode" field. +func (u *ChannelMonitorRequestTemplateUpsertBulk) SetBodyOverrideMode(v string) *ChannelMonitorRequestTemplateUpsertBulk { + return u.Update(func(s *ChannelMonitorRequestTemplateUpsert) { + s.SetBodyOverrideMode(v) + }) +} + +// UpdateBodyOverrideMode sets the "body_override_mode" field to the value that was provided on create. +func (u *ChannelMonitorRequestTemplateUpsertBulk) UpdateBodyOverrideMode() *ChannelMonitorRequestTemplateUpsertBulk { + return u.Update(func(s *ChannelMonitorRequestTemplateUpsert) { + s.UpdateBodyOverrideMode() + }) +} + +// SetBodyOverride sets the "body_override" field. +func (u *ChannelMonitorRequestTemplateUpsertBulk) SetBodyOverride(v map[string]interface{}) *ChannelMonitorRequestTemplateUpsertBulk { + return u.Update(func(s *ChannelMonitorRequestTemplateUpsert) { + s.SetBodyOverride(v) + }) +} + +// UpdateBodyOverride sets the "body_override" field to the value that was provided on create. +func (u *ChannelMonitorRequestTemplateUpsertBulk) UpdateBodyOverride() *ChannelMonitorRequestTemplateUpsertBulk { + return u.Update(func(s *ChannelMonitorRequestTemplateUpsert) { + s.UpdateBodyOverride() + }) +} + +// ClearBodyOverride clears the value of the "body_override" field. +func (u *ChannelMonitorRequestTemplateUpsertBulk) ClearBodyOverride() *ChannelMonitorRequestTemplateUpsertBulk { + return u.Update(func(s *ChannelMonitorRequestTemplateUpsert) { + s.ClearBodyOverride() + }) +} + +// Exec executes the query. +func (u *ChannelMonitorRequestTemplateUpsertBulk) 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 ChannelMonitorRequestTemplateCreateBulk instead", i) + } + } + if len(u.create.conflict) == 0 { + return errors.New("ent: missing options for ChannelMonitorRequestTemplateCreateBulk.OnConflict") + } + return u.create.Exec(ctx) +} + +// ExecX is like Exec, but panics if an error occurs. +func (u *ChannelMonitorRequestTemplateUpsertBulk) ExecX(ctx context.Context) { + if err := u.create.Exec(ctx); err != nil { + panic(err) + } +} diff --git a/backend/ent/channelmonitorrequesttemplate_delete.go b/backend/ent/channelmonitorrequesttemplate_delete.go new file mode 100644 index 00000000..98d365c8 --- /dev/null +++ b/backend/ent/channelmonitorrequesttemplate_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/channelmonitorrequesttemplate" + "github.com/Wei-Shaw/sub2api/ent/predicate" +) + +// ChannelMonitorRequestTemplateDelete is the builder for deleting a ChannelMonitorRequestTemplate entity. +type ChannelMonitorRequestTemplateDelete struct { + config + hooks []Hook + mutation *ChannelMonitorRequestTemplateMutation +} + +// Where appends a list predicates to the ChannelMonitorRequestTemplateDelete builder. +func (_d *ChannelMonitorRequestTemplateDelete) Where(ps ...predicate.ChannelMonitorRequestTemplate) *ChannelMonitorRequestTemplateDelete { + _d.mutation.Where(ps...) + return _d +} + +// Exec executes the deletion query and returns how many vertices were deleted. +func (_d *ChannelMonitorRequestTemplateDelete) 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 *ChannelMonitorRequestTemplateDelete) ExecX(ctx context.Context) int { + n, err := _d.Exec(ctx) + if err != nil { + panic(err) + } + return n +} + +func (_d *ChannelMonitorRequestTemplateDelete) sqlExec(ctx context.Context) (int, error) { + _spec := sqlgraph.NewDeleteSpec(channelmonitorrequesttemplate.Table, sqlgraph.NewFieldSpec(channelmonitorrequesttemplate.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 +} + +// ChannelMonitorRequestTemplateDeleteOne is the builder for deleting a single ChannelMonitorRequestTemplate entity. +type ChannelMonitorRequestTemplateDeleteOne struct { + _d *ChannelMonitorRequestTemplateDelete +} + +// Where appends a list predicates to the ChannelMonitorRequestTemplateDelete builder. +func (_d *ChannelMonitorRequestTemplateDeleteOne) Where(ps ...predicate.ChannelMonitorRequestTemplate) *ChannelMonitorRequestTemplateDeleteOne { + _d._d.mutation.Where(ps...) + return _d +} + +// Exec executes the deletion query. +func (_d *ChannelMonitorRequestTemplateDeleteOne) Exec(ctx context.Context) error { + n, err := _d._d.Exec(ctx) + switch { + case err != nil: + return err + case n == 0: + return &NotFoundError{channelmonitorrequesttemplate.Label} + default: + return nil + } +} + +// ExecX is like Exec, but panics if an error occurs. +func (_d *ChannelMonitorRequestTemplateDeleteOne) ExecX(ctx context.Context) { + if err := _d.Exec(ctx); err != nil { + panic(err) + } +} diff --git a/backend/ent/channelmonitorrequesttemplate_query.go b/backend/ent/channelmonitorrequesttemplate_query.go new file mode 100644 index 00000000..6491ea60 --- /dev/null +++ b/backend/ent/channelmonitorrequesttemplate_query.go @@ -0,0 +1,648 @@ +// Code generated by ent, DO NOT EDIT. + +package ent + +import ( + "context" + "database/sql/driver" + "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/channelmonitor" + "github.com/Wei-Shaw/sub2api/ent/channelmonitorrequesttemplate" + "github.com/Wei-Shaw/sub2api/ent/predicate" +) + +// ChannelMonitorRequestTemplateQuery is the builder for querying ChannelMonitorRequestTemplate entities. +type ChannelMonitorRequestTemplateQuery struct { + config + ctx *QueryContext + order []channelmonitorrequesttemplate.OrderOption + inters []Interceptor + predicates []predicate.ChannelMonitorRequestTemplate + withMonitors *ChannelMonitorQuery + 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 ChannelMonitorRequestTemplateQuery builder. +func (_q *ChannelMonitorRequestTemplateQuery) Where(ps ...predicate.ChannelMonitorRequestTemplate) *ChannelMonitorRequestTemplateQuery { + _q.predicates = append(_q.predicates, ps...) + return _q +} + +// Limit the number of records to be returned by this query. +func (_q *ChannelMonitorRequestTemplateQuery) Limit(limit int) *ChannelMonitorRequestTemplateQuery { + _q.ctx.Limit = &limit + return _q +} + +// Offset to start from. +func (_q *ChannelMonitorRequestTemplateQuery) Offset(offset int) *ChannelMonitorRequestTemplateQuery { + _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 *ChannelMonitorRequestTemplateQuery) Unique(unique bool) *ChannelMonitorRequestTemplateQuery { + _q.ctx.Unique = &unique + return _q +} + +// Order specifies how the records should be ordered. +func (_q *ChannelMonitorRequestTemplateQuery) Order(o ...channelmonitorrequesttemplate.OrderOption) *ChannelMonitorRequestTemplateQuery { + _q.order = append(_q.order, o...) + return _q +} + +// QueryMonitors chains the current query on the "monitors" edge. +func (_q *ChannelMonitorRequestTemplateQuery) QueryMonitors() *ChannelMonitorQuery { + query := (&ChannelMonitorClient{config: _q.config}).Query() + query.path = func(ctx context.Context) (fromU *sql.Selector, err error) { + if err := _q.prepareQuery(ctx); err != nil { + return nil, err + } + selector := _q.sqlQuery(ctx) + if err := selector.Err(); err != nil { + return nil, err + } + step := sqlgraph.NewStep( + sqlgraph.From(channelmonitorrequesttemplate.Table, channelmonitorrequesttemplate.FieldID, selector), + sqlgraph.To(channelmonitor.Table, channelmonitor.FieldID), + sqlgraph.Edge(sqlgraph.O2M, true, channelmonitorrequesttemplate.MonitorsTable, channelmonitorrequesttemplate.MonitorsColumn), + ) + fromU = sqlgraph.SetNeighbors(_q.driver.Dialect(), step) + return fromU, nil + } + return query +} + +// First returns the first ChannelMonitorRequestTemplate entity from the query. +// Returns a *NotFoundError when no ChannelMonitorRequestTemplate was found. +func (_q *ChannelMonitorRequestTemplateQuery) First(ctx context.Context) (*ChannelMonitorRequestTemplate, 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{channelmonitorrequesttemplate.Label} + } + return nodes[0], nil +} + +// FirstX is like First, but panics if an error occurs. +func (_q *ChannelMonitorRequestTemplateQuery) FirstX(ctx context.Context) *ChannelMonitorRequestTemplate { + node, err := _q.First(ctx) + if err != nil && !IsNotFound(err) { + panic(err) + } + return node +} + +// FirstID returns the first ChannelMonitorRequestTemplate ID from the query. +// Returns a *NotFoundError when no ChannelMonitorRequestTemplate ID was found. +func (_q *ChannelMonitorRequestTemplateQuery) 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{channelmonitorrequesttemplate.Label} + return + } + return ids[0], nil +} + +// FirstIDX is like FirstID, but panics if an error occurs. +func (_q *ChannelMonitorRequestTemplateQuery) FirstIDX(ctx context.Context) int64 { + id, err := _q.FirstID(ctx) + if err != nil && !IsNotFound(err) { + panic(err) + } + return id +} + +// Only returns a single ChannelMonitorRequestTemplate entity found by the query, ensuring it only returns one. +// Returns a *NotSingularError when more than one ChannelMonitorRequestTemplate entity is found. +// Returns a *NotFoundError when no ChannelMonitorRequestTemplate entities are found. +func (_q *ChannelMonitorRequestTemplateQuery) Only(ctx context.Context) (*ChannelMonitorRequestTemplate, 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{channelmonitorrequesttemplate.Label} + default: + return nil, &NotSingularError{channelmonitorrequesttemplate.Label} + } +} + +// OnlyX is like Only, but panics if an error occurs. +func (_q *ChannelMonitorRequestTemplateQuery) OnlyX(ctx context.Context) *ChannelMonitorRequestTemplate { + node, err := _q.Only(ctx) + if err != nil { + panic(err) + } + return node +} + +// OnlyID is like Only, but returns the only ChannelMonitorRequestTemplate ID in the query. +// Returns a *NotSingularError when more than one ChannelMonitorRequestTemplate ID is found. +// Returns a *NotFoundError when no entities are found. +func (_q *ChannelMonitorRequestTemplateQuery) 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{channelmonitorrequesttemplate.Label} + default: + err = &NotSingularError{channelmonitorrequesttemplate.Label} + } + return +} + +// OnlyIDX is like OnlyID, but panics if an error occurs. +func (_q *ChannelMonitorRequestTemplateQuery) 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 ChannelMonitorRequestTemplates. +func (_q *ChannelMonitorRequestTemplateQuery) All(ctx context.Context) ([]*ChannelMonitorRequestTemplate, error) { + ctx = setContextOp(ctx, _q.ctx, ent.OpQueryAll) + if err := _q.prepareQuery(ctx); err != nil { + return nil, err + } + qr := querierAll[[]*ChannelMonitorRequestTemplate, *ChannelMonitorRequestTemplateQuery]() + return withInterceptors[[]*ChannelMonitorRequestTemplate](ctx, _q, qr, _q.inters) +} + +// AllX is like All, but panics if an error occurs. +func (_q *ChannelMonitorRequestTemplateQuery) AllX(ctx context.Context) []*ChannelMonitorRequestTemplate { + nodes, err := _q.All(ctx) + if err != nil { + panic(err) + } + return nodes +} + +// IDs executes the query and returns a list of ChannelMonitorRequestTemplate IDs. +func (_q *ChannelMonitorRequestTemplateQuery) 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(channelmonitorrequesttemplate.FieldID).Scan(ctx, &ids); err != nil { + return nil, err + } + return ids, nil +} + +// IDsX is like IDs, but panics if an error occurs. +func (_q *ChannelMonitorRequestTemplateQuery) 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 *ChannelMonitorRequestTemplateQuery) 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[*ChannelMonitorRequestTemplateQuery](), _q.inters) +} + +// CountX is like Count, but panics if an error occurs. +func (_q *ChannelMonitorRequestTemplateQuery) 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 *ChannelMonitorRequestTemplateQuery) 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 *ChannelMonitorRequestTemplateQuery) ExistX(ctx context.Context) bool { + exist, err := _q.Exist(ctx) + if err != nil { + panic(err) + } + return exist +} + +// Clone returns a duplicate of the ChannelMonitorRequestTemplateQuery 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 *ChannelMonitorRequestTemplateQuery) Clone() *ChannelMonitorRequestTemplateQuery { + if _q == nil { + return nil + } + return &ChannelMonitorRequestTemplateQuery{ + config: _q.config, + ctx: _q.ctx.Clone(), + order: append([]channelmonitorrequesttemplate.OrderOption{}, _q.order...), + inters: append([]Interceptor{}, _q.inters...), + predicates: append([]predicate.ChannelMonitorRequestTemplate{}, _q.predicates...), + withMonitors: _q.withMonitors.Clone(), + // clone intermediate query. + sql: _q.sql.Clone(), + path: _q.path, + } +} + +// WithMonitors tells the query-builder to eager-load the nodes that are connected to +// the "monitors" edge. The optional arguments are used to configure the query builder of the edge. +func (_q *ChannelMonitorRequestTemplateQuery) WithMonitors(opts ...func(*ChannelMonitorQuery)) *ChannelMonitorRequestTemplateQuery { + query := (&ChannelMonitorClient{config: _q.config}).Query() + for _, opt := range opts { + opt(query) + } + _q.withMonitors = query + return _q +} + +// GroupBy is used to group vertices by one or more fields/columns. +// It is often used with aggregate functions, like: count, max, mean, min, sum. +// +// Example: +// +// var v []struct { +// CreatedAt time.Time `json:"created_at,omitempty"` +// Count int `json:"count,omitempty"` +// } +// +// client.ChannelMonitorRequestTemplate.Query(). +// GroupBy(channelmonitorrequesttemplate.FieldCreatedAt). +// Aggregate(ent.Count()). +// Scan(ctx, &v) +func (_q *ChannelMonitorRequestTemplateQuery) GroupBy(field string, fields ...string) *ChannelMonitorRequestTemplateGroupBy { + _q.ctx.Fields = append([]string{field}, fields...) + grbuild := &ChannelMonitorRequestTemplateGroupBy{build: _q} + grbuild.flds = &_q.ctx.Fields + grbuild.label = channelmonitorrequesttemplate.Label + grbuild.scan = grbuild.Scan + return grbuild +} + +// Select allows the selection one or more fields/columns for the given query, +// instead of selecting all fields in the entity. +// +// Example: +// +// var v []struct { +// CreatedAt time.Time `json:"created_at,omitempty"` +// } +// +// client.ChannelMonitorRequestTemplate.Query(). +// Select(channelmonitorrequesttemplate.FieldCreatedAt). +// Scan(ctx, &v) +func (_q *ChannelMonitorRequestTemplateQuery) Select(fields ...string) *ChannelMonitorRequestTemplateSelect { + _q.ctx.Fields = append(_q.ctx.Fields, fields...) + sbuild := &ChannelMonitorRequestTemplateSelect{ChannelMonitorRequestTemplateQuery: _q} + sbuild.label = channelmonitorrequesttemplate.Label + sbuild.flds, sbuild.scan = &_q.ctx.Fields, sbuild.Scan + return sbuild +} + +// Aggregate returns a ChannelMonitorRequestTemplateSelect configured with the given aggregations. +func (_q *ChannelMonitorRequestTemplateQuery) Aggregate(fns ...AggregateFunc) *ChannelMonitorRequestTemplateSelect { + return _q.Select().Aggregate(fns...) +} + +func (_q *ChannelMonitorRequestTemplateQuery) 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 !channelmonitorrequesttemplate.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 *ChannelMonitorRequestTemplateQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*ChannelMonitorRequestTemplate, error) { + var ( + nodes = []*ChannelMonitorRequestTemplate{} + _spec = _q.querySpec() + loadedTypes = [1]bool{ + _q.withMonitors != nil, + } + ) + _spec.ScanValues = func(columns []string) ([]any, error) { + return (*ChannelMonitorRequestTemplate).scanValues(nil, columns) + } + _spec.Assign = func(columns []string, values []any) error { + node := &ChannelMonitorRequestTemplate{config: _q.config} + nodes = append(nodes, node) + node.Edges.loadedTypes = loadedTypes + 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 + } + if query := _q.withMonitors; query != nil { + if err := _q.loadMonitors(ctx, query, nodes, + func(n *ChannelMonitorRequestTemplate) { n.Edges.Monitors = []*ChannelMonitor{} }, + func(n *ChannelMonitorRequestTemplate, e *ChannelMonitor) { + n.Edges.Monitors = append(n.Edges.Monitors, e) + }); err != nil { + return nil, err + } + } + return nodes, nil +} + +func (_q *ChannelMonitorRequestTemplateQuery) loadMonitors(ctx context.Context, query *ChannelMonitorQuery, nodes []*ChannelMonitorRequestTemplate, init func(*ChannelMonitorRequestTemplate), assign func(*ChannelMonitorRequestTemplate, *ChannelMonitor)) error { + fks := make([]driver.Value, 0, len(nodes)) + nodeids := make(map[int64]*ChannelMonitorRequestTemplate) + for i := range nodes { + fks = append(fks, nodes[i].ID) + nodeids[nodes[i].ID] = nodes[i] + if init != nil { + init(nodes[i]) + } + } + if len(query.ctx.Fields) > 0 { + query.ctx.AppendFieldOnce(channelmonitor.FieldTemplateID) + } + query.Where(predicate.ChannelMonitor(func(s *sql.Selector) { + s.Where(sql.InValues(s.C(channelmonitorrequesttemplate.MonitorsColumn), fks...)) + })) + neighbors, err := query.All(ctx) + if err != nil { + return err + } + for _, n := range neighbors { + fk := n.TemplateID + if fk == nil { + return fmt.Errorf(`foreign-key "template_id" is nil for node %v`, n.ID) + } + node, ok := nodeids[*fk] + if !ok { + return fmt.Errorf(`unexpected referenced foreign-key "template_id" returned %v for node %v`, *fk, n.ID) + } + assign(node, n) + } + return nil +} + +func (_q *ChannelMonitorRequestTemplateQuery) 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 *ChannelMonitorRequestTemplateQuery) querySpec() *sqlgraph.QuerySpec { + _spec := sqlgraph.NewQuerySpec(channelmonitorrequesttemplate.Table, channelmonitorrequesttemplate.Columns, sqlgraph.NewFieldSpec(channelmonitorrequesttemplate.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, channelmonitorrequesttemplate.FieldID) + for i := range fields { + if fields[i] != channelmonitorrequesttemplate.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 *ChannelMonitorRequestTemplateQuery) sqlQuery(ctx context.Context) *sql.Selector { + builder := sql.Dialect(_q.driver.Dialect()) + t1 := builder.Table(channelmonitorrequesttemplate.Table) + columns := _q.ctx.Fields + if len(columns) == 0 { + columns = channelmonitorrequesttemplate.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 *ChannelMonitorRequestTemplateQuery) ForUpdate(opts ...sql.LockOption) *ChannelMonitorRequestTemplateQuery { + 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 *ChannelMonitorRequestTemplateQuery) ForShare(opts ...sql.LockOption) *ChannelMonitorRequestTemplateQuery { + if _q.driver.Dialect() == dialect.Postgres { + _q.Unique(false) + } + _q.modifiers = append(_q.modifiers, func(s *sql.Selector) { + s.ForShare(opts...) + }) + return _q +} + +// ChannelMonitorRequestTemplateGroupBy is the group-by builder for ChannelMonitorRequestTemplate entities. +type ChannelMonitorRequestTemplateGroupBy struct { + selector + build *ChannelMonitorRequestTemplateQuery +} + +// Aggregate adds the given aggregation functions to the group-by query. +func (_g *ChannelMonitorRequestTemplateGroupBy) Aggregate(fns ...AggregateFunc) *ChannelMonitorRequestTemplateGroupBy { + _g.fns = append(_g.fns, fns...) + return _g +} + +// Scan applies the selector query and scans the result into the given value. +func (_g *ChannelMonitorRequestTemplateGroupBy) 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[*ChannelMonitorRequestTemplateQuery, *ChannelMonitorRequestTemplateGroupBy](ctx, _g.build, _g, _g.build.inters, v) +} + +func (_g *ChannelMonitorRequestTemplateGroupBy) sqlScan(ctx context.Context, root *ChannelMonitorRequestTemplateQuery, 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) +} + +// ChannelMonitorRequestTemplateSelect is the builder for selecting fields of ChannelMonitorRequestTemplate entities. +type ChannelMonitorRequestTemplateSelect struct { + *ChannelMonitorRequestTemplateQuery + selector +} + +// Aggregate adds the given aggregation functions to the selector query. +func (_s *ChannelMonitorRequestTemplateSelect) Aggregate(fns ...AggregateFunc) *ChannelMonitorRequestTemplateSelect { + _s.fns = append(_s.fns, fns...) + return _s +} + +// Scan applies the selector query and scans the result into the given value. +func (_s *ChannelMonitorRequestTemplateSelect) 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[*ChannelMonitorRequestTemplateQuery, *ChannelMonitorRequestTemplateSelect](ctx, _s.ChannelMonitorRequestTemplateQuery, _s, _s.inters, v) +} + +func (_s *ChannelMonitorRequestTemplateSelect) sqlScan(ctx context.Context, root *ChannelMonitorRequestTemplateQuery, 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/channelmonitorrequesttemplate_update.go b/backend/ent/channelmonitorrequesttemplate_update.go new file mode 100644 index 00000000..8f55ba04 --- /dev/null +++ b/backend/ent/channelmonitorrequesttemplate_update.go @@ -0,0 +1,639 @@ +// 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/channelmonitor" + "github.com/Wei-Shaw/sub2api/ent/channelmonitorrequesttemplate" + "github.com/Wei-Shaw/sub2api/ent/predicate" +) + +// ChannelMonitorRequestTemplateUpdate is the builder for updating ChannelMonitorRequestTemplate entities. +type ChannelMonitorRequestTemplateUpdate struct { + config + hooks []Hook + mutation *ChannelMonitorRequestTemplateMutation +} + +// Where appends a list predicates to the ChannelMonitorRequestTemplateUpdate builder. +func (_u *ChannelMonitorRequestTemplateUpdate) Where(ps ...predicate.ChannelMonitorRequestTemplate) *ChannelMonitorRequestTemplateUpdate { + _u.mutation.Where(ps...) + return _u +} + +// SetUpdatedAt sets the "updated_at" field. +func (_u *ChannelMonitorRequestTemplateUpdate) SetUpdatedAt(v time.Time) *ChannelMonitorRequestTemplateUpdate { + _u.mutation.SetUpdatedAt(v) + return _u +} + +// SetName sets the "name" field. +func (_u *ChannelMonitorRequestTemplateUpdate) SetName(v string) *ChannelMonitorRequestTemplateUpdate { + _u.mutation.SetName(v) + return _u +} + +// SetNillableName sets the "name" field if the given value is not nil. +func (_u *ChannelMonitorRequestTemplateUpdate) SetNillableName(v *string) *ChannelMonitorRequestTemplateUpdate { + if v != nil { + _u.SetName(*v) + } + return _u +} + +// SetProvider sets the "provider" field. +func (_u *ChannelMonitorRequestTemplateUpdate) SetProvider(v channelmonitorrequesttemplate.Provider) *ChannelMonitorRequestTemplateUpdate { + _u.mutation.SetProvider(v) + return _u +} + +// SetNillableProvider sets the "provider" field if the given value is not nil. +func (_u *ChannelMonitorRequestTemplateUpdate) SetNillableProvider(v *channelmonitorrequesttemplate.Provider) *ChannelMonitorRequestTemplateUpdate { + if v != nil { + _u.SetProvider(*v) + } + return _u +} + +// SetDescription sets the "description" field. +func (_u *ChannelMonitorRequestTemplateUpdate) SetDescription(v string) *ChannelMonitorRequestTemplateUpdate { + _u.mutation.SetDescription(v) + return _u +} + +// SetNillableDescription sets the "description" field if the given value is not nil. +func (_u *ChannelMonitorRequestTemplateUpdate) SetNillableDescription(v *string) *ChannelMonitorRequestTemplateUpdate { + if v != nil { + _u.SetDescription(*v) + } + return _u +} + +// ClearDescription clears the value of the "description" field. +func (_u *ChannelMonitorRequestTemplateUpdate) ClearDescription() *ChannelMonitorRequestTemplateUpdate { + _u.mutation.ClearDescription() + return _u +} + +// SetExtraHeaders sets the "extra_headers" field. +func (_u *ChannelMonitorRequestTemplateUpdate) SetExtraHeaders(v map[string]string) *ChannelMonitorRequestTemplateUpdate { + _u.mutation.SetExtraHeaders(v) + return _u +} + +// SetBodyOverrideMode sets the "body_override_mode" field. +func (_u *ChannelMonitorRequestTemplateUpdate) SetBodyOverrideMode(v string) *ChannelMonitorRequestTemplateUpdate { + _u.mutation.SetBodyOverrideMode(v) + return _u +} + +// SetNillableBodyOverrideMode sets the "body_override_mode" field if the given value is not nil. +func (_u *ChannelMonitorRequestTemplateUpdate) SetNillableBodyOverrideMode(v *string) *ChannelMonitorRequestTemplateUpdate { + if v != nil { + _u.SetBodyOverrideMode(*v) + } + return _u +} + +// SetBodyOverride sets the "body_override" field. +func (_u *ChannelMonitorRequestTemplateUpdate) SetBodyOverride(v map[string]interface{}) *ChannelMonitorRequestTemplateUpdate { + _u.mutation.SetBodyOverride(v) + return _u +} + +// ClearBodyOverride clears the value of the "body_override" field. +func (_u *ChannelMonitorRequestTemplateUpdate) ClearBodyOverride() *ChannelMonitorRequestTemplateUpdate { + _u.mutation.ClearBodyOverride() + return _u +} + +// AddMonitorIDs adds the "monitors" edge to the ChannelMonitor entity by IDs. +func (_u *ChannelMonitorRequestTemplateUpdate) AddMonitorIDs(ids ...int64) *ChannelMonitorRequestTemplateUpdate { + _u.mutation.AddMonitorIDs(ids...) + return _u +} + +// AddMonitors adds the "monitors" edges to the ChannelMonitor entity. +func (_u *ChannelMonitorRequestTemplateUpdate) AddMonitors(v ...*ChannelMonitor) *ChannelMonitorRequestTemplateUpdate { + ids := make([]int64, len(v)) + for i := range v { + ids[i] = v[i].ID + } + return _u.AddMonitorIDs(ids...) +} + +// Mutation returns the ChannelMonitorRequestTemplateMutation object of the builder. +func (_u *ChannelMonitorRequestTemplateUpdate) Mutation() *ChannelMonitorRequestTemplateMutation { + return _u.mutation +} + +// ClearMonitors clears all "monitors" edges to the ChannelMonitor entity. +func (_u *ChannelMonitorRequestTemplateUpdate) ClearMonitors() *ChannelMonitorRequestTemplateUpdate { + _u.mutation.ClearMonitors() + return _u +} + +// RemoveMonitorIDs removes the "monitors" edge to ChannelMonitor entities by IDs. +func (_u *ChannelMonitorRequestTemplateUpdate) RemoveMonitorIDs(ids ...int64) *ChannelMonitorRequestTemplateUpdate { + _u.mutation.RemoveMonitorIDs(ids...) + return _u +} + +// RemoveMonitors removes "monitors" edges to ChannelMonitor entities. +func (_u *ChannelMonitorRequestTemplateUpdate) RemoveMonitors(v ...*ChannelMonitor) *ChannelMonitorRequestTemplateUpdate { + ids := make([]int64, len(v)) + for i := range v { + ids[i] = v[i].ID + } + return _u.RemoveMonitorIDs(ids...) +} + +// Save executes the query and returns the number of nodes affected by the update operation. +func (_u *ChannelMonitorRequestTemplateUpdate) 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 *ChannelMonitorRequestTemplateUpdate) SaveX(ctx context.Context) int { + affected, err := _u.Save(ctx) + if err != nil { + panic(err) + } + return affected +} + +// Exec executes the query. +func (_u *ChannelMonitorRequestTemplateUpdate) Exec(ctx context.Context) error { + _, err := _u.Save(ctx) + return err +} + +// ExecX is like Exec, but panics if an error occurs. +func (_u *ChannelMonitorRequestTemplateUpdate) 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 *ChannelMonitorRequestTemplateUpdate) defaults() { + if _, ok := _u.mutation.UpdatedAt(); !ok { + v := channelmonitorrequesttemplate.UpdateDefaultUpdatedAt() + _u.mutation.SetUpdatedAt(v) + } +} + +// check runs all checks and user-defined validators on the builder. +func (_u *ChannelMonitorRequestTemplateUpdate) check() error { + if v, ok := _u.mutation.Name(); ok { + if err := channelmonitorrequesttemplate.NameValidator(v); err != nil { + return &ValidationError{Name: "name", err: fmt.Errorf(`ent: validator failed for field "ChannelMonitorRequestTemplate.name": %w`, err)} + } + } + if v, ok := _u.mutation.Provider(); ok { + if err := channelmonitorrequesttemplate.ProviderValidator(v); err != nil { + return &ValidationError{Name: "provider", err: fmt.Errorf(`ent: validator failed for field "ChannelMonitorRequestTemplate.provider": %w`, err)} + } + } + if v, ok := _u.mutation.Description(); ok { + if err := channelmonitorrequesttemplate.DescriptionValidator(v); err != nil { + return &ValidationError{Name: "description", err: fmt.Errorf(`ent: validator failed for field "ChannelMonitorRequestTemplate.description": %w`, err)} + } + } + if v, ok := _u.mutation.BodyOverrideMode(); ok { + if err := channelmonitorrequesttemplate.BodyOverrideModeValidator(v); err != nil { + return &ValidationError{Name: "body_override_mode", err: fmt.Errorf(`ent: validator failed for field "ChannelMonitorRequestTemplate.body_override_mode": %w`, err)} + } + } + return nil +} + +func (_u *ChannelMonitorRequestTemplateUpdate) sqlSave(ctx context.Context) (_node int, err error) { + if err := _u.check(); err != nil { + return _node, err + } + _spec := sqlgraph.NewUpdateSpec(channelmonitorrequesttemplate.Table, channelmonitorrequesttemplate.Columns, sqlgraph.NewFieldSpec(channelmonitorrequesttemplate.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.UpdatedAt(); ok { + _spec.SetField(channelmonitorrequesttemplate.FieldUpdatedAt, field.TypeTime, value) + } + if value, ok := _u.mutation.Name(); ok { + _spec.SetField(channelmonitorrequesttemplate.FieldName, field.TypeString, value) + } + if value, ok := _u.mutation.Provider(); ok { + _spec.SetField(channelmonitorrequesttemplate.FieldProvider, field.TypeEnum, value) + } + if value, ok := _u.mutation.Description(); ok { + _spec.SetField(channelmonitorrequesttemplate.FieldDescription, field.TypeString, value) + } + if _u.mutation.DescriptionCleared() { + _spec.ClearField(channelmonitorrequesttemplate.FieldDescription, field.TypeString) + } + if value, ok := _u.mutation.ExtraHeaders(); ok { + _spec.SetField(channelmonitorrequesttemplate.FieldExtraHeaders, field.TypeJSON, value) + } + if value, ok := _u.mutation.BodyOverrideMode(); ok { + _spec.SetField(channelmonitorrequesttemplate.FieldBodyOverrideMode, field.TypeString, value) + } + if value, ok := _u.mutation.BodyOverride(); ok { + _spec.SetField(channelmonitorrequesttemplate.FieldBodyOverride, field.TypeJSON, value) + } + if _u.mutation.BodyOverrideCleared() { + _spec.ClearField(channelmonitorrequesttemplate.FieldBodyOverride, field.TypeJSON) + } + if _u.mutation.MonitorsCleared() { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.O2M, + Inverse: true, + Table: channelmonitorrequesttemplate.MonitorsTable, + Columns: []string{channelmonitorrequesttemplate.MonitorsColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(channelmonitor.FieldID, field.TypeInt64), + }, + } + _spec.Edges.Clear = append(_spec.Edges.Clear, edge) + } + if nodes := _u.mutation.RemovedMonitorsIDs(); len(nodes) > 0 && !_u.mutation.MonitorsCleared() { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.O2M, + Inverse: true, + Table: channelmonitorrequesttemplate.MonitorsTable, + Columns: []string{channelmonitorrequesttemplate.MonitorsColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(channelmonitor.FieldID, field.TypeInt64), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _spec.Edges.Clear = append(_spec.Edges.Clear, edge) + } + if nodes := _u.mutation.MonitorsIDs(); len(nodes) > 0 { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.O2M, + Inverse: true, + Table: channelmonitorrequesttemplate.MonitorsTable, + Columns: []string{channelmonitorrequesttemplate.MonitorsColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(channelmonitor.FieldID, field.TypeInt64), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _spec.Edges.Add = append(_spec.Edges.Add, edge) + } + if _node, err = sqlgraph.UpdateNodes(ctx, _u.driver, _spec); err != nil { + if _, ok := err.(*sqlgraph.NotFoundError); ok { + err = &NotFoundError{channelmonitorrequesttemplate.Label} + } else if sqlgraph.IsConstraintError(err) { + err = &ConstraintError{msg: err.Error(), wrap: err} + } + return 0, err + } + _u.mutation.done = true + return _node, nil +} + +// ChannelMonitorRequestTemplateUpdateOne is the builder for updating a single ChannelMonitorRequestTemplate entity. +type ChannelMonitorRequestTemplateUpdateOne struct { + config + fields []string + hooks []Hook + mutation *ChannelMonitorRequestTemplateMutation +} + +// SetUpdatedAt sets the "updated_at" field. +func (_u *ChannelMonitorRequestTemplateUpdateOne) SetUpdatedAt(v time.Time) *ChannelMonitorRequestTemplateUpdateOne { + _u.mutation.SetUpdatedAt(v) + return _u +} + +// SetName sets the "name" field. +func (_u *ChannelMonitorRequestTemplateUpdateOne) SetName(v string) *ChannelMonitorRequestTemplateUpdateOne { + _u.mutation.SetName(v) + return _u +} + +// SetNillableName sets the "name" field if the given value is not nil. +func (_u *ChannelMonitorRequestTemplateUpdateOne) SetNillableName(v *string) *ChannelMonitorRequestTemplateUpdateOne { + if v != nil { + _u.SetName(*v) + } + return _u +} + +// SetProvider sets the "provider" field. +func (_u *ChannelMonitorRequestTemplateUpdateOne) SetProvider(v channelmonitorrequesttemplate.Provider) *ChannelMonitorRequestTemplateUpdateOne { + _u.mutation.SetProvider(v) + return _u +} + +// SetNillableProvider sets the "provider" field if the given value is not nil. +func (_u *ChannelMonitorRequestTemplateUpdateOne) SetNillableProvider(v *channelmonitorrequesttemplate.Provider) *ChannelMonitorRequestTemplateUpdateOne { + if v != nil { + _u.SetProvider(*v) + } + return _u +} + +// SetDescription sets the "description" field. +func (_u *ChannelMonitorRequestTemplateUpdateOne) SetDescription(v string) *ChannelMonitorRequestTemplateUpdateOne { + _u.mutation.SetDescription(v) + return _u +} + +// SetNillableDescription sets the "description" field if the given value is not nil. +func (_u *ChannelMonitorRequestTemplateUpdateOne) SetNillableDescription(v *string) *ChannelMonitorRequestTemplateUpdateOne { + if v != nil { + _u.SetDescription(*v) + } + return _u +} + +// ClearDescription clears the value of the "description" field. +func (_u *ChannelMonitorRequestTemplateUpdateOne) ClearDescription() *ChannelMonitorRequestTemplateUpdateOne { + _u.mutation.ClearDescription() + return _u +} + +// SetExtraHeaders sets the "extra_headers" field. +func (_u *ChannelMonitorRequestTemplateUpdateOne) SetExtraHeaders(v map[string]string) *ChannelMonitorRequestTemplateUpdateOne { + _u.mutation.SetExtraHeaders(v) + return _u +} + +// SetBodyOverrideMode sets the "body_override_mode" field. +func (_u *ChannelMonitorRequestTemplateUpdateOne) SetBodyOverrideMode(v string) *ChannelMonitorRequestTemplateUpdateOne { + _u.mutation.SetBodyOverrideMode(v) + return _u +} + +// SetNillableBodyOverrideMode sets the "body_override_mode" field if the given value is not nil. +func (_u *ChannelMonitorRequestTemplateUpdateOne) SetNillableBodyOverrideMode(v *string) *ChannelMonitorRequestTemplateUpdateOne { + if v != nil { + _u.SetBodyOverrideMode(*v) + } + return _u +} + +// SetBodyOverride sets the "body_override" field. +func (_u *ChannelMonitorRequestTemplateUpdateOne) SetBodyOverride(v map[string]interface{}) *ChannelMonitorRequestTemplateUpdateOne { + _u.mutation.SetBodyOverride(v) + return _u +} + +// ClearBodyOverride clears the value of the "body_override" field. +func (_u *ChannelMonitorRequestTemplateUpdateOne) ClearBodyOverride() *ChannelMonitorRequestTemplateUpdateOne { + _u.mutation.ClearBodyOverride() + return _u +} + +// AddMonitorIDs adds the "monitors" edge to the ChannelMonitor entity by IDs. +func (_u *ChannelMonitorRequestTemplateUpdateOne) AddMonitorIDs(ids ...int64) *ChannelMonitorRequestTemplateUpdateOne { + _u.mutation.AddMonitorIDs(ids...) + return _u +} + +// AddMonitors adds the "monitors" edges to the ChannelMonitor entity. +func (_u *ChannelMonitorRequestTemplateUpdateOne) AddMonitors(v ...*ChannelMonitor) *ChannelMonitorRequestTemplateUpdateOne { + ids := make([]int64, len(v)) + for i := range v { + ids[i] = v[i].ID + } + return _u.AddMonitorIDs(ids...) +} + +// Mutation returns the ChannelMonitorRequestTemplateMutation object of the builder. +func (_u *ChannelMonitorRequestTemplateUpdateOne) Mutation() *ChannelMonitorRequestTemplateMutation { + return _u.mutation +} + +// ClearMonitors clears all "monitors" edges to the ChannelMonitor entity. +func (_u *ChannelMonitorRequestTemplateUpdateOne) ClearMonitors() *ChannelMonitorRequestTemplateUpdateOne { + _u.mutation.ClearMonitors() + return _u +} + +// RemoveMonitorIDs removes the "monitors" edge to ChannelMonitor entities by IDs. +func (_u *ChannelMonitorRequestTemplateUpdateOne) RemoveMonitorIDs(ids ...int64) *ChannelMonitorRequestTemplateUpdateOne { + _u.mutation.RemoveMonitorIDs(ids...) + return _u +} + +// RemoveMonitors removes "monitors" edges to ChannelMonitor entities. +func (_u *ChannelMonitorRequestTemplateUpdateOne) RemoveMonitors(v ...*ChannelMonitor) *ChannelMonitorRequestTemplateUpdateOne { + ids := make([]int64, len(v)) + for i := range v { + ids[i] = v[i].ID + } + return _u.RemoveMonitorIDs(ids...) +} + +// Where appends a list predicates to the ChannelMonitorRequestTemplateUpdate builder. +func (_u *ChannelMonitorRequestTemplateUpdateOne) Where(ps ...predicate.ChannelMonitorRequestTemplate) *ChannelMonitorRequestTemplateUpdateOne { + _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 *ChannelMonitorRequestTemplateUpdateOne) Select(field string, fields ...string) *ChannelMonitorRequestTemplateUpdateOne { + _u.fields = append([]string{field}, fields...) + return _u +} + +// Save executes the query and returns the updated ChannelMonitorRequestTemplate entity. +func (_u *ChannelMonitorRequestTemplateUpdateOne) Save(ctx context.Context) (*ChannelMonitorRequestTemplate, error) { + _u.defaults() + return withHooks(ctx, _u.sqlSave, _u.mutation, _u.hooks) +} + +// SaveX is like Save, but panics if an error occurs. +func (_u *ChannelMonitorRequestTemplateUpdateOne) SaveX(ctx context.Context) *ChannelMonitorRequestTemplate { + node, err := _u.Save(ctx) + if err != nil { + panic(err) + } + return node +} + +// Exec executes the query on the entity. +func (_u *ChannelMonitorRequestTemplateUpdateOne) Exec(ctx context.Context) error { + _, err := _u.Save(ctx) + return err +} + +// ExecX is like Exec, but panics if an error occurs. +func (_u *ChannelMonitorRequestTemplateUpdateOne) 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 *ChannelMonitorRequestTemplateUpdateOne) defaults() { + if _, ok := _u.mutation.UpdatedAt(); !ok { + v := channelmonitorrequesttemplate.UpdateDefaultUpdatedAt() + _u.mutation.SetUpdatedAt(v) + } +} + +// check runs all checks and user-defined validators on the builder. +func (_u *ChannelMonitorRequestTemplateUpdateOne) check() error { + if v, ok := _u.mutation.Name(); ok { + if err := channelmonitorrequesttemplate.NameValidator(v); err != nil { + return &ValidationError{Name: "name", err: fmt.Errorf(`ent: validator failed for field "ChannelMonitorRequestTemplate.name": %w`, err)} + } + } + if v, ok := _u.mutation.Provider(); ok { + if err := channelmonitorrequesttemplate.ProviderValidator(v); err != nil { + return &ValidationError{Name: "provider", err: fmt.Errorf(`ent: validator failed for field "ChannelMonitorRequestTemplate.provider": %w`, err)} + } + } + if v, ok := _u.mutation.Description(); ok { + if err := channelmonitorrequesttemplate.DescriptionValidator(v); err != nil { + return &ValidationError{Name: "description", err: fmt.Errorf(`ent: validator failed for field "ChannelMonitorRequestTemplate.description": %w`, err)} + } + } + if v, ok := _u.mutation.BodyOverrideMode(); ok { + if err := channelmonitorrequesttemplate.BodyOverrideModeValidator(v); err != nil { + return &ValidationError{Name: "body_override_mode", err: fmt.Errorf(`ent: validator failed for field "ChannelMonitorRequestTemplate.body_override_mode": %w`, err)} + } + } + return nil +} + +func (_u *ChannelMonitorRequestTemplateUpdateOne) sqlSave(ctx context.Context) (_node *ChannelMonitorRequestTemplate, err error) { + if err := _u.check(); err != nil { + return _node, err + } + _spec := sqlgraph.NewUpdateSpec(channelmonitorrequesttemplate.Table, channelmonitorrequesttemplate.Columns, sqlgraph.NewFieldSpec(channelmonitorrequesttemplate.FieldID, field.TypeInt64)) + id, ok := _u.mutation.ID() + if !ok { + return nil, &ValidationError{Name: "id", err: errors.New(`ent: missing "ChannelMonitorRequestTemplate.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, channelmonitorrequesttemplate.FieldID) + for _, f := range fields { + if !channelmonitorrequesttemplate.ValidColumn(f) { + return nil, &ValidationError{Name: f, err: fmt.Errorf("ent: invalid field %q for query", f)} + } + if f != channelmonitorrequesttemplate.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.UpdatedAt(); ok { + _spec.SetField(channelmonitorrequesttemplate.FieldUpdatedAt, field.TypeTime, value) + } + if value, ok := _u.mutation.Name(); ok { + _spec.SetField(channelmonitorrequesttemplate.FieldName, field.TypeString, value) + } + if value, ok := _u.mutation.Provider(); ok { + _spec.SetField(channelmonitorrequesttemplate.FieldProvider, field.TypeEnum, value) + } + if value, ok := _u.mutation.Description(); ok { + _spec.SetField(channelmonitorrequesttemplate.FieldDescription, field.TypeString, value) + } + if _u.mutation.DescriptionCleared() { + _spec.ClearField(channelmonitorrequesttemplate.FieldDescription, field.TypeString) + } + if value, ok := _u.mutation.ExtraHeaders(); ok { + _spec.SetField(channelmonitorrequesttemplate.FieldExtraHeaders, field.TypeJSON, value) + } + if value, ok := _u.mutation.BodyOverrideMode(); ok { + _spec.SetField(channelmonitorrequesttemplate.FieldBodyOverrideMode, field.TypeString, value) + } + if value, ok := _u.mutation.BodyOverride(); ok { + _spec.SetField(channelmonitorrequesttemplate.FieldBodyOverride, field.TypeJSON, value) + } + if _u.mutation.BodyOverrideCleared() { + _spec.ClearField(channelmonitorrequesttemplate.FieldBodyOverride, field.TypeJSON) + } + if _u.mutation.MonitorsCleared() { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.O2M, + Inverse: true, + Table: channelmonitorrequesttemplate.MonitorsTable, + Columns: []string{channelmonitorrequesttemplate.MonitorsColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(channelmonitor.FieldID, field.TypeInt64), + }, + } + _spec.Edges.Clear = append(_spec.Edges.Clear, edge) + } + if nodes := _u.mutation.RemovedMonitorsIDs(); len(nodes) > 0 && !_u.mutation.MonitorsCleared() { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.O2M, + Inverse: true, + Table: channelmonitorrequesttemplate.MonitorsTable, + Columns: []string{channelmonitorrequesttemplate.MonitorsColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(channelmonitor.FieldID, field.TypeInt64), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _spec.Edges.Clear = append(_spec.Edges.Clear, edge) + } + if nodes := _u.mutation.MonitorsIDs(); len(nodes) > 0 { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.O2M, + Inverse: true, + Table: channelmonitorrequesttemplate.MonitorsTable, + Columns: []string{channelmonitorrequesttemplate.MonitorsColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(channelmonitor.FieldID, field.TypeInt64), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _spec.Edges.Add = append(_spec.Edges.Add, edge) + } + _node = &ChannelMonitorRequestTemplate{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{channelmonitorrequesttemplate.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/client.go b/backend/ent/client.go index ebc7fc5e..df20ddfa 100644 --- a/backend/ent/client.go +++ b/backend/ent/client.go @@ -25,6 +25,7 @@ import ( "github.com/Wei-Shaw/sub2api/ent/channelmonitor" "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/errorpassthroughrule" "github.com/Wei-Shaw/sub2api/ent/group" "github.com/Wei-Shaw/sub2api/ent/idempotencyrecord" @@ -77,6 +78,8 @@ type Client struct { ChannelMonitorDailyRollup *ChannelMonitorDailyRollupClient // ChannelMonitorHistory is the client for interacting with the ChannelMonitorHistory builders. ChannelMonitorHistory *ChannelMonitorHistoryClient + // ChannelMonitorRequestTemplate is the client for interacting with the ChannelMonitorRequestTemplate builders. + ChannelMonitorRequestTemplate *ChannelMonitorRequestTemplateClient // ErrorPassthroughRule is the client for interacting with the ErrorPassthroughRule builders. ErrorPassthroughRule *ErrorPassthroughRuleClient // Group is the client for interacting with the Group builders. @@ -144,6 +147,7 @@ func (c *Client) init() { c.ChannelMonitor = NewChannelMonitorClient(c.config) c.ChannelMonitorDailyRollup = NewChannelMonitorDailyRollupClient(c.config) c.ChannelMonitorHistory = NewChannelMonitorHistoryClient(c.config) + c.ChannelMonitorRequestTemplate = NewChannelMonitorRequestTemplateClient(c.config) c.ErrorPassthroughRule = NewErrorPassthroughRuleClient(c.config) c.Group = NewGroupClient(c.config) c.IdempotencyRecord = NewIdempotencyRecordClient(c.config) @@ -257,41 +261,42 @@ func (c *Client) Tx(ctx context.Context) (*Tx, error) { cfg := c.config cfg.driver = tx return &Tx{ - ctx: ctx, - config: cfg, - APIKey: NewAPIKeyClient(cfg), - Account: NewAccountClient(cfg), - AccountGroup: NewAccountGroupClient(cfg), - Announcement: NewAnnouncementClient(cfg), - AnnouncementRead: NewAnnouncementReadClient(cfg), - AuthIdentity: NewAuthIdentityClient(cfg), - AuthIdentityChannel: NewAuthIdentityChannelClient(cfg), - ChannelMonitor: NewChannelMonitorClient(cfg), - ChannelMonitorDailyRollup: NewChannelMonitorDailyRollupClient(cfg), - ChannelMonitorHistory: NewChannelMonitorHistoryClient(cfg), - ErrorPassthroughRule: NewErrorPassthroughRuleClient(cfg), - Group: NewGroupClient(cfg), - IdempotencyRecord: NewIdempotencyRecordClient(cfg), - IdentityAdoptionDecision: NewIdentityAdoptionDecisionClient(cfg), - PaymentAuditLog: NewPaymentAuditLogClient(cfg), - PaymentOrder: NewPaymentOrderClient(cfg), - PaymentProviderInstance: NewPaymentProviderInstanceClient(cfg), - PendingAuthSession: NewPendingAuthSessionClient(cfg), - PromoCode: NewPromoCodeClient(cfg), - PromoCodeUsage: NewPromoCodeUsageClient(cfg), - Proxy: NewProxyClient(cfg), - RedeemCode: NewRedeemCodeClient(cfg), - SecuritySecret: NewSecuritySecretClient(cfg), - Setting: NewSettingClient(cfg), - SubscriptionPlan: NewSubscriptionPlanClient(cfg), - TLSFingerprintProfile: NewTLSFingerprintProfileClient(cfg), - UsageCleanupTask: NewUsageCleanupTaskClient(cfg), - UsageLog: NewUsageLogClient(cfg), - User: NewUserClient(cfg), - UserAllowedGroup: NewUserAllowedGroupClient(cfg), - UserAttributeDefinition: NewUserAttributeDefinitionClient(cfg), - UserAttributeValue: NewUserAttributeValueClient(cfg), - UserSubscription: NewUserSubscriptionClient(cfg), + ctx: ctx, + config: cfg, + APIKey: NewAPIKeyClient(cfg), + Account: NewAccountClient(cfg), + AccountGroup: NewAccountGroupClient(cfg), + Announcement: NewAnnouncementClient(cfg), + AnnouncementRead: NewAnnouncementReadClient(cfg), + AuthIdentity: NewAuthIdentityClient(cfg), + AuthIdentityChannel: NewAuthIdentityChannelClient(cfg), + ChannelMonitor: NewChannelMonitorClient(cfg), + ChannelMonitorDailyRollup: NewChannelMonitorDailyRollupClient(cfg), + ChannelMonitorHistory: NewChannelMonitorHistoryClient(cfg), + ChannelMonitorRequestTemplate: NewChannelMonitorRequestTemplateClient(cfg), + ErrorPassthroughRule: NewErrorPassthroughRuleClient(cfg), + Group: NewGroupClient(cfg), + IdempotencyRecord: NewIdempotencyRecordClient(cfg), + IdentityAdoptionDecision: NewIdentityAdoptionDecisionClient(cfg), + PaymentAuditLog: NewPaymentAuditLogClient(cfg), + PaymentOrder: NewPaymentOrderClient(cfg), + PaymentProviderInstance: NewPaymentProviderInstanceClient(cfg), + PendingAuthSession: NewPendingAuthSessionClient(cfg), + PromoCode: NewPromoCodeClient(cfg), + PromoCodeUsage: NewPromoCodeUsageClient(cfg), + Proxy: NewProxyClient(cfg), + RedeemCode: NewRedeemCodeClient(cfg), + SecuritySecret: NewSecuritySecretClient(cfg), + Setting: NewSettingClient(cfg), + SubscriptionPlan: NewSubscriptionPlanClient(cfg), + TLSFingerprintProfile: NewTLSFingerprintProfileClient(cfg), + UsageCleanupTask: NewUsageCleanupTaskClient(cfg), + UsageLog: NewUsageLogClient(cfg), + User: NewUserClient(cfg), + UserAllowedGroup: NewUserAllowedGroupClient(cfg), + UserAttributeDefinition: NewUserAttributeDefinitionClient(cfg), + UserAttributeValue: NewUserAttributeValueClient(cfg), + UserSubscription: NewUserSubscriptionClient(cfg), }, nil } @@ -309,41 +314,42 @@ func (c *Client) BeginTx(ctx context.Context, opts *sql.TxOptions) (*Tx, error) cfg := c.config cfg.driver = &txDriver{tx: tx, drv: c.driver} return &Tx{ - ctx: ctx, - config: cfg, - APIKey: NewAPIKeyClient(cfg), - Account: NewAccountClient(cfg), - AccountGroup: NewAccountGroupClient(cfg), - Announcement: NewAnnouncementClient(cfg), - AnnouncementRead: NewAnnouncementReadClient(cfg), - AuthIdentity: NewAuthIdentityClient(cfg), - AuthIdentityChannel: NewAuthIdentityChannelClient(cfg), - ChannelMonitor: NewChannelMonitorClient(cfg), - ChannelMonitorDailyRollup: NewChannelMonitorDailyRollupClient(cfg), - ChannelMonitorHistory: NewChannelMonitorHistoryClient(cfg), - ErrorPassthroughRule: NewErrorPassthroughRuleClient(cfg), - Group: NewGroupClient(cfg), - IdempotencyRecord: NewIdempotencyRecordClient(cfg), - IdentityAdoptionDecision: NewIdentityAdoptionDecisionClient(cfg), - PaymentAuditLog: NewPaymentAuditLogClient(cfg), - PaymentOrder: NewPaymentOrderClient(cfg), - PaymentProviderInstance: NewPaymentProviderInstanceClient(cfg), - PendingAuthSession: NewPendingAuthSessionClient(cfg), - PromoCode: NewPromoCodeClient(cfg), - PromoCodeUsage: NewPromoCodeUsageClient(cfg), - Proxy: NewProxyClient(cfg), - RedeemCode: NewRedeemCodeClient(cfg), - SecuritySecret: NewSecuritySecretClient(cfg), - Setting: NewSettingClient(cfg), - SubscriptionPlan: NewSubscriptionPlanClient(cfg), - TLSFingerprintProfile: NewTLSFingerprintProfileClient(cfg), - UsageCleanupTask: NewUsageCleanupTaskClient(cfg), - UsageLog: NewUsageLogClient(cfg), - User: NewUserClient(cfg), - UserAllowedGroup: NewUserAllowedGroupClient(cfg), - UserAttributeDefinition: NewUserAttributeDefinitionClient(cfg), - UserAttributeValue: NewUserAttributeValueClient(cfg), - UserSubscription: NewUserSubscriptionClient(cfg), + ctx: ctx, + config: cfg, + APIKey: NewAPIKeyClient(cfg), + Account: NewAccountClient(cfg), + AccountGroup: NewAccountGroupClient(cfg), + Announcement: NewAnnouncementClient(cfg), + AnnouncementRead: NewAnnouncementReadClient(cfg), + AuthIdentity: NewAuthIdentityClient(cfg), + AuthIdentityChannel: NewAuthIdentityChannelClient(cfg), + ChannelMonitor: NewChannelMonitorClient(cfg), + ChannelMonitorDailyRollup: NewChannelMonitorDailyRollupClient(cfg), + ChannelMonitorHistory: NewChannelMonitorHistoryClient(cfg), + ChannelMonitorRequestTemplate: NewChannelMonitorRequestTemplateClient(cfg), + ErrorPassthroughRule: NewErrorPassthroughRuleClient(cfg), + Group: NewGroupClient(cfg), + IdempotencyRecord: NewIdempotencyRecordClient(cfg), + IdentityAdoptionDecision: NewIdentityAdoptionDecisionClient(cfg), + PaymentAuditLog: NewPaymentAuditLogClient(cfg), + PaymentOrder: NewPaymentOrderClient(cfg), + PaymentProviderInstance: NewPaymentProviderInstanceClient(cfg), + PendingAuthSession: NewPendingAuthSessionClient(cfg), + PromoCode: NewPromoCodeClient(cfg), + PromoCodeUsage: NewPromoCodeUsageClient(cfg), + Proxy: NewProxyClient(cfg), + RedeemCode: NewRedeemCodeClient(cfg), + SecuritySecret: NewSecuritySecretClient(cfg), + Setting: NewSettingClient(cfg), + SubscriptionPlan: NewSubscriptionPlanClient(cfg), + TLSFingerprintProfile: NewTLSFingerprintProfileClient(cfg), + UsageCleanupTask: NewUsageCleanupTaskClient(cfg), + UsageLog: NewUsageLogClient(cfg), + User: NewUserClient(cfg), + UserAllowedGroup: NewUserAllowedGroupClient(cfg), + UserAttributeDefinition: NewUserAttributeDefinitionClient(cfg), + UserAttributeValue: NewUserAttributeValueClient(cfg), + UserSubscription: NewUserSubscriptionClient(cfg), }, nil } @@ -375,8 +381,9 @@ func (c *Client) Use(hooks ...Hook) { for _, n := range []interface{ Use(...Hook) }{ c.APIKey, c.Account, c.AccountGroup, c.Announcement, c.AnnouncementRead, c.AuthIdentity, c.AuthIdentityChannel, c.ChannelMonitor, - c.ChannelMonitorDailyRollup, c.ChannelMonitorHistory, c.ErrorPassthroughRule, - c.Group, c.IdempotencyRecord, c.IdentityAdoptionDecision, c.PaymentAuditLog, + c.ChannelMonitorDailyRollup, c.ChannelMonitorHistory, + c.ChannelMonitorRequestTemplate, 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, @@ -393,8 +400,9 @@ func (c *Client) Intercept(interceptors ...Interceptor) { for _, n := range []interface{ Intercept(...Interceptor) }{ c.APIKey, c.Account, c.AccountGroup, c.Announcement, c.AnnouncementRead, c.AuthIdentity, c.AuthIdentityChannel, c.ChannelMonitor, - c.ChannelMonitorDailyRollup, c.ChannelMonitorHistory, c.ErrorPassthroughRule, - c.Group, c.IdempotencyRecord, c.IdentityAdoptionDecision, c.PaymentAuditLog, + c.ChannelMonitorDailyRollup, c.ChannelMonitorHistory, + c.ChannelMonitorRequestTemplate, 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, @@ -428,6 +436,8 @@ func (c *Client) Mutate(ctx context.Context, m Mutation) (Value, error) { return c.ChannelMonitorDailyRollup.mutate(ctx, m) case *ChannelMonitorHistoryMutation: return c.ChannelMonitorHistory.mutate(ctx, m) + case *ChannelMonitorRequestTemplateMutation: + return c.ChannelMonitorRequestTemplate.mutate(ctx, m) case *ErrorPassthroughRuleMutation: return c.ErrorPassthroughRule.mutate(ctx, m) case *GroupMutation: @@ -1761,6 +1771,22 @@ func (c *ChannelMonitorClient) QueryDailyRollups(_m *ChannelMonitor) *ChannelMon return query } +// QueryRequestTemplate queries the request_template edge of a ChannelMonitor. +func (c *ChannelMonitorClient) QueryRequestTemplate(_m *ChannelMonitor) *ChannelMonitorRequestTemplateQuery { + query := (&ChannelMonitorRequestTemplateClient{config: c.config}).Query() + query.path = func(context.Context) (fromV *sql.Selector, _ error) { + id := _m.ID + step := sqlgraph.NewStep( + sqlgraph.From(channelmonitor.Table, channelmonitor.FieldID, id), + sqlgraph.To(channelmonitorrequesttemplate.Table, channelmonitorrequesttemplate.FieldID), + sqlgraph.Edge(sqlgraph.M2O, false, channelmonitor.RequestTemplateTable, channelmonitor.RequestTemplateColumn), + ) + fromV = sqlgraph.Neighbors(_m.driver.Dialect(), step) + return fromV, nil + } + return query +} + // Hooks returns the client hooks. func (c *ChannelMonitorClient) Hooks() []Hook { return c.hooks.ChannelMonitor @@ -2084,6 +2110,155 @@ func (c *ChannelMonitorHistoryClient) mutate(ctx context.Context, m *ChannelMoni } } +// ChannelMonitorRequestTemplateClient is a client for the ChannelMonitorRequestTemplate schema. +type ChannelMonitorRequestTemplateClient struct { + config +} + +// NewChannelMonitorRequestTemplateClient returns a client for the ChannelMonitorRequestTemplate from the given config. +func NewChannelMonitorRequestTemplateClient(c config) *ChannelMonitorRequestTemplateClient { + return &ChannelMonitorRequestTemplateClient{config: c} +} + +// Use adds a list of mutation hooks to the hooks stack. +// A call to `Use(f, g, h)` equals to `channelmonitorrequesttemplate.Hooks(f(g(h())))`. +func (c *ChannelMonitorRequestTemplateClient) Use(hooks ...Hook) { + c.hooks.ChannelMonitorRequestTemplate = append(c.hooks.ChannelMonitorRequestTemplate, hooks...) +} + +// Intercept adds a list of query interceptors to the interceptors stack. +// A call to `Intercept(f, g, h)` equals to `channelmonitorrequesttemplate.Intercept(f(g(h())))`. +func (c *ChannelMonitorRequestTemplateClient) Intercept(interceptors ...Interceptor) { + c.inters.ChannelMonitorRequestTemplate = append(c.inters.ChannelMonitorRequestTemplate, interceptors...) +} + +// Create returns a builder for creating a ChannelMonitorRequestTemplate entity. +func (c *ChannelMonitorRequestTemplateClient) Create() *ChannelMonitorRequestTemplateCreate { + mutation := newChannelMonitorRequestTemplateMutation(c.config, OpCreate) + return &ChannelMonitorRequestTemplateCreate{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// CreateBulk returns a builder for creating a bulk of ChannelMonitorRequestTemplate entities. +func (c *ChannelMonitorRequestTemplateClient) CreateBulk(builders ...*ChannelMonitorRequestTemplateCreate) *ChannelMonitorRequestTemplateCreateBulk { + return &ChannelMonitorRequestTemplateCreateBulk{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 *ChannelMonitorRequestTemplateClient) MapCreateBulk(slice any, setFunc func(*ChannelMonitorRequestTemplateCreate, int)) *ChannelMonitorRequestTemplateCreateBulk { + rv := reflect.ValueOf(slice) + if rv.Kind() != reflect.Slice { + return &ChannelMonitorRequestTemplateCreateBulk{err: fmt.Errorf("calling to ChannelMonitorRequestTemplateClient.MapCreateBulk with wrong type %T, need slice", slice)} + } + builders := make([]*ChannelMonitorRequestTemplateCreate, rv.Len()) + for i := 0; i < rv.Len(); i++ { + builders[i] = c.Create() + setFunc(builders[i], i) + } + return &ChannelMonitorRequestTemplateCreateBulk{config: c.config, builders: builders} +} + +// Update returns an update builder for ChannelMonitorRequestTemplate. +func (c *ChannelMonitorRequestTemplateClient) Update() *ChannelMonitorRequestTemplateUpdate { + mutation := newChannelMonitorRequestTemplateMutation(c.config, OpUpdate) + return &ChannelMonitorRequestTemplateUpdate{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// UpdateOne returns an update builder for the given entity. +func (c *ChannelMonitorRequestTemplateClient) UpdateOne(_m *ChannelMonitorRequestTemplate) *ChannelMonitorRequestTemplateUpdateOne { + mutation := newChannelMonitorRequestTemplateMutation(c.config, OpUpdateOne, withChannelMonitorRequestTemplate(_m)) + return &ChannelMonitorRequestTemplateUpdateOne{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// UpdateOneID returns an update builder for the given id. +func (c *ChannelMonitorRequestTemplateClient) UpdateOneID(id int64) *ChannelMonitorRequestTemplateUpdateOne { + mutation := newChannelMonitorRequestTemplateMutation(c.config, OpUpdateOne, withChannelMonitorRequestTemplateID(id)) + return &ChannelMonitorRequestTemplateUpdateOne{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// Delete returns a delete builder for ChannelMonitorRequestTemplate. +func (c *ChannelMonitorRequestTemplateClient) Delete() *ChannelMonitorRequestTemplateDelete { + mutation := newChannelMonitorRequestTemplateMutation(c.config, OpDelete) + return &ChannelMonitorRequestTemplateDelete{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// DeleteOne returns a builder for deleting the given entity. +func (c *ChannelMonitorRequestTemplateClient) DeleteOne(_m *ChannelMonitorRequestTemplate) *ChannelMonitorRequestTemplateDeleteOne { + return c.DeleteOneID(_m.ID) +} + +// DeleteOneID returns a builder for deleting the given entity by its id. +func (c *ChannelMonitorRequestTemplateClient) DeleteOneID(id int64) *ChannelMonitorRequestTemplateDeleteOne { + builder := c.Delete().Where(channelmonitorrequesttemplate.ID(id)) + builder.mutation.id = &id + builder.mutation.op = OpDeleteOne + return &ChannelMonitorRequestTemplateDeleteOne{builder} +} + +// Query returns a query builder for ChannelMonitorRequestTemplate. +func (c *ChannelMonitorRequestTemplateClient) Query() *ChannelMonitorRequestTemplateQuery { + return &ChannelMonitorRequestTemplateQuery{ + config: c.config, + ctx: &QueryContext{Type: TypeChannelMonitorRequestTemplate}, + inters: c.Interceptors(), + } +} + +// Get returns a ChannelMonitorRequestTemplate entity by its id. +func (c *ChannelMonitorRequestTemplateClient) Get(ctx context.Context, id int64) (*ChannelMonitorRequestTemplate, error) { + return c.Query().Where(channelmonitorrequesttemplate.ID(id)).Only(ctx) +} + +// GetX is like Get, but panics if an error occurs. +func (c *ChannelMonitorRequestTemplateClient) GetX(ctx context.Context, id int64) *ChannelMonitorRequestTemplate { + obj, err := c.Get(ctx, id) + if err != nil { + panic(err) + } + return obj +} + +// QueryMonitors queries the monitors edge of a ChannelMonitorRequestTemplate. +func (c *ChannelMonitorRequestTemplateClient) QueryMonitors(_m *ChannelMonitorRequestTemplate) *ChannelMonitorQuery { + query := (&ChannelMonitorClient{config: c.config}).Query() + query.path = func(context.Context) (fromV *sql.Selector, _ error) { + id := _m.ID + step := sqlgraph.NewStep( + sqlgraph.From(channelmonitorrequesttemplate.Table, channelmonitorrequesttemplate.FieldID, id), + sqlgraph.To(channelmonitor.Table, channelmonitor.FieldID), + sqlgraph.Edge(sqlgraph.O2M, true, channelmonitorrequesttemplate.MonitorsTable, channelmonitorrequesttemplate.MonitorsColumn), + ) + fromV = sqlgraph.Neighbors(_m.driver.Dialect(), step) + return fromV, nil + } + return query +} + +// Hooks returns the client hooks. +func (c *ChannelMonitorRequestTemplateClient) Hooks() []Hook { + return c.hooks.ChannelMonitorRequestTemplate +} + +// Interceptors returns the client interceptors. +func (c *ChannelMonitorRequestTemplateClient) Interceptors() []Interceptor { + return c.inters.ChannelMonitorRequestTemplate +} + +func (c *ChannelMonitorRequestTemplateClient) mutate(ctx context.Context, m *ChannelMonitorRequestTemplateMutation) (Value, error) { + switch m.Op() { + case OpCreate: + return (&ChannelMonitorRequestTemplateCreate{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx) + case OpUpdate: + return (&ChannelMonitorRequestTemplateUpdate{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx) + case OpUpdateOne: + return (&ChannelMonitorRequestTemplateUpdateOne{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx) + case OpDelete, OpDeleteOne: + return (&ChannelMonitorRequestTemplateDelete{config: c.config, hooks: c.Hooks(), mutation: m}).Exec(ctx) + default: + return nil, fmt.Errorf("ent: unknown ChannelMonitorRequestTemplate mutation op: %q", m.Op()) + } +} + // ErrorPassthroughRuleClient is a client for the ErrorPassthroughRule schema. type ErrorPassthroughRuleClient struct { config @@ -5845,22 +6020,22 @@ type ( hooks struct { APIKey, Account, AccountGroup, Announcement, AnnouncementRead, AuthIdentity, AuthIdentityChannel, ChannelMonitor, ChannelMonitorDailyRollup, - ChannelMonitorHistory, ErrorPassthroughRule, Group, IdempotencyRecord, - IdentityAdoptionDecision, PaymentAuditLog, PaymentOrder, - PaymentProviderInstance, PendingAuthSession, PromoCode, PromoCodeUsage, Proxy, - RedeemCode, SecuritySecret, Setting, SubscriptionPlan, TLSFingerprintProfile, - UsageCleanupTask, UsageLog, User, UserAllowedGroup, UserAttributeDefinition, - UserAttributeValue, UserSubscription []ent.Hook + ChannelMonitorHistory, ChannelMonitorRequestTemplate, ErrorPassthroughRule, + Group, IdempotencyRecord, IdentityAdoptionDecision, PaymentAuditLog, + PaymentOrder, PaymentProviderInstance, PendingAuthSession, PromoCode, + PromoCodeUsage, Proxy, RedeemCode, SecuritySecret, Setting, SubscriptionPlan, + TLSFingerprintProfile, UsageCleanupTask, UsageLog, User, UserAllowedGroup, + UserAttributeDefinition, UserAttributeValue, UserSubscription []ent.Hook } inters struct { APIKey, Account, AccountGroup, Announcement, AnnouncementRead, AuthIdentity, AuthIdentityChannel, ChannelMonitor, ChannelMonitorDailyRollup, - ChannelMonitorHistory, ErrorPassthroughRule, Group, IdempotencyRecord, - IdentityAdoptionDecision, PaymentAuditLog, PaymentOrder, - PaymentProviderInstance, PendingAuthSession, PromoCode, PromoCodeUsage, Proxy, - RedeemCode, SecuritySecret, Setting, SubscriptionPlan, TLSFingerprintProfile, - UsageCleanupTask, UsageLog, User, UserAllowedGroup, UserAttributeDefinition, - UserAttributeValue, UserSubscription []ent.Interceptor + ChannelMonitorHistory, ChannelMonitorRequestTemplate, ErrorPassthroughRule, + Group, IdempotencyRecord, IdentityAdoptionDecision, PaymentAuditLog, + PaymentOrder, PaymentProviderInstance, PendingAuthSession, PromoCode, + PromoCodeUsage, Proxy, RedeemCode, SecuritySecret, Setting, SubscriptionPlan, + TLSFingerprintProfile, UsageCleanupTask, UsageLog, User, UserAllowedGroup, + UserAttributeDefinition, UserAttributeValue, UserSubscription []ent.Interceptor } ) diff --git a/backend/ent/ent.go b/backend/ent/ent.go index 71d17624..c9fcc314 100644 --- a/backend/ent/ent.go +++ b/backend/ent/ent.go @@ -22,6 +22,7 @@ import ( "github.com/Wei-Shaw/sub2api/ent/channelmonitor" "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/errorpassthroughrule" "github.com/Wei-Shaw/sub2api/ent/group" "github.com/Wei-Shaw/sub2api/ent/idempotencyrecord" @@ -105,39 +106,40 @@ var ( func checkColumn(t, c string) error { initCheck.Do(func() { columnCheck = sql.NewColumnCheck(map[string]func(string) bool{ - apikey.Table: apikey.ValidColumn, - account.Table: account.ValidColumn, - accountgroup.Table: accountgroup.ValidColumn, - announcement.Table: announcement.ValidColumn, - announcementread.Table: announcementread.ValidColumn, - authidentity.Table: authidentity.ValidColumn, - authidentitychannel.Table: authidentitychannel.ValidColumn, - channelmonitor.Table: channelmonitor.ValidColumn, - channelmonitordailyrollup.Table: channelmonitordailyrollup.ValidColumn, - channelmonitorhistory.Table: channelmonitorhistory.ValidColumn, - errorpassthroughrule.Table: errorpassthroughrule.ValidColumn, - group.Table: group.ValidColumn, - idempotencyrecord.Table: idempotencyrecord.ValidColumn, - identityadoptiondecision.Table: identityadoptiondecision.ValidColumn, - paymentauditlog.Table: paymentauditlog.ValidColumn, - paymentorder.Table: paymentorder.ValidColumn, - paymentproviderinstance.Table: paymentproviderinstance.ValidColumn, - pendingauthsession.Table: pendingauthsession.ValidColumn, - promocode.Table: promocode.ValidColumn, - promocodeusage.Table: promocodeusage.ValidColumn, - proxy.Table: proxy.ValidColumn, - redeemcode.Table: redeemcode.ValidColumn, - securitysecret.Table: securitysecret.ValidColumn, - setting.Table: setting.ValidColumn, - subscriptionplan.Table: subscriptionplan.ValidColumn, - tlsfingerprintprofile.Table: tlsfingerprintprofile.ValidColumn, - usagecleanuptask.Table: usagecleanuptask.ValidColumn, - usagelog.Table: usagelog.ValidColumn, - user.Table: user.ValidColumn, - userallowedgroup.Table: userallowedgroup.ValidColumn, - userattributedefinition.Table: userattributedefinition.ValidColumn, - userattributevalue.Table: userattributevalue.ValidColumn, - usersubscription.Table: usersubscription.ValidColumn, + apikey.Table: apikey.ValidColumn, + account.Table: account.ValidColumn, + accountgroup.Table: accountgroup.ValidColumn, + announcement.Table: announcement.ValidColumn, + announcementread.Table: announcementread.ValidColumn, + authidentity.Table: authidentity.ValidColumn, + authidentitychannel.Table: authidentitychannel.ValidColumn, + channelmonitor.Table: channelmonitor.ValidColumn, + channelmonitordailyrollup.Table: channelmonitordailyrollup.ValidColumn, + channelmonitorhistory.Table: channelmonitorhistory.ValidColumn, + channelmonitorrequesttemplate.Table: channelmonitorrequesttemplate.ValidColumn, + errorpassthroughrule.Table: errorpassthroughrule.ValidColumn, + group.Table: group.ValidColumn, + idempotencyrecord.Table: idempotencyrecord.ValidColumn, + identityadoptiondecision.Table: identityadoptiondecision.ValidColumn, + paymentauditlog.Table: paymentauditlog.ValidColumn, + paymentorder.Table: paymentorder.ValidColumn, + paymentproviderinstance.Table: paymentproviderinstance.ValidColumn, + pendingauthsession.Table: pendingauthsession.ValidColumn, + promocode.Table: promocode.ValidColumn, + promocodeusage.Table: promocodeusage.ValidColumn, + proxy.Table: proxy.ValidColumn, + redeemcode.Table: redeemcode.ValidColumn, + securitysecret.Table: securitysecret.ValidColumn, + setting.Table: setting.ValidColumn, + subscriptionplan.Table: subscriptionplan.ValidColumn, + tlsfingerprintprofile.Table: tlsfingerprintprofile.ValidColumn, + usagecleanuptask.Table: usagecleanuptask.ValidColumn, + usagelog.Table: usagelog.ValidColumn, + user.Table: user.ValidColumn, + userallowedgroup.Table: userallowedgroup.ValidColumn, + userattributedefinition.Table: userattributedefinition.ValidColumn, + userattributevalue.Table: userattributevalue.ValidColumn, + usersubscription.Table: usersubscription.ValidColumn, }) }) return columnCheck(t, c) diff --git a/backend/ent/hook/hook.go b/backend/ent/hook/hook.go index ff86c90d..414eba24 100644 --- a/backend/ent/hook/hook.go +++ b/backend/ent/hook/hook.go @@ -129,6 +129,18 @@ func (f ChannelMonitorHistoryFunc) Mutate(ctx context.Context, m ent.Mutation) ( return nil, fmt.Errorf("unexpected mutation type %T. expect *ent.ChannelMonitorHistoryMutation", m) } +// The ChannelMonitorRequestTemplateFunc type is an adapter to allow the use of ordinary +// function as ChannelMonitorRequestTemplate mutator. +type ChannelMonitorRequestTemplateFunc func(context.Context, *ent.ChannelMonitorRequestTemplateMutation) (ent.Value, error) + +// Mutate calls f(ctx, m). +func (f ChannelMonitorRequestTemplateFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, error) { + if mv, ok := m.(*ent.ChannelMonitorRequestTemplateMutation); ok { + return f(ctx, mv) + } + return nil, fmt.Errorf("unexpected mutation type %T. expect *ent.ChannelMonitorRequestTemplateMutation", 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 0c83fc38..95b68e09 100644 --- a/backend/ent/intercept/intercept.go +++ b/backend/ent/intercept/intercept.go @@ -18,6 +18,7 @@ import ( "github.com/Wei-Shaw/sub2api/ent/channelmonitor" "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/errorpassthroughrule" "github.com/Wei-Shaw/sub2api/ent/group" "github.com/Wei-Shaw/sub2api/ent/idempotencyrecord" @@ -370,6 +371,33 @@ func (f TraverseChannelMonitorHistory) Traverse(ctx context.Context, q ent.Query return fmt.Errorf("unexpected query type %T. expect *ent.ChannelMonitorHistoryQuery", q) } +// The ChannelMonitorRequestTemplateFunc type is an adapter to allow the use of ordinary function as a Querier. +type ChannelMonitorRequestTemplateFunc func(context.Context, *ent.ChannelMonitorRequestTemplateQuery) (ent.Value, error) + +// Query calls f(ctx, q). +func (f ChannelMonitorRequestTemplateFunc) Query(ctx context.Context, q ent.Query) (ent.Value, error) { + if q, ok := q.(*ent.ChannelMonitorRequestTemplateQuery); ok { + return f(ctx, q) + } + return nil, fmt.Errorf("unexpected query type %T. expect *ent.ChannelMonitorRequestTemplateQuery", q) +} + +// The TraverseChannelMonitorRequestTemplate type is an adapter to allow the use of ordinary function as Traverser. +type TraverseChannelMonitorRequestTemplate func(context.Context, *ent.ChannelMonitorRequestTemplateQuery) error + +// Intercept is a dummy implementation of Intercept that returns the next Querier in the pipeline. +func (f TraverseChannelMonitorRequestTemplate) Intercept(next ent.Querier) ent.Querier { + return next +} + +// Traverse calls f(ctx, q). +func (f TraverseChannelMonitorRequestTemplate) Traverse(ctx context.Context, q ent.Query) error { + if q, ok := q.(*ent.ChannelMonitorRequestTemplateQuery); ok { + return f(ctx, q) + } + return fmt.Errorf("unexpected query type %T. expect *ent.ChannelMonitorRequestTemplateQuery", 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) @@ -1014,6 +1042,8 @@ func NewQuery(q ent.Query) (Query, error) { return &query[*ent.ChannelMonitorDailyRollupQuery, predicate.ChannelMonitorDailyRollup, channelmonitordailyrollup.OrderOption]{typ: ent.TypeChannelMonitorDailyRollup, tq: q}, nil case *ent.ChannelMonitorHistoryQuery: 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.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 dba43ddf..38366e95 100644 --- a/backend/ent/migrate/schema.go +++ b/backend/ent/migrate/schema.go @@ -437,12 +437,24 @@ var ( {Name: "interval_seconds", Type: field.TypeInt}, {Name: "last_checked_at", Type: field.TypeTime, Nullable: true}, {Name: "created_by", Type: field.TypeInt64}, + {Name: "extra_headers", Type: field.TypeJSON}, + {Name: "body_override_mode", Type: field.TypeString, Size: 10, Default: "off"}, + {Name: "body_override", Type: field.TypeJSON, Nullable: true}, + {Name: "template_id", Type: field.TypeInt64, Nullable: true}, } // ChannelMonitorsTable holds the schema information for the "channel_monitors" table. ChannelMonitorsTable = &schema.Table{ Name: "channel_monitors", Columns: ChannelMonitorsColumns, PrimaryKey: []*schema.Column{ChannelMonitorsColumns[0]}, + ForeignKeys: []*schema.ForeignKey{ + { + Symbol: "channel_monitors_channel_monitor_request_templates_request_template", + Columns: []*schema.Column{ChannelMonitorsColumns[17]}, + RefColumns: []*schema.Column{ChannelMonitorRequestTemplatesColumns[0]}, + OnDelete: schema.SetNull, + }, + }, Indexes: []*schema.Index{ { Name: "channelmonitor_enabled_last_checked_at", @@ -459,6 +471,11 @@ var ( Unique: false, Columns: []*schema.Column{ChannelMonitorsColumns[9]}, }, + { + Name: "channelmonitor_template_id", + Unique: false, + Columns: []*schema.Column{ChannelMonitorsColumns[17]}, + }, }, } // ChannelMonitorDailyRollupsColumns holds the columns for the "channel_monitor_daily_rollups" table. @@ -542,6 +559,31 @@ var ( }, }, } + // ChannelMonitorRequestTemplatesColumns holds the columns for the "channel_monitor_request_templates" table. + ChannelMonitorRequestTemplatesColumns = []*schema.Column{ + {Name: "id", Type: field.TypeInt64, Increment: true}, + {Name: "created_at", Type: field.TypeTime, SchemaType: map[string]string{"postgres": "timestamptz"}}, + {Name: "updated_at", Type: field.TypeTime, SchemaType: map[string]string{"postgres": "timestamptz"}}, + {Name: "name", Type: field.TypeString, Size: 100}, + {Name: "provider", Type: field.TypeEnum, Enums: []string{"openai", "anthropic", "gemini"}}, + {Name: "description", Type: field.TypeString, Nullable: true, Size: 500, Default: ""}, + {Name: "extra_headers", Type: field.TypeJSON}, + {Name: "body_override_mode", Type: field.TypeString, Size: 10, Default: "off"}, + {Name: "body_override", Type: field.TypeJSON, Nullable: true}, + } + // ChannelMonitorRequestTemplatesTable holds the schema information for the "channel_monitor_request_templates" table. + ChannelMonitorRequestTemplatesTable = &schema.Table{ + Name: "channel_monitor_request_templates", + Columns: ChannelMonitorRequestTemplatesColumns, + PrimaryKey: []*schema.Column{ChannelMonitorRequestTemplatesColumns[0]}, + Indexes: []*schema.Index{ + { + Name: "channelmonitorrequesttemplate_provider_name", + Unique: true, + Columns: []*schema.Column{ChannelMonitorRequestTemplatesColumns[4], ChannelMonitorRequestTemplatesColumns[3]}, + }, + }, + } // ErrorPassthroughRulesColumns holds the columns for the "error_passthrough_rules" table. ErrorPassthroughRulesColumns = []*schema.Column{ {Name: "id", Type: field.TypeInt64, Increment: true}, @@ -1644,6 +1686,7 @@ var ( ChannelMonitorsTable, ChannelMonitorDailyRollupsTable, ChannelMonitorHistoriesTable, + ChannelMonitorRequestTemplatesTable, ErrorPassthroughRulesTable, GroupsTable, IdempotencyRecordsTable, @@ -1701,6 +1744,7 @@ func init() { AuthIdentityChannelsTable.Annotation = &entsql.Annotation{ Table: "auth_identity_channels", } + ChannelMonitorsTable.ForeignKeys[0].RefTable = ChannelMonitorRequestTemplatesTable ChannelMonitorsTable.Annotation = &entsql.Annotation{ Table: "channel_monitors", } @@ -1712,6 +1756,9 @@ func init() { ChannelMonitorHistoriesTable.Annotation = &entsql.Annotation{ Table: "channel_monitor_histories", } + ChannelMonitorRequestTemplatesTable.Annotation = &entsql.Annotation{ + Table: "channel_monitor_request_templates", + } ErrorPassthroughRulesTable.Annotation = &entsql.Annotation{ Table: "error_passthrough_rules", } diff --git a/backend/ent/mutation.go b/backend/ent/mutation.go index 43e52371..568b3eb5 100644 --- a/backend/ent/mutation.go +++ b/backend/ent/mutation.go @@ -22,6 +22,7 @@ import ( "github.com/Wei-Shaw/sub2api/ent/channelmonitor" "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/errorpassthroughrule" "github.com/Wei-Shaw/sub2api/ent/group" "github.com/Wei-Shaw/sub2api/ent/idempotencyrecord" @@ -58,39 +59,40 @@ const ( OpUpdateOne = ent.OpUpdateOne // Node types. - TypeAPIKey = "APIKey" - TypeAccount = "Account" - TypeAccountGroup = "AccountGroup" - TypeAnnouncement = "Announcement" - TypeAnnouncementRead = "AnnouncementRead" - TypeAuthIdentity = "AuthIdentity" - TypeAuthIdentityChannel = "AuthIdentityChannel" - TypeChannelMonitor = "ChannelMonitor" - TypeChannelMonitorDailyRollup = "ChannelMonitorDailyRollup" - TypeChannelMonitorHistory = "ChannelMonitorHistory" - TypeErrorPassthroughRule = "ErrorPassthroughRule" - TypeGroup = "Group" - TypeIdempotencyRecord = "IdempotencyRecord" - TypeIdentityAdoptionDecision = "IdentityAdoptionDecision" - TypePaymentAuditLog = "PaymentAuditLog" - TypePaymentOrder = "PaymentOrder" - TypePaymentProviderInstance = "PaymentProviderInstance" - TypePendingAuthSession = "PendingAuthSession" - TypePromoCode = "PromoCode" - TypePromoCodeUsage = "PromoCodeUsage" - TypeProxy = "Proxy" - TypeRedeemCode = "RedeemCode" - TypeSecuritySecret = "SecuritySecret" - TypeSetting = "Setting" - TypeSubscriptionPlan = "SubscriptionPlan" - TypeTLSFingerprintProfile = "TLSFingerprintProfile" - TypeUsageCleanupTask = "UsageCleanupTask" - TypeUsageLog = "UsageLog" - TypeUser = "User" - TypeUserAllowedGroup = "UserAllowedGroup" - TypeUserAttributeDefinition = "UserAttributeDefinition" - TypeUserAttributeValue = "UserAttributeValue" - TypeUserSubscription = "UserSubscription" + TypeAPIKey = "APIKey" + TypeAccount = "Account" + TypeAccountGroup = "AccountGroup" + TypeAnnouncement = "Announcement" + TypeAnnouncementRead = "AnnouncementRead" + TypeAuthIdentity = "AuthIdentity" + TypeAuthIdentityChannel = "AuthIdentityChannel" + TypeChannelMonitor = "ChannelMonitor" + TypeChannelMonitorDailyRollup = "ChannelMonitorDailyRollup" + TypeChannelMonitorHistory = "ChannelMonitorHistory" + TypeChannelMonitorRequestTemplate = "ChannelMonitorRequestTemplate" + TypeErrorPassthroughRule = "ErrorPassthroughRule" + TypeGroup = "Group" + TypeIdempotencyRecord = "IdempotencyRecord" + TypeIdentityAdoptionDecision = "IdentityAdoptionDecision" + TypePaymentAuditLog = "PaymentAuditLog" + TypePaymentOrder = "PaymentOrder" + TypePaymentProviderInstance = "PaymentProviderInstance" + TypePendingAuthSession = "PendingAuthSession" + TypePromoCode = "PromoCode" + TypePromoCodeUsage = "PromoCodeUsage" + TypeProxy = "Proxy" + TypeRedeemCode = "RedeemCode" + TypeSecuritySecret = "SecuritySecret" + TypeSetting = "Setting" + TypeSubscriptionPlan = "SubscriptionPlan" + TypeTLSFingerprintProfile = "TLSFingerprintProfile" + TypeUsageCleanupTask = "UsageCleanupTask" + TypeUsageLog = "UsageLog" + TypeUser = "User" + TypeUserAllowedGroup = "UserAllowedGroup" + TypeUserAttributeDefinition = "UserAttributeDefinition" + TypeUserAttributeValue = "UserAttributeValue" + TypeUserSubscription = "UserSubscription" ) // APIKeyMutation represents an operation that mutates the APIKey nodes in the graph. @@ -8743,35 +8745,40 @@ func (m *AuthIdentityChannelMutation) ResetEdge(name string) error { // ChannelMonitorMutation represents an operation that mutates the ChannelMonitor nodes in the graph. type ChannelMonitorMutation struct { config - op Op - typ string - id *int64 - created_at *time.Time - updated_at *time.Time - name *string - provider *channelmonitor.Provider - endpoint *string - api_key_encrypted *string - primary_model *string - extra_models *[]string - appendextra_models []string - group_name *string - enabled *bool - interval_seconds *int - addinterval_seconds *int - last_checked_at *time.Time - created_by *int64 - addcreated_by *int64 - clearedFields map[string]struct{} - history map[int64]struct{} - removedhistory map[int64]struct{} - clearedhistory bool - daily_rollups map[int64]struct{} - removeddaily_rollups map[int64]struct{} - cleareddaily_rollups bool - done bool - oldValue func(context.Context) (*ChannelMonitor, error) - predicates []predicate.ChannelMonitor + op Op + typ string + id *int64 + created_at *time.Time + updated_at *time.Time + name *string + provider *channelmonitor.Provider + endpoint *string + api_key_encrypted *string + primary_model *string + extra_models *[]string + appendextra_models []string + group_name *string + enabled *bool + interval_seconds *int + addinterval_seconds *int + last_checked_at *time.Time + created_by *int64 + addcreated_by *int64 + extra_headers *map[string]string + body_override_mode *string + body_override *map[string]interface{} + clearedFields map[string]struct{} + history map[int64]struct{} + removedhistory map[int64]struct{} + clearedhistory bool + daily_rollups map[int64]struct{} + removeddaily_rollups map[int64]struct{} + cleareddaily_rollups bool + request_template *int64 + clearedrequest_template bool + done bool + oldValue func(context.Context) (*ChannelMonitor, error) + predicates []predicate.ChannelMonitor } var _ ent.Mutation = (*ChannelMonitorMutation)(nil) @@ -9421,6 +9428,176 @@ func (m *ChannelMonitorMutation) ResetCreatedBy() { m.addcreated_by = nil } +// SetTemplateID sets the "template_id" field. +func (m *ChannelMonitorMutation) SetTemplateID(i int64) { + m.request_template = &i +} + +// TemplateID returns the value of the "template_id" field in the mutation. +func (m *ChannelMonitorMutation) TemplateID() (r int64, exists bool) { + v := m.request_template + if v == nil { + return + } + return *v, true +} + +// OldTemplateID returns the old "template_id" field's value of the ChannelMonitor entity. +// If the ChannelMonitor 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 *ChannelMonitorMutation) OldTemplateID(ctx context.Context) (v *int64, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldTemplateID is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldTemplateID requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldTemplateID: %w", err) + } + return oldValue.TemplateID, nil +} + +// ClearTemplateID clears the value of the "template_id" field. +func (m *ChannelMonitorMutation) ClearTemplateID() { + m.request_template = nil + m.clearedFields[channelmonitor.FieldTemplateID] = struct{}{} +} + +// TemplateIDCleared returns if the "template_id" field was cleared in this mutation. +func (m *ChannelMonitorMutation) TemplateIDCleared() bool { + _, ok := m.clearedFields[channelmonitor.FieldTemplateID] + return ok +} + +// ResetTemplateID resets all changes to the "template_id" field. +func (m *ChannelMonitorMutation) ResetTemplateID() { + m.request_template = nil + delete(m.clearedFields, channelmonitor.FieldTemplateID) +} + +// SetExtraHeaders sets the "extra_headers" field. +func (m *ChannelMonitorMutation) SetExtraHeaders(value map[string]string) { + m.extra_headers = &value +} + +// ExtraHeaders returns the value of the "extra_headers" field in the mutation. +func (m *ChannelMonitorMutation) ExtraHeaders() (r map[string]string, exists bool) { + v := m.extra_headers + if v == nil { + return + } + return *v, true +} + +// OldExtraHeaders returns the old "extra_headers" field's value of the ChannelMonitor entity. +// If the ChannelMonitor 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 *ChannelMonitorMutation) OldExtraHeaders(ctx context.Context) (v map[string]string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldExtraHeaders is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldExtraHeaders requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldExtraHeaders: %w", err) + } + return oldValue.ExtraHeaders, nil +} + +// ResetExtraHeaders resets all changes to the "extra_headers" field. +func (m *ChannelMonitorMutation) ResetExtraHeaders() { + m.extra_headers = nil +} + +// SetBodyOverrideMode sets the "body_override_mode" field. +func (m *ChannelMonitorMutation) SetBodyOverrideMode(s string) { + m.body_override_mode = &s +} + +// BodyOverrideMode returns the value of the "body_override_mode" field in the mutation. +func (m *ChannelMonitorMutation) BodyOverrideMode() (r string, exists bool) { + v := m.body_override_mode + if v == nil { + return + } + return *v, true +} + +// OldBodyOverrideMode returns the old "body_override_mode" field's value of the ChannelMonitor entity. +// If the ChannelMonitor 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 *ChannelMonitorMutation) OldBodyOverrideMode(ctx context.Context) (v string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldBodyOverrideMode is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldBodyOverrideMode requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldBodyOverrideMode: %w", err) + } + return oldValue.BodyOverrideMode, nil +} + +// ResetBodyOverrideMode resets all changes to the "body_override_mode" field. +func (m *ChannelMonitorMutation) ResetBodyOverrideMode() { + m.body_override_mode = nil +} + +// SetBodyOverride sets the "body_override" field. +func (m *ChannelMonitorMutation) SetBodyOverride(value map[string]interface{}) { + m.body_override = &value +} + +// BodyOverride returns the value of the "body_override" field in the mutation. +func (m *ChannelMonitorMutation) BodyOverride() (r map[string]interface{}, exists bool) { + v := m.body_override + if v == nil { + return + } + return *v, true +} + +// OldBodyOverride returns the old "body_override" field's value of the ChannelMonitor entity. +// If the ChannelMonitor 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 *ChannelMonitorMutation) OldBodyOverride(ctx context.Context) (v map[string]interface{}, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldBodyOverride is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldBodyOverride requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldBodyOverride: %w", err) + } + return oldValue.BodyOverride, nil +} + +// ClearBodyOverride clears the value of the "body_override" field. +func (m *ChannelMonitorMutation) ClearBodyOverride() { + m.body_override = nil + m.clearedFields[channelmonitor.FieldBodyOverride] = struct{}{} +} + +// BodyOverrideCleared returns if the "body_override" field was cleared in this mutation. +func (m *ChannelMonitorMutation) BodyOverrideCleared() bool { + _, ok := m.clearedFields[channelmonitor.FieldBodyOverride] + return ok +} + +// ResetBodyOverride resets all changes to the "body_override" field. +func (m *ChannelMonitorMutation) ResetBodyOverride() { + m.body_override = nil + delete(m.clearedFields, channelmonitor.FieldBodyOverride) +} + // AddHistoryIDs adds the "history" edge to the ChannelMonitorHistory entity by ids. func (m *ChannelMonitorMutation) AddHistoryIDs(ids ...int64) { if m.history == nil { @@ -9529,6 +9706,46 @@ func (m *ChannelMonitorMutation) ResetDailyRollups() { m.removeddaily_rollups = nil } +// SetRequestTemplateID sets the "request_template" edge to the ChannelMonitorRequestTemplate entity by id. +func (m *ChannelMonitorMutation) SetRequestTemplateID(id int64) { + m.request_template = &id +} + +// ClearRequestTemplate clears the "request_template" edge to the ChannelMonitorRequestTemplate entity. +func (m *ChannelMonitorMutation) ClearRequestTemplate() { + m.clearedrequest_template = true + m.clearedFields[channelmonitor.FieldTemplateID] = struct{}{} +} + +// RequestTemplateCleared reports if the "request_template" edge to the ChannelMonitorRequestTemplate entity was cleared. +func (m *ChannelMonitorMutation) RequestTemplateCleared() bool { + return m.TemplateIDCleared() || m.clearedrequest_template +} + +// RequestTemplateID returns the "request_template" edge ID in the mutation. +func (m *ChannelMonitorMutation) RequestTemplateID() (id int64, exists bool) { + if m.request_template != nil { + return *m.request_template, true + } + return +} + +// RequestTemplateIDs returns the "request_template" edge IDs in the mutation. +// Note that IDs always returns len(IDs) <= 1 for unique edges, and you should use +// RequestTemplateID instead. It exists only for internal usage by the builders. +func (m *ChannelMonitorMutation) RequestTemplateIDs() (ids []int64) { + if id := m.request_template; id != nil { + ids = append(ids, *id) + } + return +} + +// ResetRequestTemplate resets all changes to the "request_template" edge. +func (m *ChannelMonitorMutation) ResetRequestTemplate() { + m.request_template = nil + m.clearedrequest_template = false +} + // Where appends a list predicates to the ChannelMonitorMutation builder. func (m *ChannelMonitorMutation) Where(ps ...predicate.ChannelMonitor) { m.predicates = append(m.predicates, ps...) @@ -9563,7 +9780,7 @@ func (m *ChannelMonitorMutation) Type() string { // order to get all numeric fields that were incremented/decremented, call // AddedFields(). func (m *ChannelMonitorMutation) Fields() []string { - fields := make([]string, 0, 13) + fields := make([]string, 0, 17) if m.created_at != nil { fields = append(fields, channelmonitor.FieldCreatedAt) } @@ -9603,6 +9820,18 @@ func (m *ChannelMonitorMutation) Fields() []string { if m.created_by != nil { fields = append(fields, channelmonitor.FieldCreatedBy) } + if m.request_template != nil { + fields = append(fields, channelmonitor.FieldTemplateID) + } + if m.extra_headers != nil { + fields = append(fields, channelmonitor.FieldExtraHeaders) + } + if m.body_override_mode != nil { + fields = append(fields, channelmonitor.FieldBodyOverrideMode) + } + if m.body_override != nil { + fields = append(fields, channelmonitor.FieldBodyOverride) + } return fields } @@ -9637,6 +9866,14 @@ func (m *ChannelMonitorMutation) Field(name string) (ent.Value, bool) { return m.LastCheckedAt() case channelmonitor.FieldCreatedBy: return m.CreatedBy() + case channelmonitor.FieldTemplateID: + return m.TemplateID() + case channelmonitor.FieldExtraHeaders: + return m.ExtraHeaders() + case channelmonitor.FieldBodyOverrideMode: + return m.BodyOverrideMode() + case channelmonitor.FieldBodyOverride: + return m.BodyOverride() } return nil, false } @@ -9672,6 +9909,14 @@ func (m *ChannelMonitorMutation) OldField(ctx context.Context, name string) (ent return m.OldLastCheckedAt(ctx) case channelmonitor.FieldCreatedBy: return m.OldCreatedBy(ctx) + case channelmonitor.FieldTemplateID: + return m.OldTemplateID(ctx) + case channelmonitor.FieldExtraHeaders: + return m.OldExtraHeaders(ctx) + case channelmonitor.FieldBodyOverrideMode: + return m.OldBodyOverrideMode(ctx) + case channelmonitor.FieldBodyOverride: + return m.OldBodyOverride(ctx) } return nil, fmt.Errorf("unknown ChannelMonitor field %s", name) } @@ -9772,6 +10017,34 @@ func (m *ChannelMonitorMutation) SetField(name string, value ent.Value) error { } m.SetCreatedBy(v) return nil + case channelmonitor.FieldTemplateID: + v, ok := value.(int64) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetTemplateID(v) + return nil + case channelmonitor.FieldExtraHeaders: + v, ok := value.(map[string]string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetExtraHeaders(v) + return nil + case channelmonitor.FieldBodyOverrideMode: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetBodyOverrideMode(v) + return nil + case channelmonitor.FieldBodyOverride: + v, ok := value.(map[string]interface{}) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetBodyOverride(v) + return nil } return fmt.Errorf("unknown ChannelMonitor field %s", name) } @@ -9835,6 +10108,12 @@ func (m *ChannelMonitorMutation) ClearedFields() []string { if m.FieldCleared(channelmonitor.FieldLastCheckedAt) { fields = append(fields, channelmonitor.FieldLastCheckedAt) } + if m.FieldCleared(channelmonitor.FieldTemplateID) { + fields = append(fields, channelmonitor.FieldTemplateID) + } + if m.FieldCleared(channelmonitor.FieldBodyOverride) { + fields = append(fields, channelmonitor.FieldBodyOverride) + } return fields } @@ -9855,6 +10134,12 @@ func (m *ChannelMonitorMutation) ClearField(name string) error { case channelmonitor.FieldLastCheckedAt: m.ClearLastCheckedAt() return nil + case channelmonitor.FieldTemplateID: + m.ClearTemplateID() + return nil + case channelmonitor.FieldBodyOverride: + m.ClearBodyOverride() + return nil } return fmt.Errorf("unknown ChannelMonitor nullable field %s", name) } @@ -9902,19 +10187,34 @@ func (m *ChannelMonitorMutation) ResetField(name string) error { case channelmonitor.FieldCreatedBy: m.ResetCreatedBy() return nil + case channelmonitor.FieldTemplateID: + m.ResetTemplateID() + return nil + case channelmonitor.FieldExtraHeaders: + m.ResetExtraHeaders() + return nil + case channelmonitor.FieldBodyOverrideMode: + m.ResetBodyOverrideMode() + return nil + case channelmonitor.FieldBodyOverride: + m.ResetBodyOverride() + return nil } return fmt.Errorf("unknown ChannelMonitor field %s", name) } // AddedEdges returns all edge names that were set/added in this mutation. func (m *ChannelMonitorMutation) AddedEdges() []string { - edges := make([]string, 0, 2) + edges := make([]string, 0, 3) if m.history != nil { edges = append(edges, channelmonitor.EdgeHistory) } if m.daily_rollups != nil { edges = append(edges, channelmonitor.EdgeDailyRollups) } + if m.request_template != nil { + edges = append(edges, channelmonitor.EdgeRequestTemplate) + } return edges } @@ -9934,13 +10234,17 @@ func (m *ChannelMonitorMutation) AddedIDs(name string) []ent.Value { ids = append(ids, id) } return ids + case channelmonitor.EdgeRequestTemplate: + if id := m.request_template; id != nil { + return []ent.Value{*id} + } } return nil } // RemovedEdges returns all edge names that were removed in this mutation. func (m *ChannelMonitorMutation) RemovedEdges() []string { - edges := make([]string, 0, 2) + edges := make([]string, 0, 3) if m.removedhistory != nil { edges = append(edges, channelmonitor.EdgeHistory) } @@ -9972,13 +10276,16 @@ func (m *ChannelMonitorMutation) RemovedIDs(name string) []ent.Value { // ClearedEdges returns all edge names that were cleared in this mutation. func (m *ChannelMonitorMutation) ClearedEdges() []string { - edges := make([]string, 0, 2) + edges := make([]string, 0, 3) if m.clearedhistory { edges = append(edges, channelmonitor.EdgeHistory) } if m.cleareddaily_rollups { edges = append(edges, channelmonitor.EdgeDailyRollups) } + if m.clearedrequest_template { + edges = append(edges, channelmonitor.EdgeRequestTemplate) + } return edges } @@ -9990,6 +10297,8 @@ func (m *ChannelMonitorMutation) EdgeCleared(name string) bool { return m.clearedhistory case channelmonitor.EdgeDailyRollups: return m.cleareddaily_rollups + case channelmonitor.EdgeRequestTemplate: + return m.clearedrequest_template } return false } @@ -9998,6 +10307,9 @@ func (m *ChannelMonitorMutation) EdgeCleared(name string) bool { // if that edge is not defined in the schema. func (m *ChannelMonitorMutation) ClearEdge(name string) error { switch name { + case channelmonitor.EdgeRequestTemplate: + m.ClearRequestTemplate() + return nil } return fmt.Errorf("unknown ChannelMonitor unique edge %s", name) } @@ -10012,6 +10324,9 @@ func (m *ChannelMonitorMutation) ResetEdge(name string) error { case channelmonitor.EdgeDailyRollups: m.ResetDailyRollups() return nil + case channelmonitor.EdgeRequestTemplate: + m.ResetRequestTemplate() + return nil } return fmt.Errorf("unknown ChannelMonitor edge %s", name) } @@ -12266,6 +12581,844 @@ func (m *ChannelMonitorHistoryMutation) ResetEdge(name string) error { return fmt.Errorf("unknown ChannelMonitorHistory edge %s", name) } +// ChannelMonitorRequestTemplateMutation represents an operation that mutates the ChannelMonitorRequestTemplate nodes in the graph. +type ChannelMonitorRequestTemplateMutation struct { + config + op Op + typ string + id *int64 + created_at *time.Time + updated_at *time.Time + name *string + provider *channelmonitorrequesttemplate.Provider + description *string + extra_headers *map[string]string + body_override_mode *string + body_override *map[string]interface{} + clearedFields map[string]struct{} + monitors map[int64]struct{} + removedmonitors map[int64]struct{} + clearedmonitors bool + done bool + oldValue func(context.Context) (*ChannelMonitorRequestTemplate, error) + predicates []predicate.ChannelMonitorRequestTemplate +} + +var _ ent.Mutation = (*ChannelMonitorRequestTemplateMutation)(nil) + +// channelmonitorrequesttemplateOption allows management of the mutation configuration using functional options. +type channelmonitorrequesttemplateOption func(*ChannelMonitorRequestTemplateMutation) + +// newChannelMonitorRequestTemplateMutation creates new mutation for the ChannelMonitorRequestTemplate entity. +func newChannelMonitorRequestTemplateMutation(c config, op Op, opts ...channelmonitorrequesttemplateOption) *ChannelMonitorRequestTemplateMutation { + m := &ChannelMonitorRequestTemplateMutation{ + config: c, + op: op, + typ: TypeChannelMonitorRequestTemplate, + clearedFields: make(map[string]struct{}), + } + for _, opt := range opts { + opt(m) + } + return m +} + +// withChannelMonitorRequestTemplateID sets the ID field of the mutation. +func withChannelMonitorRequestTemplateID(id int64) channelmonitorrequesttemplateOption { + return func(m *ChannelMonitorRequestTemplateMutation) { + var ( + err error + once sync.Once + value *ChannelMonitorRequestTemplate + ) + m.oldValue = func(ctx context.Context) (*ChannelMonitorRequestTemplate, error) { + once.Do(func() { + if m.done { + err = errors.New("querying old values post mutation is not allowed") + } else { + value, err = m.Client().ChannelMonitorRequestTemplate.Get(ctx, id) + } + }) + return value, err + } + m.id = &id + } +} + +// withChannelMonitorRequestTemplate sets the old ChannelMonitorRequestTemplate of the mutation. +func withChannelMonitorRequestTemplate(node *ChannelMonitorRequestTemplate) channelmonitorrequesttemplateOption { + return func(m *ChannelMonitorRequestTemplateMutation) { + m.oldValue = func(context.Context) (*ChannelMonitorRequestTemplate, 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 ChannelMonitorRequestTemplateMutation) 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 ChannelMonitorRequestTemplateMutation) 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 *ChannelMonitorRequestTemplateMutation) 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 *ChannelMonitorRequestTemplateMutation) 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().ChannelMonitorRequestTemplate.Query().Where(m.predicates...).IDs(ctx) + default: + return nil, fmt.Errorf("IDs is not allowed on %s operations", m.op) + } +} + +// SetCreatedAt sets the "created_at" field. +func (m *ChannelMonitorRequestTemplateMutation) SetCreatedAt(t time.Time) { + m.created_at = &t +} + +// CreatedAt returns the value of the "created_at" field in the mutation. +func (m *ChannelMonitorRequestTemplateMutation) 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 ChannelMonitorRequestTemplate entity. +// If the ChannelMonitorRequestTemplate 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 *ChannelMonitorRequestTemplateMutation) 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 *ChannelMonitorRequestTemplateMutation) ResetCreatedAt() { + m.created_at = nil +} + +// SetUpdatedAt sets the "updated_at" field. +func (m *ChannelMonitorRequestTemplateMutation) SetUpdatedAt(t time.Time) { + m.updated_at = &t +} + +// UpdatedAt returns the value of the "updated_at" field in the mutation. +func (m *ChannelMonitorRequestTemplateMutation) 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 ChannelMonitorRequestTemplate entity. +// If the ChannelMonitorRequestTemplate 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 *ChannelMonitorRequestTemplateMutation) 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 *ChannelMonitorRequestTemplateMutation) ResetUpdatedAt() { + m.updated_at = nil +} + +// SetName sets the "name" field. +func (m *ChannelMonitorRequestTemplateMutation) SetName(s string) { + m.name = &s +} + +// Name returns the value of the "name" field in the mutation. +func (m *ChannelMonitorRequestTemplateMutation) Name() (r string, exists bool) { + v := m.name + if v == nil { + return + } + return *v, true +} + +// OldName returns the old "name" field's value of the ChannelMonitorRequestTemplate entity. +// If the ChannelMonitorRequestTemplate 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 *ChannelMonitorRequestTemplateMutation) OldName(ctx context.Context) (v string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldName is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldName requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldName: %w", err) + } + return oldValue.Name, nil +} + +// ResetName resets all changes to the "name" field. +func (m *ChannelMonitorRequestTemplateMutation) ResetName() { + m.name = nil +} + +// SetProvider sets the "provider" field. +func (m *ChannelMonitorRequestTemplateMutation) SetProvider(c channelmonitorrequesttemplate.Provider) { + m.provider = &c +} + +// Provider returns the value of the "provider" field in the mutation. +func (m *ChannelMonitorRequestTemplateMutation) Provider() (r channelmonitorrequesttemplate.Provider, exists bool) { + v := m.provider + if v == nil { + return + } + return *v, true +} + +// OldProvider returns the old "provider" field's value of the ChannelMonitorRequestTemplate entity. +// If the ChannelMonitorRequestTemplate 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 *ChannelMonitorRequestTemplateMutation) OldProvider(ctx context.Context) (v channelmonitorrequesttemplate.Provider, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldProvider is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldProvider requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldProvider: %w", err) + } + return oldValue.Provider, nil +} + +// ResetProvider resets all changes to the "provider" field. +func (m *ChannelMonitorRequestTemplateMutation) ResetProvider() { + m.provider = nil +} + +// SetDescription sets the "description" field. +func (m *ChannelMonitorRequestTemplateMutation) SetDescription(s string) { + m.description = &s +} + +// Description returns the value of the "description" field in the mutation. +func (m *ChannelMonitorRequestTemplateMutation) Description() (r string, exists bool) { + v := m.description + if v == nil { + return + } + return *v, true +} + +// OldDescription returns the old "description" field's value of the ChannelMonitorRequestTemplate entity. +// If the ChannelMonitorRequestTemplate 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 *ChannelMonitorRequestTemplateMutation) OldDescription(ctx context.Context) (v string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldDescription is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldDescription requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldDescription: %w", err) + } + return oldValue.Description, nil +} + +// ClearDescription clears the value of the "description" field. +func (m *ChannelMonitorRequestTemplateMutation) ClearDescription() { + m.description = nil + m.clearedFields[channelmonitorrequesttemplate.FieldDescription] = struct{}{} +} + +// DescriptionCleared returns if the "description" field was cleared in this mutation. +func (m *ChannelMonitorRequestTemplateMutation) DescriptionCleared() bool { + _, ok := m.clearedFields[channelmonitorrequesttemplate.FieldDescription] + return ok +} + +// ResetDescription resets all changes to the "description" field. +func (m *ChannelMonitorRequestTemplateMutation) ResetDescription() { + m.description = nil + delete(m.clearedFields, channelmonitorrequesttemplate.FieldDescription) +} + +// SetExtraHeaders sets the "extra_headers" field. +func (m *ChannelMonitorRequestTemplateMutation) SetExtraHeaders(value map[string]string) { + m.extra_headers = &value +} + +// ExtraHeaders returns the value of the "extra_headers" field in the mutation. +func (m *ChannelMonitorRequestTemplateMutation) ExtraHeaders() (r map[string]string, exists bool) { + v := m.extra_headers + if v == nil { + return + } + return *v, true +} + +// OldExtraHeaders returns the old "extra_headers" field's value of the ChannelMonitorRequestTemplate entity. +// If the ChannelMonitorRequestTemplate 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 *ChannelMonitorRequestTemplateMutation) OldExtraHeaders(ctx context.Context) (v map[string]string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldExtraHeaders is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldExtraHeaders requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldExtraHeaders: %w", err) + } + return oldValue.ExtraHeaders, nil +} + +// ResetExtraHeaders resets all changes to the "extra_headers" field. +func (m *ChannelMonitorRequestTemplateMutation) ResetExtraHeaders() { + m.extra_headers = nil +} + +// SetBodyOverrideMode sets the "body_override_mode" field. +func (m *ChannelMonitorRequestTemplateMutation) SetBodyOverrideMode(s string) { + m.body_override_mode = &s +} + +// BodyOverrideMode returns the value of the "body_override_mode" field in the mutation. +func (m *ChannelMonitorRequestTemplateMutation) BodyOverrideMode() (r string, exists bool) { + v := m.body_override_mode + if v == nil { + return + } + return *v, true +} + +// OldBodyOverrideMode returns the old "body_override_mode" field's value of the ChannelMonitorRequestTemplate entity. +// If the ChannelMonitorRequestTemplate 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 *ChannelMonitorRequestTemplateMutation) OldBodyOverrideMode(ctx context.Context) (v string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldBodyOverrideMode is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldBodyOverrideMode requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldBodyOverrideMode: %w", err) + } + return oldValue.BodyOverrideMode, nil +} + +// ResetBodyOverrideMode resets all changes to the "body_override_mode" field. +func (m *ChannelMonitorRequestTemplateMutation) ResetBodyOverrideMode() { + m.body_override_mode = nil +} + +// SetBodyOverride sets the "body_override" field. +func (m *ChannelMonitorRequestTemplateMutation) SetBodyOverride(value map[string]interface{}) { + m.body_override = &value +} + +// BodyOverride returns the value of the "body_override" field in the mutation. +func (m *ChannelMonitorRequestTemplateMutation) BodyOverride() (r map[string]interface{}, exists bool) { + v := m.body_override + if v == nil { + return + } + return *v, true +} + +// OldBodyOverride returns the old "body_override" field's value of the ChannelMonitorRequestTemplate entity. +// If the ChannelMonitorRequestTemplate 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 *ChannelMonitorRequestTemplateMutation) OldBodyOverride(ctx context.Context) (v map[string]interface{}, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldBodyOverride is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldBodyOverride requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldBodyOverride: %w", err) + } + return oldValue.BodyOverride, nil +} + +// ClearBodyOverride clears the value of the "body_override" field. +func (m *ChannelMonitorRequestTemplateMutation) ClearBodyOverride() { + m.body_override = nil + m.clearedFields[channelmonitorrequesttemplate.FieldBodyOverride] = struct{}{} +} + +// BodyOverrideCleared returns if the "body_override" field was cleared in this mutation. +func (m *ChannelMonitorRequestTemplateMutation) BodyOverrideCleared() bool { + _, ok := m.clearedFields[channelmonitorrequesttemplate.FieldBodyOverride] + return ok +} + +// ResetBodyOverride resets all changes to the "body_override" field. +func (m *ChannelMonitorRequestTemplateMutation) ResetBodyOverride() { + m.body_override = nil + delete(m.clearedFields, channelmonitorrequesttemplate.FieldBodyOverride) +} + +// AddMonitorIDs adds the "monitors" edge to the ChannelMonitor entity by ids. +func (m *ChannelMonitorRequestTemplateMutation) AddMonitorIDs(ids ...int64) { + if m.monitors == nil { + m.monitors = make(map[int64]struct{}) + } + for i := range ids { + m.monitors[ids[i]] = struct{}{} + } +} + +// ClearMonitors clears the "monitors" edge to the ChannelMonitor entity. +func (m *ChannelMonitorRequestTemplateMutation) ClearMonitors() { + m.clearedmonitors = true +} + +// MonitorsCleared reports if the "monitors" edge to the ChannelMonitor entity was cleared. +func (m *ChannelMonitorRequestTemplateMutation) MonitorsCleared() bool { + return m.clearedmonitors +} + +// RemoveMonitorIDs removes the "monitors" edge to the ChannelMonitor entity by IDs. +func (m *ChannelMonitorRequestTemplateMutation) RemoveMonitorIDs(ids ...int64) { + if m.removedmonitors == nil { + m.removedmonitors = make(map[int64]struct{}) + } + for i := range ids { + delete(m.monitors, ids[i]) + m.removedmonitors[ids[i]] = struct{}{} + } +} + +// RemovedMonitors returns the removed IDs of the "monitors" edge to the ChannelMonitor entity. +func (m *ChannelMonitorRequestTemplateMutation) RemovedMonitorsIDs() (ids []int64) { + for id := range m.removedmonitors { + ids = append(ids, id) + } + return +} + +// MonitorsIDs returns the "monitors" edge IDs in the mutation. +func (m *ChannelMonitorRequestTemplateMutation) MonitorsIDs() (ids []int64) { + for id := range m.monitors { + ids = append(ids, id) + } + return +} + +// ResetMonitors resets all changes to the "monitors" edge. +func (m *ChannelMonitorRequestTemplateMutation) ResetMonitors() { + m.monitors = nil + m.clearedmonitors = false + m.removedmonitors = nil +} + +// Where appends a list predicates to the ChannelMonitorRequestTemplateMutation builder. +func (m *ChannelMonitorRequestTemplateMutation) Where(ps ...predicate.ChannelMonitorRequestTemplate) { + m.predicates = append(m.predicates, ps...) +} + +// WhereP appends storage-level predicates to the ChannelMonitorRequestTemplateMutation builder. Using this method, +// users can use type-assertion to append predicates that do not depend on any generated package. +func (m *ChannelMonitorRequestTemplateMutation) WhereP(ps ...func(*sql.Selector)) { + p := make([]predicate.ChannelMonitorRequestTemplate, len(ps)) + for i := range ps { + p[i] = ps[i] + } + m.Where(p...) +} + +// Op returns the operation name. +func (m *ChannelMonitorRequestTemplateMutation) Op() Op { + return m.op +} + +// SetOp allows setting the mutation operation. +func (m *ChannelMonitorRequestTemplateMutation) SetOp(op Op) { + m.op = op +} + +// Type returns the node type of this mutation (ChannelMonitorRequestTemplate). +func (m *ChannelMonitorRequestTemplateMutation) 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 *ChannelMonitorRequestTemplateMutation) Fields() []string { + fields := make([]string, 0, 8) + if m.created_at != nil { + fields = append(fields, channelmonitorrequesttemplate.FieldCreatedAt) + } + if m.updated_at != nil { + fields = append(fields, channelmonitorrequesttemplate.FieldUpdatedAt) + } + if m.name != nil { + fields = append(fields, channelmonitorrequesttemplate.FieldName) + } + if m.provider != nil { + fields = append(fields, channelmonitorrequesttemplate.FieldProvider) + } + if m.description != nil { + fields = append(fields, channelmonitorrequesttemplate.FieldDescription) + } + if m.extra_headers != nil { + fields = append(fields, channelmonitorrequesttemplate.FieldExtraHeaders) + } + if m.body_override_mode != nil { + fields = append(fields, channelmonitorrequesttemplate.FieldBodyOverrideMode) + } + if m.body_override != nil { + fields = append(fields, channelmonitorrequesttemplate.FieldBodyOverride) + } + 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 *ChannelMonitorRequestTemplateMutation) Field(name string) (ent.Value, bool) { + switch name { + case channelmonitorrequesttemplate.FieldCreatedAt: + return m.CreatedAt() + case channelmonitorrequesttemplate.FieldUpdatedAt: + return m.UpdatedAt() + case channelmonitorrequesttemplate.FieldName: + return m.Name() + case channelmonitorrequesttemplate.FieldProvider: + return m.Provider() + case channelmonitorrequesttemplate.FieldDescription: + return m.Description() + case channelmonitorrequesttemplate.FieldExtraHeaders: + return m.ExtraHeaders() + case channelmonitorrequesttemplate.FieldBodyOverrideMode: + return m.BodyOverrideMode() + case channelmonitorrequesttemplate.FieldBodyOverride: + return m.BodyOverride() + } + 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 *ChannelMonitorRequestTemplateMutation) OldField(ctx context.Context, name string) (ent.Value, error) { + switch name { + case channelmonitorrequesttemplate.FieldCreatedAt: + return m.OldCreatedAt(ctx) + case channelmonitorrequesttemplate.FieldUpdatedAt: + return m.OldUpdatedAt(ctx) + case channelmonitorrequesttemplate.FieldName: + return m.OldName(ctx) + case channelmonitorrequesttemplate.FieldProvider: + return m.OldProvider(ctx) + case channelmonitorrequesttemplate.FieldDescription: + return m.OldDescription(ctx) + case channelmonitorrequesttemplate.FieldExtraHeaders: + return m.OldExtraHeaders(ctx) + case channelmonitorrequesttemplate.FieldBodyOverrideMode: + return m.OldBodyOverrideMode(ctx) + case channelmonitorrequesttemplate.FieldBodyOverride: + return m.OldBodyOverride(ctx) + } + return nil, fmt.Errorf("unknown ChannelMonitorRequestTemplate 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 *ChannelMonitorRequestTemplateMutation) SetField(name string, value ent.Value) error { + switch name { + case channelmonitorrequesttemplate.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 channelmonitorrequesttemplate.FieldUpdatedAt: + v, ok := value.(time.Time) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetUpdatedAt(v) + return nil + case channelmonitorrequesttemplate.FieldName: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetName(v) + return nil + case channelmonitorrequesttemplate.FieldProvider: + v, ok := value.(channelmonitorrequesttemplate.Provider) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetProvider(v) + return nil + case channelmonitorrequesttemplate.FieldDescription: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetDescription(v) + return nil + case channelmonitorrequesttemplate.FieldExtraHeaders: + v, ok := value.(map[string]string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetExtraHeaders(v) + return nil + case channelmonitorrequesttemplate.FieldBodyOverrideMode: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetBodyOverrideMode(v) + return nil + case channelmonitorrequesttemplate.FieldBodyOverride: + v, ok := value.(map[string]interface{}) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetBodyOverride(v) + return nil + } + return fmt.Errorf("unknown ChannelMonitorRequestTemplate field %s", name) +} + +// AddedFields returns all numeric fields that were incremented/decremented during +// this mutation. +func (m *ChannelMonitorRequestTemplateMutation) AddedFields() []string { + return nil +} + +// 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 *ChannelMonitorRequestTemplateMutation) AddedField(name string) (ent.Value, bool) { + 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 *ChannelMonitorRequestTemplateMutation) AddField(name string, value ent.Value) error { + switch name { + } + return fmt.Errorf("unknown ChannelMonitorRequestTemplate numeric field %s", name) +} + +// ClearedFields returns all nullable fields that were cleared during this +// mutation. +func (m *ChannelMonitorRequestTemplateMutation) ClearedFields() []string { + var fields []string + if m.FieldCleared(channelmonitorrequesttemplate.FieldDescription) { + fields = append(fields, channelmonitorrequesttemplate.FieldDescription) + } + if m.FieldCleared(channelmonitorrequesttemplate.FieldBodyOverride) { + fields = append(fields, channelmonitorrequesttemplate.FieldBodyOverride) + } + return fields +} + +// FieldCleared returns a boolean indicating if a field with the given name was +// cleared in this mutation. +func (m *ChannelMonitorRequestTemplateMutation) 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 *ChannelMonitorRequestTemplateMutation) ClearField(name string) error { + switch name { + case channelmonitorrequesttemplate.FieldDescription: + m.ClearDescription() + return nil + case channelmonitorrequesttemplate.FieldBodyOverride: + m.ClearBodyOverride() + return nil + } + return fmt.Errorf("unknown ChannelMonitorRequestTemplate 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 *ChannelMonitorRequestTemplateMutation) ResetField(name string) error { + switch name { + case channelmonitorrequesttemplate.FieldCreatedAt: + m.ResetCreatedAt() + return nil + case channelmonitorrequesttemplate.FieldUpdatedAt: + m.ResetUpdatedAt() + return nil + case channelmonitorrequesttemplate.FieldName: + m.ResetName() + return nil + case channelmonitorrequesttemplate.FieldProvider: + m.ResetProvider() + return nil + case channelmonitorrequesttemplate.FieldDescription: + m.ResetDescription() + return nil + case channelmonitorrequesttemplate.FieldExtraHeaders: + m.ResetExtraHeaders() + return nil + case channelmonitorrequesttemplate.FieldBodyOverrideMode: + m.ResetBodyOverrideMode() + return nil + case channelmonitorrequesttemplate.FieldBodyOverride: + m.ResetBodyOverride() + return nil + } + return fmt.Errorf("unknown ChannelMonitorRequestTemplate field %s", name) +} + +// AddedEdges returns all edge names that were set/added in this mutation. +func (m *ChannelMonitorRequestTemplateMutation) AddedEdges() []string { + edges := make([]string, 0, 1) + if m.monitors != nil { + edges = append(edges, channelmonitorrequesttemplate.EdgeMonitors) + } + return edges +} + +// AddedIDs returns all IDs (to other nodes) that were added for the given edge +// name in this mutation. +func (m *ChannelMonitorRequestTemplateMutation) AddedIDs(name string) []ent.Value { + switch name { + case channelmonitorrequesttemplate.EdgeMonitors: + ids := make([]ent.Value, 0, len(m.monitors)) + for id := range m.monitors { + ids = append(ids, id) + } + return ids + } + return nil +} + +// RemovedEdges returns all edge names that were removed in this mutation. +func (m *ChannelMonitorRequestTemplateMutation) RemovedEdges() []string { + edges := make([]string, 0, 1) + if m.removedmonitors != nil { + edges = append(edges, channelmonitorrequesttemplate.EdgeMonitors) + } + return edges +} + +// RemovedIDs returns all IDs (to other nodes) that were removed for the edge with +// the given name in this mutation. +func (m *ChannelMonitorRequestTemplateMutation) RemovedIDs(name string) []ent.Value { + switch name { + case channelmonitorrequesttemplate.EdgeMonitors: + ids := make([]ent.Value, 0, len(m.removedmonitors)) + for id := range m.removedmonitors { + ids = append(ids, id) + } + return ids + } + return nil +} + +// ClearedEdges returns all edge names that were cleared in this mutation. +func (m *ChannelMonitorRequestTemplateMutation) ClearedEdges() []string { + edges := make([]string, 0, 1) + if m.clearedmonitors { + edges = append(edges, channelmonitorrequesttemplate.EdgeMonitors) + } + return edges +} + +// EdgeCleared returns a boolean which indicates if the edge with the given name +// was cleared in this mutation. +func (m *ChannelMonitorRequestTemplateMutation) EdgeCleared(name string) bool { + switch name { + case channelmonitorrequesttemplate.EdgeMonitors: + return m.clearedmonitors + } + 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 *ChannelMonitorRequestTemplateMutation) ClearEdge(name string) error { + switch name { + } + return fmt.Errorf("unknown ChannelMonitorRequestTemplate 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 *ChannelMonitorRequestTemplateMutation) ResetEdge(name string) error { + switch name { + case channelmonitorrequesttemplate.EdgeMonitors: + m.ResetMonitors() + return nil + } + return fmt.Errorf("unknown ChannelMonitorRequestTemplate 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 adb9a085..dc86471e 100644 --- a/backend/ent/predicate/predicate.go +++ b/backend/ent/predicate/predicate.go @@ -36,6 +36,9 @@ type ChannelMonitorDailyRollup func(*sql.Selector) // ChannelMonitorHistory is the predicate function for channelmonitorhistory builders. type ChannelMonitorHistory func(*sql.Selector) +// ChannelMonitorRequestTemplate is the predicate function for channelmonitorrequesttemplate builders. +type ChannelMonitorRequestTemplate 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 63552bb5..aaa939c5 100644 --- a/backend/ent/runtime/runtime.go +++ b/backend/ent/runtime/runtime.go @@ -15,6 +15,7 @@ import ( "github.com/Wei-Shaw/sub2api/ent/channelmonitor" "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/errorpassthroughrule" "github.com/Wei-Shaw/sub2api/ent/group" "github.com/Wei-Shaw/sub2api/ent/idempotencyrecord" @@ -521,6 +522,16 @@ func init() { channelmonitorDescIntervalSeconds := channelmonitorFields[8].Descriptor() // channelmonitor.IntervalSecondsValidator is a validator for the "interval_seconds" field. It is called by the builders before save. channelmonitor.IntervalSecondsValidator = channelmonitorDescIntervalSeconds.Validators[0].(func(int) error) + // channelmonitorDescExtraHeaders is the schema descriptor for extra_headers field. + channelmonitorDescExtraHeaders := channelmonitorFields[12].Descriptor() + // channelmonitor.DefaultExtraHeaders holds the default value on creation for the extra_headers field. + channelmonitor.DefaultExtraHeaders = channelmonitorDescExtraHeaders.Default.(map[string]string) + // channelmonitorDescBodyOverrideMode is the schema descriptor for body_override_mode field. + channelmonitorDescBodyOverrideMode := channelmonitorFields[13].Descriptor() + // channelmonitor.DefaultBodyOverrideMode holds the default value on creation for the body_override_mode field. + channelmonitor.DefaultBodyOverrideMode = channelmonitorDescBodyOverrideMode.Default.(string) + // channelmonitor.BodyOverrideModeValidator is a validator for the "body_override_mode" field. It is called by the builders before save. + channelmonitor.BodyOverrideModeValidator = channelmonitorDescBodyOverrideMode.Validators[0].(func(string) error) channelmonitordailyrollupFields := schema.ChannelMonitorDailyRollup{}.Fields() _ = channelmonitordailyrollupFields // channelmonitordailyrollupDescModel is the schema descriptor for model field. @@ -617,6 +628,55 @@ func init() { channelmonitorhistoryDescCheckedAt := channelmonitorhistoryFields[6].Descriptor() // channelmonitorhistory.DefaultCheckedAt holds the default value on creation for the checked_at field. channelmonitorhistory.DefaultCheckedAt = channelmonitorhistoryDescCheckedAt.Default.(func() time.Time) + channelmonitorrequesttemplateMixin := schema.ChannelMonitorRequestTemplate{}.Mixin() + channelmonitorrequesttemplateMixinFields0 := channelmonitorrequesttemplateMixin[0].Fields() + _ = channelmonitorrequesttemplateMixinFields0 + channelmonitorrequesttemplateFields := schema.ChannelMonitorRequestTemplate{}.Fields() + _ = channelmonitorrequesttemplateFields + // channelmonitorrequesttemplateDescCreatedAt is the schema descriptor for created_at field. + channelmonitorrequesttemplateDescCreatedAt := channelmonitorrequesttemplateMixinFields0[0].Descriptor() + // channelmonitorrequesttemplate.DefaultCreatedAt holds the default value on creation for the created_at field. + channelmonitorrequesttemplate.DefaultCreatedAt = channelmonitorrequesttemplateDescCreatedAt.Default.(func() time.Time) + // channelmonitorrequesttemplateDescUpdatedAt is the schema descriptor for updated_at field. + channelmonitorrequesttemplateDescUpdatedAt := channelmonitorrequesttemplateMixinFields0[1].Descriptor() + // channelmonitorrequesttemplate.DefaultUpdatedAt holds the default value on creation for the updated_at field. + channelmonitorrequesttemplate.DefaultUpdatedAt = channelmonitorrequesttemplateDescUpdatedAt.Default.(func() time.Time) + // channelmonitorrequesttemplate.UpdateDefaultUpdatedAt holds the default value on update for the updated_at field. + channelmonitorrequesttemplate.UpdateDefaultUpdatedAt = channelmonitorrequesttemplateDescUpdatedAt.UpdateDefault.(func() time.Time) + // channelmonitorrequesttemplateDescName is the schema descriptor for name field. + channelmonitorrequesttemplateDescName := channelmonitorrequesttemplateFields[0].Descriptor() + // channelmonitorrequesttemplate.NameValidator is a validator for the "name" field. It is called by the builders before save. + channelmonitorrequesttemplate.NameValidator = func() func(string) error { + validators := channelmonitorrequesttemplateDescName.Validators + fns := [...]func(string) error{ + validators[0].(func(string) error), + validators[1].(func(string) error), + } + return func(name string) error { + for _, fn := range fns { + if err := fn(name); err != nil { + return err + } + } + return nil + } + }() + // channelmonitorrequesttemplateDescDescription is the schema descriptor for description field. + channelmonitorrequesttemplateDescDescription := channelmonitorrequesttemplateFields[2].Descriptor() + // channelmonitorrequesttemplate.DefaultDescription holds the default value on creation for the description field. + channelmonitorrequesttemplate.DefaultDescription = channelmonitorrequesttemplateDescDescription.Default.(string) + // channelmonitorrequesttemplate.DescriptionValidator is a validator for the "description" field. It is called by the builders before save. + channelmonitorrequesttemplate.DescriptionValidator = channelmonitorrequesttemplateDescDescription.Validators[0].(func(string) error) + // channelmonitorrequesttemplateDescExtraHeaders is the schema descriptor for extra_headers field. + channelmonitorrequesttemplateDescExtraHeaders := channelmonitorrequesttemplateFields[3].Descriptor() + // channelmonitorrequesttemplate.DefaultExtraHeaders holds the default value on creation for the extra_headers field. + channelmonitorrequesttemplate.DefaultExtraHeaders = channelmonitorrequesttemplateDescExtraHeaders.Default.(map[string]string) + // channelmonitorrequesttemplateDescBodyOverrideMode is the schema descriptor for body_override_mode field. + channelmonitorrequesttemplateDescBodyOverrideMode := channelmonitorrequesttemplateFields[4].Descriptor() + // channelmonitorrequesttemplate.DefaultBodyOverrideMode holds the default value on creation for the body_override_mode field. + 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) errorpassthroughruleMixin := schema.ErrorPassthroughRule{}.Mixin() errorpassthroughruleMixinFields0 := errorpassthroughruleMixin[0].Fields() _ = errorpassthroughruleMixinFields0 diff --git a/backend/ent/schema/channel_monitor.go b/backend/ent/schema/channel_monitor.go index f6a6578d..355ade4b 100644 --- a/backend/ent/schema/channel_monitor.go +++ b/backend/ent/schema/channel_monitor.go @@ -62,6 +62,26 @@ func (ChannelMonitor) Fields() []ent.Field { Optional(). Nillable(), field.Int64("created_by"), + + // ---- 自定义请求快照字段(来自模板 / 手动编辑) ---- + + // template_id: 关联的请求模板 ID(仅用于 UI 分组 + 一键应用)。 + // 实际运行时 checker 只读下面 3 个快照字段,**不再回查模板表**。 + // 模板被删除时此字段会被 SET NULL(见 Edges 的 OnDelete 注解)。 + field.Int64("template_id"). + Optional(). + Nillable(), + // extra_headers: 自定义 HTTP 头快照(来自模板 or 用户手填)。 + // 运行时 merge 进 adapter 默认 headers。 + field.JSON("extra_headers", map[string]string{}). + Default(map[string]string{}), + // body_override_mode: 同 ChannelMonitorRequestTemplate.body_override_mode + field.String("body_override_mode"). + Default("off"). + MaxLen(10), + // body_override: 同 ChannelMonitorRequestTemplate.body_override + field.JSON("body_override", map[string]any{}). + Optional(), } } @@ -71,6 +91,12 @@ func (ChannelMonitor) Edges() []ent.Edge { Annotations(entsql.OnDelete(entsql.Cascade)), edge.To("daily_rollups", ChannelMonitorDailyRollup.Type). Annotations(entsql.OnDelete(entsql.Cascade)), + // 关联请求模板:模板被删除时 template_id 自动置空, + // 监控本身保留(继续用快照字段跑)。 + edge.To("request_template", ChannelMonitorRequestTemplate.Type). + Field("template_id"). + Unique(). + Annotations(entsql.OnDelete(entsql.SetNull)), } } @@ -79,5 +105,6 @@ func (ChannelMonitor) Indexes() []ent.Index { index.Fields("enabled", "last_checked_at"), index.Fields("provider"), index.Fields("group_name"), + index.Fields("template_id"), } } diff --git a/backend/ent/schema/channel_monitor_request_template.go b/backend/ent/schema/channel_monitor_request_template.go new file mode 100644 index 00000000..59df2f29 --- /dev/null +++ b/backend/ent/schema/channel_monitor_request_template.go @@ -0,0 +1,80 @@ +package schema + +import ( + "github.com/Wei-Shaw/sub2api/ent/schema/mixins" + + "entgo.io/ent" + "entgo.io/ent/dialect/entsql" + "entgo.io/ent/schema" + "entgo.io/ent/schema/edge" + "entgo.io/ent/schema/field" + "entgo.io/ent/schema/index" +) + +// ChannelMonitorRequestTemplate 请求模板:一组可复用的 headers + 可选 body 覆盖配置。 +// +// 语义为快照:模板被"应用"到监控时,extra_headers / body_override_mode / body_override +// 会被**拷贝**到 channel_monitors 同名字段;后续模板变动不会自动影响已应用的监控—— +// 必须用户主动在模板编辑 Dialog 里点「应用到关联监控」才会覆盖快照。 +// 这样模板改错不会瞬间打挂所有已经跑起来的监控。 +type ChannelMonitorRequestTemplate struct { + ent.Schema +} + +func (ChannelMonitorRequestTemplate) Annotations() []schema.Annotation { + return []schema.Annotation{ + entsql.Annotation{Table: "channel_monitor_request_templates"}, + } +} + +func (ChannelMonitorRequestTemplate) Mixin() []ent.Mixin { + return []ent.Mixin{ + mixins.TimeMixin{}, + } +} + +func (ChannelMonitorRequestTemplate) Fields() []ent.Field { + return []ent.Field{ + field.String("name"). + NotEmpty(). + MaxLen(100), + field.Enum("provider"). + Values("openai", "anthropic", "gemini"), + field.String("description"). + Optional(). + Default(""). + MaxLen(500), + // extra_headers: 用户自定义 HTTP 头(如 User-Agent 伪装)。 + // 运行时 merge 进 adapter 默认 headers,用户值优先; + // hop-by-hop 黑名单(Host/Content-Length/...)由 checker 过滤。 + field.JSON("extra_headers", map[string]string{}). + Default(map[string]string{}), + // body_override_mode: 'off' | 'merge' | 'replace' + // off - 用 adapter 默认 body(忽略 body_override) + // merge - adapter 默认 body 与 body_override 浅合并(body_override 优先, + // model/messages/contents 等关键字段在 checker 里走黑名单跳过) + // replace - 直接用 body_override 作为完整 body;此时跳过 challenge 校验, + // 改为 HTTP 2xx + 响应文本非空即视为可用 + field.String("body_override_mode"). + Default("off"). + MaxLen(10), + // body_override: JSON 对象,根据 body_override_mode 使用。 + // 用 map[string]any 以便前端传任意结构(含嵌套)。 + field.JSON("body_override", map[string]any{}). + Optional(), + } +} + +func (ChannelMonitorRequestTemplate) Edges() []ent.Edge { + return []ent.Edge{ + edge.From("monitors", ChannelMonitor.Type). + Ref("request_template"), + } +} + +func (ChannelMonitorRequestTemplate) Indexes() []ent.Index { + return []ent.Index{ + // 同一 provider 内 name 唯一:允许 Anthropic + OpenAI 重名 "伪装官方客户端"。 + index.Fields("provider", "name").Unique(), + } +} diff --git a/backend/ent/tx.go b/backend/ent/tx.go index 0e65a940..611028e9 100644 --- a/backend/ent/tx.go +++ b/backend/ent/tx.go @@ -34,6 +34,8 @@ type Tx struct { ChannelMonitorDailyRollup *ChannelMonitorDailyRollupClient // ChannelMonitorHistory is the client for interacting with the ChannelMonitorHistory builders. ChannelMonitorHistory *ChannelMonitorHistoryClient + // ChannelMonitorRequestTemplate is the client for interacting with the ChannelMonitorRequestTemplate builders. + ChannelMonitorRequestTemplate *ChannelMonitorRequestTemplateClient // ErrorPassthroughRule is the client for interacting with the ErrorPassthroughRule builders. ErrorPassthroughRule *ErrorPassthroughRuleClient // Group is the client for interacting with the Group builders. @@ -221,6 +223,7 @@ func (tx *Tx) init() { tx.ChannelMonitor = NewChannelMonitorClient(tx.config) tx.ChannelMonitorDailyRollup = NewChannelMonitorDailyRollupClient(tx.config) tx.ChannelMonitorHistory = NewChannelMonitorHistoryClient(tx.config) + tx.ChannelMonitorRequestTemplate = NewChannelMonitorRequestTemplateClient(tx.config) tx.ErrorPassthroughRule = NewErrorPassthroughRuleClient(tx.config) tx.Group = NewGroupClient(tx.config) tx.IdempotencyRecord = NewIdempotencyRecordClient(tx.config) diff --git a/backend/internal/handler/admin/channel_monitor_handler.go b/backend/internal/handler/admin/channel_monitor_handler.go index ce86c3dc..e92c81fe 100644 --- a/backend/internal/handler/admin/channel_monitor_handler.go +++ b/backend/internal/handler/admin/channel_monitor_handler.go @@ -36,27 +36,36 @@ func NewChannelMonitorHandler(monitorService *service.ChannelMonitorService) *Ch // --- Request / Response --- type channelMonitorCreateRequest struct { - Name string `json:"name" binding:"required,max=100"` - Provider string `json:"provider" binding:"required,oneof=openai anthropic gemini"` - Endpoint string `json:"endpoint" binding:"required,max=500"` - APIKey string `json:"api_key" binding:"required,max=2000"` - PrimaryModel string `json:"primary_model" binding:"required,max=200"` - ExtraModels []string `json:"extra_models"` - GroupName string `json:"group_name" binding:"max=100"` - Enabled *bool `json:"enabled"` - IntervalSeconds int `json:"interval_seconds" binding:"required,min=15,max=3600"` + Name string `json:"name" binding:"required,max=100"` + Provider string `json:"provider" binding:"required,oneof=openai anthropic gemini"` + Endpoint string `json:"endpoint" binding:"required,max=500"` + APIKey string `json:"api_key" binding:"required,max=2000"` + PrimaryModel string `json:"primary_model" binding:"required,max=200"` + ExtraModels []string `json:"extra_models"` + GroupName string `json:"group_name" binding:"max=100"` + Enabled *bool `json:"enabled"` + IntervalSeconds int `json:"interval_seconds" binding:"required,min=15,max=3600"` + TemplateID *int64 `json:"template_id"` + ExtraHeaders map[string]string `json:"extra_headers"` + BodyOverrideMode string `json:"body_override_mode" binding:"omitempty,oneof=off merge replace"` + BodyOverride map[string]any `json:"body_override"` } type channelMonitorUpdateRequest struct { - Name *string `json:"name" binding:"omitempty,max=100"` - Provider *string `json:"provider" binding:"omitempty,oneof=openai anthropic gemini"` - Endpoint *string `json:"endpoint" binding:"omitempty,max=500"` - APIKey *string `json:"api_key" binding:"omitempty,max=2000"` - PrimaryModel *string `json:"primary_model" binding:"omitempty,max=200"` - ExtraModels *[]string `json:"extra_models"` - GroupName *string `json:"group_name" binding:"omitempty,max=100"` - Enabled *bool `json:"enabled"` - IntervalSeconds *int `json:"interval_seconds" binding:"omitempty,min=15,max=3600"` + Name *string `json:"name" binding:"omitempty,max=100"` + Provider *string `json:"provider" binding:"omitempty,oneof=openai anthropic gemini"` + Endpoint *string `json:"endpoint" binding:"omitempty,max=500"` + APIKey *string `json:"api_key" binding:"omitempty,max=2000"` + PrimaryModel *string `json:"primary_model" binding:"omitempty,max=200"` + ExtraModels *[]string `json:"extra_models"` + GroupName *string `json:"group_name" binding:"omitempty,max=100"` + Enabled *bool `json:"enabled"` + IntervalSeconds *int `json:"interval_seconds" binding:"omitempty,min=15,max=3600"` + TemplateID *int64 `json:"template_id"` + ClearTemplate bool `json:"clear_template"` // true 时把 template_id 置空,忽略 TemplateID + ExtraHeaders *map[string]string `json:"extra_headers"` + BodyOverrideMode *string `json:"body_override_mode" binding:"omitempty,oneof=off merge replace"` + BodyOverride *map[string]any `json:"body_override"` } type channelMonitorResponse struct { @@ -79,6 +88,11 @@ type channelMonitorResponse struct { PrimaryLatencyMs *int `json:"primary_latency_ms"` Availability7d float64 `json:"availability_7d"` ExtraModelsStatus []dto.ChannelMonitorExtraModelStatus `json:"extra_models_status"` + // 请求自定义快照:前端编辑 / 展示「高级设置」用 + TemplateID *int64 `json:"template_id"` + ExtraHeaders map[string]string `json:"extra_headers"` + BodyOverrideMode string `json:"body_override_mode"` + BodyOverride map[string]any `json:"body_override"` } type channelMonitorCheckResultResponse struct { @@ -116,6 +130,10 @@ func channelMonitorToResponse(m *service.ChannelMonitor) *channelMonitorResponse if extras == nil { extras = []string{} } + headers := m.ExtraHeaders + if headers == nil { + headers = map[string]string{} + } resp := &channelMonitorResponse{ ID: m.ID, Name: m.Name, @@ -131,6 +149,10 @@ func channelMonitorToResponse(m *service.ChannelMonitor) *channelMonitorResponse CreatedBy: m.CreatedBy, CreatedAt: m.CreatedAt.UTC().Format(time.RFC3339), UpdatedAt: m.UpdatedAt.UTC().Format(time.RFC3339), + TemplateID: m.TemplateID, + ExtraHeaders: headers, + BodyOverrideMode: m.BodyOverrideMode, + BodyOverride: m.BodyOverride, // PrimaryStatus / PrimaryLatencyMs / Availability7d 由 List handler 在批量聚合后填充。 } if m.LastCheckedAt != nil { @@ -279,16 +301,20 @@ func (h *ChannelMonitorHandler) Create(c *gin.Context) { } m, err := h.monitorService.Create(c.Request.Context(), service.ChannelMonitorCreateParams{ - Name: req.Name, - Provider: req.Provider, - Endpoint: req.Endpoint, - APIKey: req.APIKey, - PrimaryModel: req.PrimaryModel, - ExtraModels: req.ExtraModels, - GroupName: req.GroupName, - Enabled: enabled, - IntervalSeconds: req.IntervalSeconds, - CreatedBy: subject.UserID, + Name: req.Name, + Provider: req.Provider, + Endpoint: req.Endpoint, + APIKey: req.APIKey, + PrimaryModel: req.PrimaryModel, + ExtraModels: req.ExtraModels, + GroupName: req.GroupName, + Enabled: enabled, + IntervalSeconds: req.IntervalSeconds, + CreatedBy: subject.UserID, + TemplateID: req.TemplateID, + ExtraHeaders: req.ExtraHeaders, + BodyOverrideMode: req.BodyOverrideMode, + BodyOverride: req.BodyOverride, }) if err != nil { response.ErrorFrom(c, err) @@ -310,15 +336,20 @@ func (h *ChannelMonitorHandler) Update(c *gin.Context) { } m, err := h.monitorService.Update(c.Request.Context(), id, service.ChannelMonitorUpdateParams{ - Name: req.Name, - Provider: req.Provider, - Endpoint: req.Endpoint, - APIKey: req.APIKey, - PrimaryModel: req.PrimaryModel, - ExtraModels: req.ExtraModels, - GroupName: req.GroupName, - Enabled: req.Enabled, - IntervalSeconds: req.IntervalSeconds, + Name: req.Name, + Provider: req.Provider, + Endpoint: req.Endpoint, + APIKey: req.APIKey, + PrimaryModel: req.PrimaryModel, + ExtraModels: req.ExtraModels, + GroupName: req.GroupName, + Enabled: req.Enabled, + IntervalSeconds: req.IntervalSeconds, + TemplateID: req.TemplateID, + ClearTemplate: req.ClearTemplate, + ExtraHeaders: req.ExtraHeaders, + BodyOverrideMode: req.BodyOverrideMode, + BodyOverride: req.BodyOverride, }) if err != nil { response.ErrorFrom(c, err) diff --git a/backend/internal/handler/admin/channel_monitor_template_handler.go b/backend/internal/handler/admin/channel_monitor_template_handler.go new file mode 100644 index 00000000..8c1191ea --- /dev/null +++ b/backend/internal/handler/admin/channel_monitor_template_handler.go @@ -0,0 +1,195 @@ +package admin + +import ( + "strconv" + "strings" + "time" + + infraerrors "github.com/Wei-Shaw/sub2api/internal/pkg/errors" + "github.com/Wei-Shaw/sub2api/internal/pkg/response" + "github.com/Wei-Shaw/sub2api/internal/service" + + "github.com/gin-gonic/gin" +) + +// ChannelMonitorRequestTemplateHandler 请求模板管理后台 handler。 +type ChannelMonitorRequestTemplateHandler struct { + templateService *service.ChannelMonitorRequestTemplateService +} + +// NewChannelMonitorRequestTemplateHandler 创建 handler。 +func NewChannelMonitorRequestTemplateHandler(templateService *service.ChannelMonitorRequestTemplateService) *ChannelMonitorRequestTemplateHandler { + return &ChannelMonitorRequestTemplateHandler{templateService: templateService} +} + +// --- DTO --- + +type channelMonitorTemplateCreateRequest struct { + Name string `json:"name" binding:"required,max=100"` + Provider string `json:"provider" binding:"required,oneof=openai anthropic gemini"` + Description string `json:"description" binding:"max=500"` + ExtraHeaders map[string]string `json:"extra_headers"` + BodyOverrideMode string `json:"body_override_mode" binding:"omitempty,oneof=off merge replace"` + BodyOverride map[string]any `json:"body_override"` +} + +type channelMonitorTemplateUpdateRequest struct { + Name *string `json:"name" binding:"omitempty,max=100"` + Description *string `json:"description" binding:"omitempty,max=500"` + ExtraHeaders *map[string]string `json:"extra_headers"` + BodyOverrideMode *string `json:"body_override_mode" binding:"omitempty,oneof=off merge replace"` + BodyOverride *map[string]any `json:"body_override"` +} + +type channelMonitorTemplateResponse struct { + ID int64 `json:"id"` + Name string `json:"name"` + Provider string `json:"provider"` + Description string `json:"description"` + ExtraHeaders map[string]string `json:"extra_headers"` + BodyOverrideMode string `json:"body_override_mode"` + BodyOverride map[string]any `json:"body_override"` + CreatedAt string `json:"created_at"` + UpdatedAt string `json:"updated_at"` + AssociatedMonitors int64 `json:"associated_monitors"` +} + +func (h *ChannelMonitorRequestTemplateHandler) toResponse(c *gin.Context, t *service.ChannelMonitorRequestTemplate) *channelMonitorTemplateResponse { + if t == nil { + return nil + } + headers := t.ExtraHeaders + if headers == nil { + headers = map[string]string{} + } + count, _ := h.templateService.CountAssociatedMonitors(c.Request.Context(), t.ID) + return &channelMonitorTemplateResponse{ + ID: t.ID, + Name: t.Name, + Provider: t.Provider, + Description: t.Description, + ExtraHeaders: headers, + BodyOverrideMode: t.BodyOverrideMode, + BodyOverride: t.BodyOverride, + CreatedAt: t.CreatedAt.UTC().Format(time.RFC3339), + UpdatedAt: t.UpdatedAt.UTC().Format(time.RFC3339), + AssociatedMonitors: count, + } +} + +// parseTemplateID 提取并校验 :id。 +func parseTemplateID(c *gin.Context) (int64, bool) { + id, err := strconv.ParseInt(c.Param("id"), 10, 64) + if err != nil || id <= 0 { + response.ErrorFrom(c, infraerrors.BadRequest("INVALID_TEMPLATE_ID", "invalid template id")) + return 0, false + } + return id, true +} + +// --- Handlers --- + +// List GET /api/v1/admin/channel-monitor-templates?provider=anthropic +func (h *ChannelMonitorRequestTemplateHandler) List(c *gin.Context) { + items, err := h.templateService.List(c.Request.Context(), service.ChannelMonitorRequestTemplateListParams{ + Provider: strings.TrimSpace(c.Query("provider")), + }) + if err != nil { + response.ErrorFrom(c, err) + return + } + out := make([]*channelMonitorTemplateResponse, 0, len(items)) + for _, t := range items { + out = append(out, h.toResponse(c, t)) + } + response.Success(c, gin.H{"items": out}) +} + +// Get GET /api/v1/admin/channel-monitor-templates/:id +func (h *ChannelMonitorRequestTemplateHandler) Get(c *gin.Context) { + id, ok := parseTemplateID(c) + if !ok { + return + } + t, err := h.templateService.Get(c.Request.Context(), id) + if err != nil { + response.ErrorFrom(c, err) + return + } + response.Success(c, h.toResponse(c, t)) +} + +// Create POST /api/v1/admin/channel-monitor-templates +func (h *ChannelMonitorRequestTemplateHandler) Create(c *gin.Context) { + var req channelMonitorTemplateCreateRequest + if err := c.ShouldBindJSON(&req); err != nil { + response.ErrorFrom(c, infraerrors.BadRequest("VALIDATION_ERROR", err.Error())) + return + } + t, err := h.templateService.Create(c.Request.Context(), service.ChannelMonitorRequestTemplateCreateParams{ + Name: req.Name, + Provider: req.Provider, + Description: req.Description, + ExtraHeaders: req.ExtraHeaders, + BodyOverrideMode: req.BodyOverrideMode, + BodyOverride: req.BodyOverride, + }) + if err != nil { + response.ErrorFrom(c, err) + return + } + response.Created(c, h.toResponse(c, t)) +} + +// Update PUT /api/v1/admin/channel-monitor-templates/:id +func (h *ChannelMonitorRequestTemplateHandler) Update(c *gin.Context) { + id, ok := parseTemplateID(c) + if !ok { + return + } + var req channelMonitorTemplateUpdateRequest + if err := c.ShouldBindJSON(&req); err != nil { + response.ErrorFrom(c, infraerrors.BadRequest("VALIDATION_ERROR", err.Error())) + return + } + t, err := h.templateService.Update(c.Request.Context(), id, service.ChannelMonitorRequestTemplateUpdateParams{ + Name: req.Name, + Description: req.Description, + ExtraHeaders: req.ExtraHeaders, + BodyOverrideMode: req.BodyOverrideMode, + BodyOverride: req.BodyOverride, + }) + if err != nil { + response.ErrorFrom(c, err) + return + } + response.Success(c, h.toResponse(c, t)) +} + +// Delete DELETE /api/v1/admin/channel-monitor-templates/:id +func (h *ChannelMonitorRequestTemplateHandler) Delete(c *gin.Context) { + id, ok := parseTemplateID(c) + if !ok { + return + } + if err := h.templateService.Delete(c.Request.Context(), id); err != nil { + response.ErrorFrom(c, err) + return + } + response.Success(c, nil) +} + +// Apply POST /api/v1/admin/channel-monitor-templates/:id/apply +// 一键把模板当前配置覆盖到所有关联监控上。 +func (h *ChannelMonitorRequestTemplateHandler) Apply(c *gin.Context) { + id, ok := parseTemplateID(c) + if !ok { + return + } + affected, err := h.templateService.ApplyToMonitors(c.Request.Context(), id) + if err != nil { + response.ErrorFrom(c, err) + return + } + response.Success(c, gin.H{"affected": affected}) +} diff --git a/backend/internal/handler/handler.go b/backend/internal/handler/handler.go index 58480c93..bedb81ae 100644 --- a/backend/internal/handler/handler.go +++ b/backend/internal/handler/handler.go @@ -6,33 +6,34 @@ import ( // AdminHandlers contains all admin-related HTTP handlers type AdminHandlers struct { - Dashboard *admin.DashboardHandler - User *admin.UserHandler - Group *admin.GroupHandler - Account *admin.AccountHandler - Announcement *admin.AnnouncementHandler - DataManagement *admin.DataManagementHandler - Backup *admin.BackupHandler - OAuth *admin.OAuthHandler - OpenAIOAuth *admin.OpenAIOAuthHandler - GeminiOAuth *admin.GeminiOAuthHandler - AntigravityOAuth *admin.AntigravityOAuthHandler - Proxy *admin.ProxyHandler - Redeem *admin.RedeemHandler - Promo *admin.PromoHandler - Setting *admin.SettingHandler - Ops *admin.OpsHandler - System *admin.SystemHandler - Subscription *admin.SubscriptionHandler - Usage *admin.UsageHandler - UserAttribute *admin.UserAttributeHandler - ErrorPassthrough *admin.ErrorPassthroughHandler - TLSFingerprintProfile *admin.TLSFingerprintProfileHandler - APIKey *admin.AdminAPIKeyHandler - ScheduledTest *admin.ScheduledTestHandler - Channel *admin.ChannelHandler - ChannelMonitor *admin.ChannelMonitorHandler - Payment *admin.PaymentHandler + Dashboard *admin.DashboardHandler + User *admin.UserHandler + Group *admin.GroupHandler + Account *admin.AccountHandler + Announcement *admin.AnnouncementHandler + DataManagement *admin.DataManagementHandler + Backup *admin.BackupHandler + OAuth *admin.OAuthHandler + OpenAIOAuth *admin.OpenAIOAuthHandler + GeminiOAuth *admin.GeminiOAuthHandler + AntigravityOAuth *admin.AntigravityOAuthHandler + Proxy *admin.ProxyHandler + Redeem *admin.RedeemHandler + Promo *admin.PromoHandler + Setting *admin.SettingHandler + Ops *admin.OpsHandler + System *admin.SystemHandler + Subscription *admin.SubscriptionHandler + Usage *admin.UsageHandler + UserAttribute *admin.UserAttributeHandler + ErrorPassthrough *admin.ErrorPassthroughHandler + TLSFingerprintProfile *admin.TLSFingerprintProfileHandler + APIKey *admin.AdminAPIKeyHandler + ScheduledTest *admin.ScheduledTestHandler + Channel *admin.ChannelHandler + ChannelMonitor *admin.ChannelMonitorHandler + ChannelMonitorTemplate *admin.ChannelMonitorRequestTemplateHandler + Payment *admin.PaymentHandler } // Handlers contains all HTTP handlers diff --git a/backend/internal/handler/wire.go b/backend/internal/handler/wire.go index 7c1a5d1b..6584eb70 100644 --- a/backend/internal/handler/wire.go +++ b/backend/internal/handler/wire.go @@ -35,36 +35,38 @@ func ProvideAdminHandlers( scheduledTestHandler *admin.ScheduledTestHandler, channelHandler *admin.ChannelHandler, channelMonitorHandler *admin.ChannelMonitorHandler, + channelMonitorTemplateHandler *admin.ChannelMonitorRequestTemplateHandler, paymentHandler *admin.PaymentHandler, ) *AdminHandlers { return &AdminHandlers{ - Dashboard: dashboardHandler, - User: userHandler, - Group: groupHandler, - Account: accountHandler, - Announcement: announcementHandler, - DataManagement: dataManagementHandler, - Backup: backupHandler, - OAuth: oauthHandler, - OpenAIOAuth: openaiOAuthHandler, - GeminiOAuth: geminiOAuthHandler, - AntigravityOAuth: antigravityOAuthHandler, - Proxy: proxyHandler, - Redeem: redeemHandler, - Promo: promoHandler, - Setting: settingHandler, - Ops: opsHandler, - System: systemHandler, - Subscription: subscriptionHandler, - Usage: usageHandler, - UserAttribute: userAttributeHandler, - ErrorPassthrough: errorPassthroughHandler, - TLSFingerprintProfile: tlsFingerprintProfileHandler, - APIKey: apiKeyHandler, - ScheduledTest: scheduledTestHandler, - Channel: channelHandler, - ChannelMonitor: channelMonitorHandler, - Payment: paymentHandler, + Dashboard: dashboardHandler, + User: userHandler, + Group: groupHandler, + Account: accountHandler, + Announcement: announcementHandler, + DataManagement: dataManagementHandler, + Backup: backupHandler, + OAuth: oauthHandler, + OpenAIOAuth: openaiOAuthHandler, + GeminiOAuth: geminiOAuthHandler, + AntigravityOAuth: antigravityOAuthHandler, + Proxy: proxyHandler, + Redeem: redeemHandler, + Promo: promoHandler, + Setting: settingHandler, + Ops: opsHandler, + System: systemHandler, + Subscription: subscriptionHandler, + Usage: usageHandler, + UserAttribute: userAttributeHandler, + ErrorPassthrough: errorPassthroughHandler, + TLSFingerprintProfile: tlsFingerprintProfileHandler, + APIKey: apiKeyHandler, + ScheduledTest: scheduledTestHandler, + Channel: channelHandler, + ChannelMonitor: channelMonitorHandler, + ChannelMonitorTemplate: channelMonitorTemplateHandler, + Payment: paymentHandler, } } @@ -162,6 +164,7 @@ var ProviderSet = wire.NewSet( admin.NewScheduledTestHandler, admin.NewChannelHandler, admin.NewChannelMonitorHandler, + admin.NewChannelMonitorRequestTemplateHandler, admin.NewPaymentHandler, // AdminHandlers and Handlers constructors diff --git a/backend/internal/repository/channel_monitor_repo.go b/backend/internal/repository/channel_monitor_repo.go index f4e2a0ec..67dccd6c 100644 --- a/backend/internal/repository/channel_monitor_repo.go +++ b/backend/internal/repository/channel_monitor_repo.go @@ -44,7 +44,15 @@ func (r *channelMonitorRepository) Create(ctx context.Context, m *service.Channe SetGroupName(m.GroupName). SetEnabled(m.Enabled). SetIntervalSeconds(m.IntervalSeconds). - SetCreatedBy(m.CreatedBy) + SetCreatedBy(m.CreatedBy). + SetExtraHeaders(emptyHeadersIfNilRepo(m.ExtraHeaders)). + SetBodyOverrideMode(defaultBodyModeRepo(m.BodyOverrideMode)) + if m.TemplateID != nil { + builder = builder.SetTemplateID(*m.TemplateID) + } + if m.BodyOverride != nil { + builder = builder.SetBodyOverride(m.BodyOverride) + } created, err := builder.Save(ctx) if err != nil { @@ -77,7 +85,19 @@ func (r *channelMonitorRepository) Update(ctx context.Context, m *service.Channe SetExtraModels(emptySliceIfNil(m.ExtraModels)). SetGroupName(m.GroupName). SetEnabled(m.Enabled). - SetIntervalSeconds(m.IntervalSeconds) + SetIntervalSeconds(m.IntervalSeconds). + SetExtraHeaders(emptyHeadersIfNilRepo(m.ExtraHeaders)). + SetBodyOverrideMode(defaultBodyModeRepo(m.BodyOverrideMode)) + if m.TemplateID != nil { + updater = updater.SetTemplateID(*m.TemplateID) + } else { + updater = updater.ClearTemplateID() + } + if m.BodyOverride != nil { + updater = updater.SetBodyOverride(m.BodyOverride) + } else { + updater = updater.ClearBodyOverride() + } updated, err := updater.Save(ctx) if err != nil { @@ -716,22 +736,51 @@ func entToServiceMonitor(row *dbent.ChannelMonitor) *service.ChannelMonitor { if extras == nil { extras = []string{} } - return &service.ChannelMonitor{ - ID: row.ID, - Name: row.Name, - Provider: string(row.Provider), - Endpoint: row.Endpoint, - APIKey: row.APIKeyEncrypted, // 仍为密文,service 层负责解密 - PrimaryModel: row.PrimaryModel, - ExtraModels: extras, - GroupName: row.GroupName, - Enabled: row.Enabled, - IntervalSeconds: row.IntervalSeconds, - LastCheckedAt: row.LastCheckedAt, - CreatedBy: row.CreatedBy, - CreatedAt: row.CreatedAt, - UpdatedAt: row.UpdatedAt, + headers := row.ExtraHeaders + if headers == nil { + headers = map[string]string{} } + out := &service.ChannelMonitor{ + ID: row.ID, + Name: row.Name, + Provider: string(row.Provider), + Endpoint: row.Endpoint, + APIKey: row.APIKeyEncrypted, // 仍为密文,service 层负责解密 + PrimaryModel: row.PrimaryModel, + ExtraModels: extras, + GroupName: row.GroupName, + Enabled: row.Enabled, + IntervalSeconds: row.IntervalSeconds, + LastCheckedAt: row.LastCheckedAt, + CreatedBy: row.CreatedBy, + CreatedAt: row.CreatedAt, + UpdatedAt: row.UpdatedAt, + ExtraHeaders: headers, + BodyOverrideMode: row.BodyOverrideMode, + BodyOverride: row.BodyOverride, + } + if row.TemplateID != nil { + id := *row.TemplateID + out.TemplateID = &id + } + return out +} + +// emptyHeadersIfNilRepo 与 service.emptyHeadersIfNil 功能一致, +// repo 独立一份避免 import 循环。 +func emptyHeadersIfNilRepo(h map[string]string) map[string]string { + if h == nil { + return map[string]string{} + } + return h +} + +// defaultBodyModeRepo 空串归一为 off(同上不循环)。 +func defaultBodyModeRepo(mode string) string { + if mode == "" { + return "off" + } + return mode } func emptySliceIfNil(in []string) []string { diff --git a/backend/internal/repository/channel_monitor_template_repo.go b/backend/internal/repository/channel_monitor_template_repo.go new file mode 100644 index 00000000..03f3692b --- /dev/null +++ b/backend/internal/repository/channel_monitor_template_repo.go @@ -0,0 +1,168 @@ +package repository + +import ( + "context" + "database/sql" + "fmt" + + dbent "github.com/Wei-Shaw/sub2api/ent" + "github.com/Wei-Shaw/sub2api/ent/channelmonitor" + "github.com/Wei-Shaw/sub2api/ent/channelmonitorrequesttemplate" + "github.com/Wei-Shaw/sub2api/internal/service" +) + +// channelMonitorRequestTemplateRepository 实现 service.ChannelMonitorRequestTemplateRepository。 +// 与 channelMonitorRepository 分开一个文件,职责清晰。 +type channelMonitorRequestTemplateRepository struct { + client *dbent.Client + db *sql.DB +} + +// NewChannelMonitorRequestTemplateRepository 创建模板仓储实例。 +func NewChannelMonitorRequestTemplateRepository(client *dbent.Client, db *sql.DB) service.ChannelMonitorRequestTemplateRepository { + return &channelMonitorRequestTemplateRepository{client: client, db: db} +} + +// ---------- CRUD ---------- + +func (r *channelMonitorRequestTemplateRepository) Create(ctx context.Context, t *service.ChannelMonitorRequestTemplate) error { + client := clientFromContext(ctx, r.client) + builder := client.ChannelMonitorRequestTemplate.Create(). + SetName(t.Name). + SetProvider(channelmonitorrequesttemplate.Provider(t.Provider)). + SetDescription(t.Description). + SetExtraHeaders(emptyHeadersIfNilRepo(t.ExtraHeaders)). + SetBodyOverrideMode(defaultBodyModeRepo(t.BodyOverrideMode)) + if t.BodyOverride != nil { + builder = builder.SetBodyOverride(t.BodyOverride) + } + + created, err := builder.Save(ctx) + if err != nil { + return translatePersistenceError(err, service.ErrChannelMonitorTemplateNotFound, nil) + } + t.ID = created.ID + t.CreatedAt = created.CreatedAt + t.UpdatedAt = created.UpdatedAt + return nil +} + +func (r *channelMonitorRequestTemplateRepository) GetByID(ctx context.Context, id int64) (*service.ChannelMonitorRequestTemplate, error) { + row, err := r.client.ChannelMonitorRequestTemplate.Query(). + Where(channelmonitorrequesttemplate.IDEQ(id)). + Only(ctx) + if err != nil { + return nil, translatePersistenceError(err, service.ErrChannelMonitorTemplateNotFound, nil) + } + return entToServiceTemplate(row), nil +} + +func (r *channelMonitorRequestTemplateRepository) Update(ctx context.Context, t *service.ChannelMonitorRequestTemplate) error { + client := clientFromContext(ctx, r.client) + updater := client.ChannelMonitorRequestTemplate.UpdateOneID(t.ID). + SetName(t.Name). + SetDescription(t.Description). + SetExtraHeaders(emptyHeadersIfNilRepo(t.ExtraHeaders)). + SetBodyOverrideMode(defaultBodyModeRepo(t.BodyOverrideMode)) + if t.BodyOverride != nil { + updater = updater.SetBodyOverride(t.BodyOverride) + } else { + updater = updater.ClearBodyOverride() + } + updated, err := updater.Save(ctx) + if err != nil { + return translatePersistenceError(err, service.ErrChannelMonitorTemplateNotFound, nil) + } + t.UpdatedAt = updated.UpdatedAt + return nil +} + +func (r *channelMonitorRequestTemplateRepository) Delete(ctx context.Context, id int64) error { + client := clientFromContext(ctx, r.client) + if err := client.ChannelMonitorRequestTemplate.DeleteOneID(id).Exec(ctx); err != nil { + return translatePersistenceError(err, service.ErrChannelMonitorTemplateNotFound, nil) + } + return nil +} + +func (r *channelMonitorRequestTemplateRepository) List(ctx context.Context, params service.ChannelMonitorRequestTemplateListParams) ([]*service.ChannelMonitorRequestTemplate, error) { + q := r.client.ChannelMonitorRequestTemplate.Query() + if params.Provider != "" { + q = q.Where(channelmonitorrequesttemplate.ProviderEQ(channelmonitorrequesttemplate.Provider(params.Provider))) + } + rows, err := q. + Order(dbent.Asc(channelmonitorrequesttemplate.FieldProvider), dbent.Asc(channelmonitorrequesttemplate.FieldName)). + All(ctx) + if err != nil { + return nil, fmt.Errorf("list monitor templates: %w", err) + } + out := make([]*service.ChannelMonitorRequestTemplate, 0, len(rows)) + for _, row := range rows { + out = append(out, entToServiceTemplate(row)) + } + return out, nil +} + +// ApplyToMonitors 把模板当前配置批量覆盖到 template_id = id 的监控上。 +// +// 用一条 UPDATE 完成:extra_headers / body_override_mode / body_override 都覆盖。 +// 走 ent 的 UpdateMany 保证走 ent hooks;走原生 SQL 也可以但 ent jsonb 序列化更省心。 +func (r *channelMonitorRequestTemplateRepository) ApplyToMonitors(ctx context.Context, id int64) (int64, error) { + client := clientFromContext(ctx, r.client) + tpl, err := client.ChannelMonitorRequestTemplate.Query(). + Where(channelmonitorrequesttemplate.IDEQ(id)). + Only(ctx) + if err != nil { + return 0, translatePersistenceError(err, service.ErrChannelMonitorTemplateNotFound, nil) + } + + updater := client.ChannelMonitor.Update(). + Where(channelmonitor.TemplateIDEQ(id)). + SetExtraHeaders(emptyHeadersIfNilRepo(tpl.ExtraHeaders)). + SetBodyOverrideMode(defaultBodyModeRepo(tpl.BodyOverrideMode)) + if tpl.BodyOverride != nil { + updater = updater.SetBodyOverride(tpl.BodyOverride) + } else { + updater = updater.ClearBodyOverride() + } + + affected, err := updater.Save(ctx) + if err != nil { + return 0, fmt.Errorf("apply template to monitors: %w", err) + } + return int64(affected), nil +} + +// CountAssociatedMonitors 统计关联监控数(UI 展示「N 个配置」用)。 +func (r *channelMonitorRequestTemplateRepository) CountAssociatedMonitors(ctx context.Context, id int64) (int64, error) { + count, err := r.client.ChannelMonitor.Query(). + Where(channelmonitor.TemplateIDEQ(id)). + Count(ctx) + if err != nil { + return 0, fmt.Errorf("count monitors for template %d: %w", id, err) + } + return int64(count), nil +} + +// ---------- helpers ---------- + +func entToServiceTemplate(row *dbent.ChannelMonitorRequestTemplate) *service.ChannelMonitorRequestTemplate { + if row == nil { + return nil + } + headers := row.ExtraHeaders + if headers == nil { + headers = map[string]string{} + } + return &service.ChannelMonitorRequestTemplate{ + ID: row.ID, + Name: row.Name, + Provider: string(row.Provider), + Description: row.Description, + ExtraHeaders: headers, + BodyOverrideMode: row.BodyOverrideMode, + BodyOverride: row.BodyOverride, + CreatedAt: row.CreatedAt, + UpdatedAt: row.UpdatedAt, + } +} diff --git a/backend/internal/repository/wire.go b/backend/internal/repository/wire.go index 7427cd04..b1d5e36a 100644 --- a/backend/internal/repository/wire.go +++ b/backend/internal/repository/wire.go @@ -90,6 +90,7 @@ var ProviderSet = wire.NewSet( NewTLSFingerprintProfileRepository, NewChannelRepository, NewChannelMonitorRepository, + NewChannelMonitorRequestTemplateRepository, // Cache implementations NewGatewayCache, diff --git a/backend/internal/server/routes/admin.go b/backend/internal/server/routes/admin.go index 0381dc57..13cecd59 100644 --- a/backend/internal/server/routes/admin.go +++ b/backend/internal/server/routes/admin.go @@ -579,4 +579,14 @@ func registerChannelMonitorRoutes(admin *gin.RouterGroup, h *handler.Handlers) { monitors.POST("/:id/run", h.Admin.ChannelMonitor.Run) monitors.GET("/:id/history", h.Admin.ChannelMonitor.History) } + + templates := admin.Group("/channel-monitor-templates") + { + templates.GET("", h.Admin.ChannelMonitorTemplate.List) + templates.POST("", h.Admin.ChannelMonitorTemplate.Create) + templates.GET("/:id", h.Admin.ChannelMonitorTemplate.Get) + templates.PUT("/:id", h.Admin.ChannelMonitorTemplate.Update) + templates.DELETE("/:id", h.Admin.ChannelMonitorTemplate.Delete) + templates.POST("/:id/apply", h.Admin.ChannelMonitorTemplate.Apply) + } } diff --git a/backend/internal/service/channel_monitor_checker.go b/backend/internal/service/channel_monitor_checker.go index e03c2e3a..33570629 100644 --- a/backend/internal/service/channel_monitor_checker.go +++ b/backend/internal/service/channel_monitor_checker.go @@ -37,9 +37,23 @@ func newSSRFSafeHTTPClient(timeout time.Duration) *http.Client { return &http.Client{Timeout: timeout, Transport: tr} } +// CheckOptions 承载一次检测的自定义入参。 +// 所有字段都是可选(零值即等价于"用默认行为")。 +type CheckOptions struct { + // ExtraHeaders 用户自定义 HTTP 头(merge 到 adapter 默认 headers,用户优先)。 + ExtraHeaders map[string]string + // BodyOverrideMode: off | merge | replace + BodyOverrideMode string + // BodyOverride 在 merge 模式下做浅合并(key 命中黑名单时静默丢弃), + // 在 replace 模式下直接当作完整 body。 + BodyOverride map[string]any +} + // runCheckForModel 对单个 (provider, model) 做一次完整检测。 // 不返回 error:所有失败都包装进 CheckResult.Status=error/failed。 -func runCheckForModel(ctx context.Context, provider, endpoint, apiKey, model string) *CheckResult { +// +// opts 承载模板 / 监控快照带来的自定义配置。nil 等同于 "off + 无 extra headers"。 +func runCheckForModel(ctx context.Context, provider, endpoint, apiKey, model string, opts *CheckOptions) *CheckResult { res := &CheckResult{ Model: model, Status: MonitorStatusError, @@ -47,9 +61,10 @@ func runCheckForModel(ctx context.Context, provider, endpoint, apiKey, model str } challenge := generateChallenge() + mode := bodyOverrideMode(opts) start := time.Now() - respText, rawBody, statusCode, err := callProvider(ctx, provider, endpoint, apiKey, model, challenge.Prompt) + respText, rawBody, statusCode, err := callProvider(ctx, provider, endpoint, apiKey, model, challenge.Prompt, opts) latency := time.Since(start) latencyMs := int(latency / time.Millisecond) res.LatencyMs = &latencyMs @@ -68,22 +83,47 @@ func runCheckForModel(ctx context.Context, provider, endpoint, apiKey, model str return res } + // Replace 模式:跳过 challenge 校验(用户 body 是静态的,challenge 没法嵌入)。 + // 改用「HTTP 2xx + 响应文本(adapter.textPath 抽取)非空」作为 operational 判定。 + // 响应文本为空则降级为 failed(视为上游回了 200 但没实际内容)。 + if mode == MonitorBodyOverrideModeReplace { + if strings.TrimSpace(respText) == "" { + res.Status = MonitorStatusFailed + res.Message = truncateMessage("replace-mode: upstream returned 2xx with empty text") + return res + } + return finalizeOperationalOrDegraded(res, latency, latencyMs) + } + if !validateChallenge(respText, challenge.Expected) { res.Status = MonitorStatusFailed res.Message = truncateMessage(sanitizeErrorMessage(fmt.Sprintf("challenge mismatch (expected %s, got %q)", challenge.Expected, respText))) return res } + return finalizeOperationalOrDegraded(res, latency, latencyMs) +} + +// finalizeOperationalOrDegraded 负责走到最后一步的 operational/degraded 判定。 +// 拆出来是为了让 runCheckForModel 不超过 30 行。 +func finalizeOperationalOrDegraded(res *CheckResult, latency time.Duration, latencyMs int) *CheckResult { if latency >= monitorDegradedThreshold { res.Status = MonitorStatusDegraded res.Message = truncateMessage(fmt.Sprintf("slow response: %dms", latencyMs)) return res } - res.Status = MonitorStatusOperational return res } +// bodyOverrideMode 归一取 opts.BodyOverrideMode,nil opts / 空串都视为 off。 +func bodyOverrideMode(opts *CheckOptions) string { + if opts == nil || opts.BodyOverrideMode == "" { + return MonitorBodyOverrideModeOff + } + return opts.BodyOverrideMode +} + // pingEndpointOrigin 对 endpoint 的 origin (scheme://host) 发起 HEAD 请求,返回耗时。 // 失败时返回 nil(不影响主状态判定)。 func pingEndpointOrigin(ctx context.Context, endpoint string) *int { @@ -183,29 +223,109 @@ func isSupportedProvider(p string) bool { } // callProvider 通过 providerAdapters 分发到具体实现。 +// opts 承载用户的自定义 headers / body 覆盖(可为 nil)。 // // 返回值: // - extractedText: 按 textPath 抽出的成功文本,仅在 status 2xx 时有意义;非 2xx 时通常为空串 // - rawBody: 完整响应体的字符串形式(已被 monitorResponseMaxBytes 截断),用于错误路径保留上游真实回包 // - status: HTTP 状态码 // - err: 网络 / 序列化错误 -func callProvider(ctx context.Context, provider, endpoint, apiKey, model, prompt string) (extractedText, rawBody string, status int, err error) { +func callProvider(ctx context.Context, provider, endpoint, apiKey, model, prompt string, opts *CheckOptions) (extractedText, rawBody string, status int, err error) { adapter, ok := providerAdapters[provider] if !ok { return "", "", 0, fmt.Errorf("unsupported provider %q", provider) } - body, err := adapter.buildBody(model, prompt) + body, err := buildRequestBody(adapter, provider, model, prompt, opts) if err != nil { - return "", "", 0, fmt.Errorf("marshal body: %w", err) + return "", "", 0, err } + headers := mergeHeaders(adapter.buildHeaders(apiKey), opts) full := joinURL(endpoint, adapter.buildPath(model)) - respBytes, status, err := postRawJSON(ctx, full, body, adapter.buildHeaders(apiKey)) + respBytes, status, err := postRawJSON(ctx, full, body, headers) if err != nil { return "", "", status, err } return gjson.GetBytes(respBytes, adapter.textPath).String(), string(respBytes), status, nil } +// mergeHeaders 把用户自定义 headers 合并到 adapter 默认 headers 上。 +// 用户值覆盖默认;命中黑名单(hop-by-hop / 由 http.Client 自管的)的 key 静默丢弃。 +func mergeHeaders(base map[string]string, opts *CheckOptions) map[string]string { + if opts == nil || len(opts.ExtraHeaders) == 0 { + return base + } + out := make(map[string]string, len(base)+len(opts.ExtraHeaders)) + for k, v := range base { + out[k] = v + } + for k, v := range opts.ExtraHeaders { + if IsForbiddenHeaderName(k) { + continue + } + out[k] = v + } + return out +} + +// buildRequestBody 根据 body_override_mode 构造请求 body。 +// +// - off: adapter 默认 body +// - merge: adapter 默认 body 与 BodyOverride 浅合并;BodyOverride 中命中 +// bodyMergeKeyDenyList[provider] 的 key 会被静默丢弃,避免破坏 challenge / model 路由 +// - replace: 直接 marshal BodyOverride 作为完整 body +// +// 任何 mode 返回的 []byte 都已经是合法 JSON,可直接送入 postRawJSON。 +func buildRequestBody(adapter providerAdapter, provider, model, prompt string, opts *CheckOptions) ([]byte, error) { + mode := bodyOverrideMode(opts) + + if mode == MonitorBodyOverrideModeReplace { + if opts == nil || len(opts.BodyOverride) == 0 { + return nil, fmt.Errorf("replace mode: body_override is empty") + } + body, err := json.Marshal(opts.BodyOverride) + if err != nil { + return nil, fmt.Errorf("marshal body_override (replace): %w", err) + } + return body, nil + } + + defaultBody, err := adapter.buildBody(model, prompt) + if err != nil { + return nil, fmt.Errorf("marshal default body: %w", err) + } + if mode != MonitorBodyOverrideModeMerge || opts == nil || len(opts.BodyOverride) == 0 { + return defaultBody, nil + } + + var defaultMap map[string]any + if err := json.Unmarshal(defaultBody, &defaultMap); err != nil { + return nil, fmt.Errorf("unmarshal default body for merge: %w", err) + } + deny := bodyMergeKeyDenyList[provider] + for k, v := range opts.BodyOverride { + if deny[k] { + continue + } + defaultMap[k] = v + } + merged, err := json.Marshal(defaultMap) + if err != nil { + return nil, fmt.Errorf("marshal merged body: %w", err) + } + return merged, nil +} + +// bodyMergeKeyDenyList 在 merge 模式下,禁止用户覆盖这些 provider-specific 的关键字段。 +// 思路抄 check-cx 的 EXCLUDED_METADATA_KEYS:保护 challenge / model 路由不被用户误伤。 +// 用户想动这些字段就用 replace 模式(已知会跳 challenge 校验)。 +// +//nolint:gochecknoglobals // 静态查表,初始化后不变。 +var bodyMergeKeyDenyList = map[string]map[string]bool{ + MonitorProviderOpenAI: {"model": true, "messages": true, "stream": true}, + MonitorProviderAnthropic: {"model": true, "messages": true}, + MonitorProviderGemini: {"contents": true}, +} + // postRawJSON 发送 POST + 已序列化好的 JSON 字节,限制响应体大小,返回响应字节、HTTP status、错误。 // adapter 自行 marshal 是为了精确控制字段顺序与类型,所以这里直接收 []byte 而不是 any。 func postRawJSON(ctx context.Context, fullURL string, payload []byte, headers map[string]string) ([]byte, int, error) { diff --git a/backend/internal/service/channel_monitor_checker_body_test.go b/backend/internal/service/channel_monitor_checker_body_test.go new file mode 100644 index 00000000..323cf8b7 --- /dev/null +++ b/backend/internal/service/channel_monitor_checker_body_test.go @@ -0,0 +1,173 @@ +//go:build unit + +package service + +import ( + "context" + "encoding/json" + "net/http" + "net/http/httptest" + "strings" + "testing" + "time" +) + +// swapMonitorHTTPClient 临时替换 monitorHTTPClient 为不带 SSRF 校验的普通 client, +// 让 httptest (127.0.0.1) 能连通。测试结束后恢复。 +func swapMonitorHTTPClient(t *testing.T) { + t.Helper() + orig := monitorHTTPClient + monitorHTTPClient = &http.Client{Timeout: 5 * time.Second} + t.Cleanup(func() { monitorHTTPClient = orig }) +} + +// captureHandler 把每次收到的请求 body 和 headers 存起来,测试断言用。 +type captureHandler struct { + lastBody map[string]any + lastHeaders http.Header + respondText string // 写到 Anthropic content[0].text 里(校验用) + status int +} + +func (h *captureHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { + h.lastHeaders = r.Header.Clone() + defer func() { _ = r.Body.Close() }() + var parsed map[string]any + _ = json.NewDecoder(r.Body).Decode(&parsed) + h.lastBody = parsed + + if h.status == 0 { + h.status = 200 + } + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(h.status) + // 构造 Anthropic 格式的响应:content[0].text = h.respondText + _ = json.NewEncoder(w).Encode(map[string]any{ + "content": []map[string]any{ + {"type": "text", "text": h.respondText}, + }, + }) +} + +func setupFakeAnthropic(t *testing.T, handler *captureHandler) string { + t.Helper() + swapMonitorHTTPClient(t) + srv := httptest.NewServer(handler) + t.Cleanup(srv.Close) + return srv.URL +} + +func TestRunCheckForModel_OffMode_PreservesDefaultBody(t *testing.T) { + h := &captureHandler{respondText: "the answer is 42"} + endpoint := setupFakeAnthropic(t, h) + + // 跑一次 off 模式(opts=nil),确认默认 body 行为未变 + _ = runCheckForModel(context.Background(), MonitorProviderAnthropic, endpoint, "sk-fake", "claude-x", nil) + + if h.lastBody["model"] != "claude-x" { + t.Errorf("default body should contain model=claude-x, got %v", h.lastBody["model"]) + } + if _, ok := h.lastBody["messages"]; !ok { + t.Error("default body should contain messages") + } + if h.lastHeaders.Get("x-api-key") != "sk-fake" { + t.Errorf("expected adapter's x-api-key header, got %q", h.lastHeaders.Get("x-api-key")) + } +} + +func TestRunCheckForModel_MergeMode_UserFieldsWinButDenyListProtects(t *testing.T) { + h := &captureHandler{respondText: "the answer is 42"} + endpoint := setupFakeAnthropic(t, h) + + opts := &CheckOptions{ + BodyOverrideMode: MonitorBodyOverrideModeMerge, + BodyOverride: map[string]any{ + "system": "You are Claude Code...", + "max_tokens": float64(999), // 应该覆盖默认 50 + "model": "hacked-model", // 应该被黑名单挡住,保留原 model + "messages": []any{}, // 同上,被挡 + }, + ExtraHeaders: map[string]string{ + "User-Agent": "claude-cli/1.0", + "Content-Length": "999", // 黑名单 + "x-custom": "ok", + }, + } + _ = runCheckForModel(context.Background(), MonitorProviderAnthropic, endpoint, "sk-fake", "claude-x", opts) + + if h.lastBody["system"] != "You are Claude Code..." { + t.Errorf("merge mode should inject system, got %v", h.lastBody["system"]) + } + // max_tokens 覆盖生效 + if mt, ok := h.lastBody["max_tokens"].(float64); !ok || mt != 999 { + t.Errorf("merge mode should override max_tokens to 999, got %v", h.lastBody["max_tokens"]) + } + // model 在黑名单 — 应该保留默认值 + if h.lastBody["model"] != "claude-x" { + t.Errorf("model should be protected by deny list, got %v", h.lastBody["model"]) + } + // messages 在黑名单 — 应该保留默认值(非空) + msgs, _ := h.lastBody["messages"].([]any) + if len(msgs) == 0 { + t.Error("messages should be protected by deny list (kept default, non-empty)") + } + // header 合并 + if h.lastHeaders.Get("User-Agent") != "claude-cli/1.0" { + t.Errorf("extra User-Agent should override, got %q", h.lastHeaders.Get("User-Agent")) + } + if h.lastHeaders.Get("x-custom") != "ok" { + t.Errorf("extra custom header should be present, got %q", h.lastHeaders.Get("x-custom")) + } + // Content-Length 黑名单:会被 net/http 自动重算,但不应由用户的 "999" 决定。 + // 我们无法直接断言丢弃(http.Client 总会填上),只断言请求成功即可。 +} + +func TestRunCheckForModel_ReplaceMode_FullBodyUsedAndChallengeSkipped(t *testing.T) { + // replace 模式下我们的 body 完全自定义,challenge 数学题不会出现在请求里, + // 上游也不会回正确答案 — 但只要 2xx + 响应文本非空,就算 operational + h := &captureHandler{respondText: "any non-empty text"} + endpoint := setupFakeAnthropic(t, h) + + userBody := map[string]any{ + "model": "user-forced-model", + "messages": []any{map[string]any{"role": "user", "content": "hi"}}, + "max_tokens": float64(10), + "system": "You are someone else", + } + opts := &CheckOptions{ + BodyOverrideMode: MonitorBodyOverrideModeReplace, + BodyOverride: userBody, + } + res := runCheckForModel(context.Background(), MonitorProviderAnthropic, endpoint, "sk-fake", "claude-x", opts) + + // 请求 body = 用户提供的原样 + if h.lastBody["model"] != "user-forced-model" { + t.Errorf("replace mode should use user's model, got %v", h.lastBody["model"]) + } + if h.lastBody["system"] != "You are someone else" { + t.Errorf("replace mode should use user's system, got %v", h.lastBody["system"]) + } + // challenge 虽然没命中,但由于 replace 模式跳过 challenge 校验 + 响应非空 → operational + if res.Status != MonitorStatusOperational { + t.Errorf("replace mode with 2xx + non-empty text should be operational, got status=%s message=%q", + res.Status, res.Message) + } +} + +func TestRunCheckForModel_ReplaceMode_EmptyResponseIsFailed(t *testing.T) { + h := &captureHandler{respondText: ""} // 上游 200 但 content[0].text 为空 + endpoint := setupFakeAnthropic(t, h) + + opts := &CheckOptions{ + BodyOverrideMode: MonitorBodyOverrideModeReplace, + BodyOverride: map[string]any{"model": "x", "messages": []any{}}, + } + res := runCheckForModel(context.Background(), MonitorProviderAnthropic, endpoint, "sk-fake", "claude-x", opts) + + if res.Status != MonitorStatusFailed { + t.Errorf("replace mode with empty text should be failed, got status=%s", res.Status) + } + if !strings.Contains(res.Message, "replace-mode") { + t.Errorf("failure message should hint replace-mode, got %q", res.Message) + } +} diff --git a/backend/internal/service/channel_monitor_service.go b/backend/internal/service/channel_monitor_service.go index 144c66a0..ec1107a3 100644 --- a/backend/internal/service/channel_monitor_service.go +++ b/backend/internal/service/channel_monitor_service.go @@ -104,21 +104,31 @@ func (s *ChannelMonitorService) Create(ctx context.Context, p ChannelMonitorCrea if err := validateCreateParams(p); err != nil { return nil, err } + if err := validateBodyModeParams(p.BodyOverrideMode, p.BodyOverride); err != nil { + return nil, err + } + if err := validateExtraHeaders(p.ExtraHeaders); err != nil { + return nil, err + } encrypted, err := s.encryptor.Encrypt(p.APIKey) if err != nil { return nil, fmt.Errorf("encrypt api key: %w", err) } m := &ChannelMonitor{ - Name: strings.TrimSpace(p.Name), - Provider: p.Provider, - Endpoint: normalizeEndpoint(p.Endpoint), - APIKey: encrypted, // 注意:传入 repository 时该字段为密文 - PrimaryModel: strings.TrimSpace(p.PrimaryModel), - ExtraModels: normalizeModels(p.ExtraModels), - GroupName: strings.TrimSpace(p.GroupName), - Enabled: p.Enabled, - IntervalSeconds: p.IntervalSeconds, - CreatedBy: p.CreatedBy, + Name: strings.TrimSpace(p.Name), + Provider: p.Provider, + Endpoint: normalizeEndpoint(p.Endpoint), + APIKey: encrypted, // 注意:传入 repository 时该字段为密文 + PrimaryModel: strings.TrimSpace(p.PrimaryModel), + ExtraModels: normalizeModels(p.ExtraModels), + GroupName: strings.TrimSpace(p.GroupName), + Enabled: p.Enabled, + IntervalSeconds: p.IntervalSeconds, + CreatedBy: p.CreatedBy, + TemplateID: p.TemplateID, + ExtraHeaders: emptyHeadersIfNil(p.ExtraHeaders), + BodyOverrideMode: defaultBodyMode(p.BodyOverrideMode), + BodyOverride: p.BodyOverride, } if err := s.repo.Create(ctx, m); err != nil { return nil, fmt.Errorf("create channel monitor: %w", err) @@ -272,12 +282,19 @@ func (s *ChannelMonitorService) runChecksConcurrent(ctx context.Context, m *Chan // ping 共享一次,所有模型记录同一个 ping 延迟。 pingMs := pingEndpointOrigin(ctx, m.Endpoint) + // 所有模型共用同一份 CheckOptions(来自监控的快照字段)。 + opts := &CheckOptions{ + ExtraHeaders: m.ExtraHeaders, + BodyOverrideMode: m.BodyOverrideMode, + BodyOverride: m.BodyOverride, + } + var eg errgroup.Group var mu sync.Mutex for i, model := range models { i, model := i, model eg.Go(func() error { - r := runCheckForModel(ctx, m.Provider, m.Endpoint, m.APIKey, model) + r := runCheckForModel(ctx, m.Provider, m.Endpoint, m.APIKey, model, opts) r.PingLatencyMs = pingMs mu.Lock() results[i] = r @@ -476,5 +493,38 @@ func applyMonitorUpdate(existing *ChannelMonitor, p ChannelMonitorUpdateParams) } existing.IntervalSeconds = *p.IntervalSeconds } + return applyMonitorAdvancedUpdate(existing, p) +} + +// applyMonitorAdvancedUpdate 处理自定义请求快照相关字段,从 applyMonitorUpdate 拆出避免过长。 +func applyMonitorAdvancedUpdate(existing *ChannelMonitor, p ChannelMonitorUpdateParams) error { + if p.ClearTemplate { + existing.TemplateID = nil + } else if p.TemplateID != nil { + id := *p.TemplateID + existing.TemplateID = &id + } + if p.ExtraHeaders != nil { + if err := validateExtraHeaders(*p.ExtraHeaders); err != nil { + return err + } + existing.ExtraHeaders = emptyHeadersIfNil(*p.ExtraHeaders) + } + // BodyOverrideMode / BodyOverride 联合校验,和模板一致。 + newMode := existing.BodyOverrideMode + newBody := existing.BodyOverride + if p.BodyOverrideMode != nil { + newMode = *p.BodyOverrideMode + } + if p.BodyOverride != nil { + newBody = *p.BodyOverride + } + if p.BodyOverrideMode != nil || p.BodyOverride != nil { + if err := validateBodyModeParams(newMode, newBody); err != nil { + return err + } + existing.BodyOverrideMode = defaultBodyMode(newMode) + existing.BodyOverride = newBody + } return nil } diff --git a/backend/internal/service/channel_monitor_template_service.go b/backend/internal/service/channel_monitor_template_service.go new file mode 100644 index 00000000..98fc930b --- /dev/null +++ b/backend/internal/service/channel_monitor_template_service.go @@ -0,0 +1,225 @@ +package service + +import ( + "context" + "fmt" + "regexp" + "strings" +) + +// ChannelMonitorRequestTemplateRepository 模板数据访问接口。 +type ChannelMonitorRequestTemplateRepository interface { + Create(ctx context.Context, t *ChannelMonitorRequestTemplate) error + GetByID(ctx context.Context, id int64) (*ChannelMonitorRequestTemplate, error) + Update(ctx context.Context, t *ChannelMonitorRequestTemplate) error + Delete(ctx context.Context, id int64) error + List(ctx context.Context, params ChannelMonitorRequestTemplateListParams) ([]*ChannelMonitorRequestTemplate, error) + // ApplyToMonitors 把模板当前的 extra_headers / body_override_mode / body_override + // 批量覆盖到所有 template_id = id 的监控上。返回被覆盖的监控数量。 + ApplyToMonitors(ctx context.Context, id int64) (int64, error) + // CountAssociatedMonitors 统计 template_id = id 的监控数(用于 UI 展示「应用到 N 个配置」)。 + CountAssociatedMonitors(ctx context.Context, id int64) (int64, error) +} + +// ChannelMonitorRequestTemplateService 模板管理 service。 +type ChannelMonitorRequestTemplateService struct { + repo ChannelMonitorRequestTemplateRepository +} + +// NewChannelMonitorRequestTemplateService 创建模板 service。 +func NewChannelMonitorRequestTemplateService(repo ChannelMonitorRequestTemplateRepository) *ChannelMonitorRequestTemplateService { + return &ChannelMonitorRequestTemplateService{repo: repo} +} + +// ---------- CRUD ---------- + +// List 按 provider 过滤(空串 = 全部),不分页(模板量级小)。 +func (s *ChannelMonitorRequestTemplateService) List(ctx context.Context, params ChannelMonitorRequestTemplateListParams) ([]*ChannelMonitorRequestTemplate, error) { + if params.Provider != "" { + if err := validateProvider(params.Provider); err != nil { + return nil, err + } + } + return s.repo.List(ctx, params) +} + +// Get 返回单个模板。 +func (s *ChannelMonitorRequestTemplateService) Get(ctx context.Context, id int64) (*ChannelMonitorRequestTemplate, error) { + return s.repo.GetByID(ctx, id) +} + +// Create 创建模板(会校验 headers 黑名单和 body 模式匹配)。 +func (s *ChannelMonitorRequestTemplateService) Create(ctx context.Context, p ChannelMonitorRequestTemplateCreateParams) (*ChannelMonitorRequestTemplate, error) { + if err := validateTemplateCreateParams(p); err != nil { + return nil, err + } + t := &ChannelMonitorRequestTemplate{ + Name: strings.TrimSpace(p.Name), + Provider: p.Provider, + Description: strings.TrimSpace(p.Description), + ExtraHeaders: emptyHeadersIfNil(p.ExtraHeaders), + BodyOverrideMode: defaultBodyMode(p.BodyOverrideMode), + BodyOverride: p.BodyOverride, + } + if err := s.repo.Create(ctx, t); err != nil { + return nil, fmt.Errorf("create template: %w", err) + } + return t, nil +} + +// Update 更新模板(provider 不可改)。 +func (s *ChannelMonitorRequestTemplateService) Update(ctx context.Context, id int64, p ChannelMonitorRequestTemplateUpdateParams) (*ChannelMonitorRequestTemplate, error) { + existing, err := s.repo.GetByID(ctx, id) + if err != nil { + return nil, err + } + if err := applyTemplateUpdate(existing, p); err != nil { + return nil, err + } + if err := s.repo.Update(ctx, existing); err != nil { + return nil, fmt.Errorf("update template: %w", err) + } + return existing, nil +} + +// Delete 删除模板。关联监控的 template_id 会被 SET NULL,监控保留快照继续跑。 +func (s *ChannelMonitorRequestTemplateService) Delete(ctx context.Context, id int64) error { + if err := s.repo.Delete(ctx, id); err != nil { + return fmt.Errorf("delete template: %w", err) + } + return nil +} + +// ApplyToMonitors 把模板当前配置一键应用到所有关联监控。 +// 返回被影响的监控数。 +func (s *ChannelMonitorRequestTemplateService) ApplyToMonitors(ctx context.Context, id int64) (int64, error) { + if _, err := s.repo.GetByID(ctx, id); err != nil { + return 0, err + } + affected, err := s.repo.ApplyToMonitors(ctx, id) + if err != nil { + return 0, fmt.Errorf("apply template to monitors: %w", err) + } + return affected, nil +} + +// CountAssociatedMonitors 返回关联监控数。 +func (s *ChannelMonitorRequestTemplateService) CountAssociatedMonitors(ctx context.Context, id int64) (int64, error) { + return s.repo.CountAssociatedMonitors(ctx, id) +} + +// ---------- 校验 & 工具 ---------- + +// validateTemplateCreateParams 聚合 create 入参校验,避免函数超过 30 行。 +func validateTemplateCreateParams(p ChannelMonitorRequestTemplateCreateParams) error { + if strings.TrimSpace(p.Name) == "" { + return ErrChannelMonitorTemplateMissingName + } + if err := validateProvider(p.Provider); err != nil { + return ErrChannelMonitorTemplateInvalidProvider + } + if err := validateBodyModeParams(p.BodyOverrideMode, p.BodyOverride); err != nil { + return err + } + if err := validateExtraHeaders(p.ExtraHeaders); err != nil { + return err + } + return nil +} + +// applyTemplateUpdate 把 update params 中非 nil 字段应用到 existing 上。 +func applyTemplateUpdate(existing *ChannelMonitorRequestTemplate, p ChannelMonitorRequestTemplateUpdateParams) error { + if p.Name != nil { + name := strings.TrimSpace(*p.Name) + if name == "" { + return ErrChannelMonitorTemplateMissingName + } + existing.Name = name + } + if p.Description != nil { + existing.Description = strings.TrimSpace(*p.Description) + } + if p.ExtraHeaders != nil { + if err := validateExtraHeaders(*p.ExtraHeaders); err != nil { + return err + } + existing.ExtraHeaders = emptyHeadersIfNil(*p.ExtraHeaders) + } + // BodyOverrideMode / BodyOverride 联合校验:任一变化都用「更新后的值」做校验。 + newMode := existing.BodyOverrideMode + newBody := existing.BodyOverride + if p.BodyOverrideMode != nil { + newMode = *p.BodyOverrideMode + } + if p.BodyOverride != nil { + newBody = *p.BodyOverride + } + if err := validateBodyModeParams(newMode, newBody); err != nil { + return err + } + existing.BodyOverrideMode = defaultBodyMode(newMode) + existing.BodyOverride = newBody + return nil +} + +// validateBodyModeParams 校验 body_override_mode 合法,且 merge/replace 模式下 body_override 非空。 +func validateBodyModeParams(mode string, body map[string]any) error { + switch mode { + case "", MonitorBodyOverrideModeOff: + return nil + case MonitorBodyOverrideModeMerge, MonitorBodyOverrideModeReplace: + if len(body) == 0 { + return ErrChannelMonitorTemplateBodyRequired + } + return nil + default: + return ErrChannelMonitorTemplateInvalidBodyMode + } +} + +// headerNameRegex 合法 header 名:RFC 7230 token(ASCII 可见字符减特殊符号)。 +var headerNameRegex = regexp.MustCompile(`^[A-Za-z0-9!#$%&'*+\-.^_` + "`" + `|~]+$`) + +// forbiddenHeaderNames hop-by-hop + HTTP 客户端自管的 header;禁止用户覆盖, +// 否则会让 Go http.Client 行为异常(双重 Content-Length、连接复用错乱等)。 +var forbiddenHeaderNames = map[string]bool{ + "host": true, + "content-length": true, + "content-encoding": true, + "transfer-encoding": true, + "connection": true, +} + +// IsForbiddenHeaderName 对外暴露,checker 运行时也会再过滤一次做兜底。 +func IsForbiddenHeaderName(name string) bool { + return forbiddenHeaderNames[strings.ToLower(strings.TrimSpace(name))] +} + +// validateExtraHeaders 校验 header 名字格式 + 黑名单。保存时就拒绝非法 header,早失败。 +func validateExtraHeaders(h map[string]string) error { + for k := range h { + if !headerNameRegex.MatchString(k) { + return ErrChannelMonitorTemplateHeaderInvalidName + } + if IsForbiddenHeaderName(k) { + return ErrChannelMonitorTemplateHeaderForbidden + } + } + return nil +} + +// emptyHeadersIfNil 把 nil map 归一成空 map(repo 层写库时 JSONB 需要非 nil)。 +func emptyHeadersIfNil(h map[string]string) map[string]string { + if h == nil { + return map[string]string{} + } + return h +} + +// defaultBodyMode 空串归一为 off。 +func defaultBodyMode(mode string) string { + if mode == "" { + return MonitorBodyOverrideModeOff + } + return mode +} diff --git a/backend/internal/service/channel_monitor_template_types.go b/backend/internal/service/channel_monitor_template_types.go new file mode 100644 index 00000000..a6e2bb59 --- /dev/null +++ b/backend/internal/service/channel_monitor_template_types.go @@ -0,0 +1,74 @@ +package service + +import ( + infraerrors "github.com/Wei-Shaw/sub2api/internal/pkg/errors" + "time" +) + +// ChannelMonitorRequestTemplate 请求模板(service 层模型)。 +// 作用:把一组可复用的 headers + 可选 body 覆盖配置抽出来管理, +// 被监控「应用」时以快照方式拷贝到监控本身的同名字段。 +type ChannelMonitorRequestTemplate struct { + ID int64 + Name string + Provider string + Description string + ExtraHeaders map[string]string + BodyOverrideMode string + BodyOverride map[string]any + CreatedAt time.Time + UpdatedAt time.Time +} + +// ChannelMonitorRequestTemplateListParams 列表过滤。 +type ChannelMonitorRequestTemplateListParams struct { + Provider string // 空 = 全部;非空则按 provider 过滤 +} + +// ChannelMonitorRequestTemplateCreateParams 创建参数。 +type ChannelMonitorRequestTemplateCreateParams struct { + Name string + Provider string + Description string + ExtraHeaders map[string]string + BodyOverrideMode string + BodyOverride map[string]any +} + +// ChannelMonitorRequestTemplateUpdateParams 更新参数(指针字段 = 不修改)。 +// 注意 Provider 不可修改:改 provider 会让已关联监控的 body 黑名单语义错乱。 +type ChannelMonitorRequestTemplateUpdateParams struct { + Name *string + Description *string + ExtraHeaders *map[string]string + BodyOverrideMode *string + BodyOverride *map[string]any +} + +// 模板相关错误(命名与现有 ErrChannelMonitor* 风格保持一致)。 +var ( + ErrChannelMonitorTemplateNotFound = infraerrors.NotFound( + "CHANNEL_MONITOR_TEMPLATE_NOT_FOUND", "channel monitor request template not found", + ) + ErrChannelMonitorTemplateInvalidProvider = infraerrors.BadRequest( + "CHANNEL_MONITOR_TEMPLATE_INVALID_PROVIDER", "template provider must be one of openai/anthropic/gemini", + ) + ErrChannelMonitorTemplateMissingName = infraerrors.BadRequest( + "CHANNEL_MONITOR_TEMPLATE_MISSING_NAME", "template name is required", + ) + ErrChannelMonitorTemplateInvalidBodyMode = infraerrors.BadRequest( + "CHANNEL_MONITOR_TEMPLATE_INVALID_BODY_MODE", "body_override_mode must be one of off/merge/replace", + ) + ErrChannelMonitorTemplateBodyRequired = infraerrors.BadRequest( + "CHANNEL_MONITOR_TEMPLATE_BODY_REQUIRED", "body_override is required when body_override_mode is merge or replace", + ) + ErrChannelMonitorTemplateHeaderForbidden = infraerrors.BadRequest( + "CHANNEL_MONITOR_TEMPLATE_HEADER_FORBIDDEN", "header name is forbidden (hop-by-hop or computed by HTTP client)", + ) + ErrChannelMonitorTemplateHeaderInvalidName = infraerrors.BadRequest( + "CHANNEL_MONITOR_TEMPLATE_HEADER_INVALID_NAME", "header name contains invalid characters", + ) + ErrChannelMonitorTemplateProviderMismatch = infraerrors.BadRequest( + "CHANNEL_MONITOR_TEMPLATE_PROVIDER_MISMATCH", "monitor provider does not match template provider", + ) +) diff --git a/backend/internal/service/channel_monitor_types.go b/backend/internal/service/channel_monitor_types.go index 739c82fb..b797a89b 100644 --- a/backend/internal/service/channel_monitor_types.go +++ b/backend/internal/service/channel_monitor_types.go @@ -2,6 +2,19 @@ package service import "time" +// MonitorBodyOverrideMode 自定义请求体处理模式。 +// +// - off 使用 adapter 默认 body(忽略 BodyOverride) +// - merge adapter 默认 body 与 BodyOverride 浅合并(用户优先; +// model/messages/contents 等关键字段在 checker 黑名单内会被静默丢弃) +// - replace 完全用 BodyOverride 作为 body;跳过 challenge 校验, +// 改成 HTTP 2xx + 响应非空即视为可用(用户负责构造 body) +const ( + MonitorBodyOverrideModeOff = "off" + MonitorBodyOverrideModeMerge = "merge" + MonitorBodyOverrideModeReplace = "replace" +) + // ChannelMonitor 渠道监控配置(service 层模型,不直接暴露 ent 类型)。 type ChannelMonitor struct { ID int64 @@ -19,6 +32,12 @@ type ChannelMonitor struct { CreatedAt time.Time UpdatedAt time.Time + // 请求自定义快照(来自模板拷贝 or 用户手填,运行时直接读取) + TemplateID *int64 // 仅用于 UI 分组 + 一键应用,运行时不用 + ExtraHeaders map[string]string // 与 adapter 默认 headers 合并,用户优先 + BodyOverrideMode string // off / merge / replace + BodyOverride map[string]any // 仅 mode != off 时使用 + // APIKeyDecryptFailed 表示 APIKey 字段无法解密(密钥不一致或损坏)。 // 此时 APIKey 为空字符串,runner / RunCheck 必须跳过该监控并提示重填。 APIKeyDecryptFailed bool @@ -35,16 +54,20 @@ type ChannelMonitorListParams struct { // ChannelMonitorCreateParams 创建参数。 type ChannelMonitorCreateParams struct { - Name string - Provider string - Endpoint string - APIKey string - PrimaryModel string - ExtraModels []string - GroupName string - Enabled bool - IntervalSeconds int - CreatedBy int64 + Name string + Provider string + Endpoint string + APIKey string + PrimaryModel string + ExtraModels []string + GroupName string + Enabled bool + IntervalSeconds int + CreatedBy int64 + TemplateID *int64 + ExtraHeaders map[string]string + BodyOverrideMode string + BodyOverride map[string]any } // ChannelMonitorUpdateParams 更新参数(指针字段表示"未提供则不更新")。 @@ -58,6 +81,14 @@ type ChannelMonitorUpdateParams struct { GroupName *string Enabled *bool IntervalSeconds *int + // 自定义快照字段:指针为 nil 表示不更新,非 nil 覆盖 + // TemplateID *(*int64):用 ** 表达三态:nil=不更新;&nil=清空;&&id=设为 id。 + // 简化处理:用 ClearTemplate 显式标志 + TemplateID(普通指针) + TemplateID *int64 + ClearTemplate bool // true 时无视 TemplateID,把监控的 template_id 置空 + ExtraHeaders *map[string]string + BodyOverrideMode *string + BodyOverride *map[string]any } // CheckResult 单个模型一次检测的结果。 diff --git a/backend/internal/service/wire.go b/backend/internal/service/wire.go index 1482d650..3148f865 100644 --- a/backend/internal/service/wire.go +++ b/backend/internal/service/wire.go @@ -472,6 +472,7 @@ var ProviderSet = wire.NewSet( ProvideBalanceNotifyService, ProvideChannelMonitorService, ProvideChannelMonitorRunner, + NewChannelMonitorRequestTemplateService, ) // ProvidePaymentConfigService wraps NewPaymentConfigService to accept the named diff --git a/backend/migrations/128_add_channel_monitor_request_templates.sql b/backend/migrations/128_add_channel_monitor_request_templates.sql new file mode 100644 index 00000000..2db8fef6 --- /dev/null +++ b/backend/migrations/128_add_channel_monitor_request_templates.sql @@ -0,0 +1,70 @@ +-- Migration: 128_add_channel_monitor_request_templates +-- 加请求模板表 + 给 channel_monitors 加 4 个快照字段(template_id 关联引用 + extra_headers / +-- body_override_mode / body_override 三个真正运行时使用的快照)。 +-- +-- 设计要点: +-- 1) 模板与监控之间是「应用即拷贝」的快照语义,运行时 checker 不再回查模板表。 +-- 模板 UPDATE 不会自动影响监控;只有用户主动「应用到关联监控」才会刷新快照。 +-- 2) ON DELETE SET NULL:模板删除不级联清理监控;监控保留快照继续工作。 +-- 3) extra_headers / body_override 都是 JSONB;body_override_mode 用 varchar(不是 enum) +-- 便于将来加新模式无需 ALTER TYPE。 +-- 4) 同一 provider 内模板 name 唯一(允许 Anthropic + OpenAI 重名 "伪装官方客户端")。 + +CREATE TABLE IF NOT EXISTS channel_monitor_request_templates ( + id BIGSERIAL PRIMARY KEY, + name VARCHAR(100) NOT NULL, + provider VARCHAR(20) NOT NULL, + description VARCHAR(500) NOT NULL DEFAULT '', + extra_headers JSONB NOT NULL DEFAULT '{}'::jsonb, + body_override_mode VARCHAR(10) NOT NULL DEFAULT 'off', + body_override JSONB NULL, + created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), + updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), + CONSTRAINT channel_monitor_request_templates_provider_check + CHECK (provider IN ('openai', 'anthropic', 'gemini')), + CONSTRAINT channel_monitor_request_templates_body_mode_check + CHECK (body_override_mode IN ('off', 'merge', 'replace')) +); + +CREATE UNIQUE INDEX IF NOT EXISTS channel_monitor_request_templates_provider_name + ON channel_monitor_request_templates (provider, name); + +-- channel_monitors 加 4 列(ADD COLUMN IF NOT EXISTS 需要 PG 9.6+,生产使用 PG 16) +ALTER TABLE channel_monitors + ADD COLUMN IF NOT EXISTS template_id BIGINT NULL; +ALTER TABLE channel_monitors + ADD COLUMN IF NOT EXISTS extra_headers JSONB NOT NULL DEFAULT '{}'::jsonb; +ALTER TABLE channel_monitors + ADD COLUMN IF NOT EXISTS body_override_mode VARCHAR(10) NOT NULL DEFAULT 'off'; +ALTER TABLE channel_monitors + ADD COLUMN IF NOT EXISTS body_override JSONB NULL; + +-- 约束 + 外键(DO 块里 IF NOT EXISTS 判断,保证幂等) +DO $$ +BEGIN + IF NOT EXISTS ( + SELECT 1 FROM information_schema.table_constraints + WHERE constraint_name = 'channel_monitors_body_mode_check' + AND table_name = 'channel_monitors' + ) THEN + ALTER TABLE channel_monitors + ADD CONSTRAINT channel_monitors_body_mode_check + CHECK (body_override_mode IN ('off', 'merge', 'replace')); + END IF; + + IF NOT EXISTS ( + SELECT 1 FROM information_schema.table_constraints + WHERE constraint_name = 'channel_monitors_template_id_fkey' + AND table_name = 'channel_monitors' + ) THEN + ALTER TABLE channel_monitors + ADD CONSTRAINT channel_monitors_template_id_fkey + FOREIGN KEY (template_id) + REFERENCES channel_monitor_request_templates (id) + ON DELETE SET NULL; + END IF; +END $$; + +CREATE INDEX IF NOT EXISTS idx_channel_monitors_template_id + ON channel_monitors (template_id) + WHERE template_id IS NOT NULL; diff --git a/frontend/src/api/admin/channelMonitor.ts b/frontend/src/api/admin/channelMonitor.ts index d9cc6aed..949c4bc8 100644 --- a/frontend/src/api/admin/channelMonitor.ts +++ b/frontend/src/api/admin/channelMonitor.ts @@ -7,6 +7,7 @@ import { apiClient } from '../client' export type Provider = 'openai' | 'anthropic' | 'gemini' export type MonitorStatus = 'operational' | 'degraded' | 'failed' | 'error' +export type BodyOverrideMode = 'off' | 'merge' | 'replace' export interface ChannelMonitor { id: number @@ -37,6 +38,11 @@ export interface ChannelMonitor { availability_7d: number /** Latest status per extra model (used for hover tooltip) */ extra_models_status: ExtraModelStatus[] + /** 请求自定义快照字段(高级设置) */ + template_id: number | null + extra_headers: Record + body_override_mode: BodyOverrideMode + body_override: Record | null } export interface ExtraModelStatus { @@ -71,10 +77,16 @@ export interface CreateParams { group_name?: string enabled?: boolean interval_seconds: number + template_id?: number | null + extra_headers?: Record + body_override_mode?: BodyOverrideMode + body_override?: Record | null } -// Update request: api_key empty string means "do not modify" -export type UpdateParams = Partial +// Update request: api_key 空串 = 不修改;clear_template=true 时把 template_id 置空 +export type UpdateParams = Partial & { + clear_template?: boolean +} export interface CheckResult { model: string diff --git a/frontend/src/api/admin/channelMonitorTemplate.ts b/frontend/src/api/admin/channelMonitorTemplate.ts new file mode 100644 index 00000000..258adab8 --- /dev/null +++ b/frontend/src/api/admin/channelMonitorTemplate.ts @@ -0,0 +1,108 @@ +/** + * Admin Channel Monitor Request Template API. + * + * 模板 = 一组可复用的 headers + 可选 body 覆盖配置。 + * 应用到监控 = 拷贝快照;模板后续变动不自动同步,需手动点「应用到关联监控」刷新。 + */ + +import { apiClient } from '../client' +import type { BodyOverrideMode, Provider } from './channelMonitor' + +export interface ChannelMonitorTemplate { + id: number + name: string + provider: Provider + description: string + extra_headers: Record + body_override_mode: BodyOverrideMode + body_override: Record | null + created_at: string + updated_at: string + /** 关联的监控数量(快照来自此模板,仅 template_id 匹配即可) */ + associated_monitors: number +} + +export interface ListParams { + provider?: Provider +} + +export interface ListResponse { + items: ChannelMonitorTemplate[] +} + +export interface CreateParams { + name: string + provider: Provider + description?: string + extra_headers?: Record + body_override_mode?: BodyOverrideMode + body_override?: Record | null +} + +export interface UpdateParams { + name?: string + description?: string + extra_headers?: Record + body_override_mode?: BodyOverrideMode + body_override?: Record | null +} + +export interface ApplyResponse { + affected: number +} + +export async function list(params: ListParams = {}): Promise { + const { data } = await apiClient.get('/admin/channel-monitor-templates', { + params, + }) + return data +} + +export async function get(id: number): Promise { + const { data } = await apiClient.get( + `/admin/channel-monitor-templates/${id}`, + ) + return data +} + +export async function create(params: CreateParams): Promise { + const { data } = await apiClient.post( + '/admin/channel-monitor-templates', + params, + ) + return data +} + +export async function update(id: number, params: UpdateParams): Promise { + const { data } = await apiClient.put( + `/admin/channel-monitor-templates/${id}`, + params, + ) + return data +} + +export async function del(id: number): Promise { + await apiClient.delete(`/admin/channel-monitor-templates/${id}`) +} + +/** + * Apply the template to all associated monitors (overwrite snapshot fields). + * Returns count of affected monitors. + */ +export async function apply(id: number): Promise { + const { data } = await apiClient.post( + `/admin/channel-monitor-templates/${id}/apply`, + ) + return data +} + +export const channelMonitorTemplateAPI = { + list, + get, + create, + update, + del, + apply, +} + +export default channelMonitorTemplateAPI diff --git a/frontend/src/api/admin/index.ts b/frontend/src/api/admin/index.ts index 5e2a9959..9cda5814 100644 --- a/frontend/src/api/admin/index.ts +++ b/frontend/src/api/admin/index.ts @@ -27,6 +27,7 @@ import backupAPI from './backup' import tlsFingerprintProfileAPI from './tlsFingerprintProfile' import channelsAPI from './channels' import channelMonitorAPI from './channelMonitor' +import channelMonitorTemplateAPI from './channelMonitorTemplate' import adminPaymentAPI from './payment' /** @@ -57,6 +58,7 @@ export const adminAPI = { tlsFingerprintProfiles: tlsFingerprintProfileAPI, channels: channelsAPI, channelMonitor: channelMonitorAPI, + channelMonitorTemplate: channelMonitorTemplateAPI, payment: adminPaymentAPI } @@ -85,6 +87,7 @@ export { tlsFingerprintProfileAPI, channelsAPI, channelMonitorAPI, + channelMonitorTemplateAPI, adminPaymentAPI } diff --git a/frontend/src/components/admin/monitor/MonitorAdvancedRequestConfig.vue b/frontend/src/components/admin/monitor/MonitorAdvancedRequestConfig.vue new file mode 100644 index 00000000..24827316 --- /dev/null +++ b/frontend/src/components/admin/monitor/MonitorAdvancedRequestConfig.vue @@ -0,0 +1,205 @@ +