update tasks so they are by ip due to spammers

This commit is contained in:
maddalax 2024-09-29 01:36:39 -05:00
parent fce0dfe746
commit 13538191c9
13 changed files with 324 additions and 25 deletions

View file

@ -16,6 +16,7 @@ var (
{Name: "updated_at", Type: field.TypeTime, Default: "CURRENT_TIMESTAMP"}, {Name: "updated_at", Type: field.TypeTime, Default: "CURRENT_TIMESTAMP"},
{Name: "completed_at", Type: field.TypeTime, Nullable: true}, {Name: "completed_at", Type: field.TypeTime, Nullable: true},
{Name: "tags", Type: field.TypeJSON, Nullable: true}, {Name: "tags", Type: field.TypeJSON, Nullable: true},
{Name: "ip_address", Type: field.TypeString, Nullable: true, Default: ""},
} }
// TasksTable holds the schema information for the "tasks" table. // TasksTable holds the schema information for the "tasks" table.
TasksTable = &schema.Table{ TasksTable = &schema.Table{

View file

@ -31,8 +31,8 @@ const (
// TaskMutation represents an operation that mutates the Task nodes in the graph. // TaskMutation represents an operation that mutates the Task nodes in the graph.
type TaskMutation struct { type TaskMutation struct {
config config
op Op op Op
typ string typ string
id *uuid.UUID id *uuid.UUID
name *string name *string
created_at *time.Time created_at *time.Time
@ -40,10 +40,11 @@ type TaskMutation struct {
completed_at *time.Time completed_at *time.Time
tags *[]string tags *[]string
appendtags []string appendtags []string
ip_address *string
clearedFields map[string]struct{} clearedFields map[string]struct{}
done bool done bool
oldValue func(context.Context) (*Task, error) oldValue func(context.Context) (*Task, error)
predicates []predicate.Task predicates []predicate.Task
} }
var _ ent.Mutation = (*TaskMutation)(nil) var _ ent.Mutation = (*TaskMutation)(nil)
@ -372,6 +373,55 @@ func (m *TaskMutation) ResetTags() {
delete(m.clearedFields, task.FieldTags) delete(m.clearedFields, task.FieldTags)
} }
// SetIPAddress sets the "ip_address" field.
func (m *TaskMutation) SetIPAddress(s string) {
m.ip_address = &s
}
// IPAddress returns the value of the "ip_address" field in the mutation.
func (m *TaskMutation) IPAddress() (r string, exists bool) {
v := m.ip_address
if v == nil {
return
}
return *v, true
}
// OldIPAddress returns the old "ip_address" field's value of the Task entity.
// If the Task 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 *TaskMutation) OldIPAddress(ctx context.Context) (v string, err error) {
if !m.op.Is(OpUpdateOne) {
return v, errors.New("OldIPAddress is only allowed on UpdateOne operations")
}
if m.id == nil || m.oldValue == nil {
return v, errors.New("OldIPAddress requires an ID field in the mutation")
}
oldValue, err := m.oldValue(ctx)
if err != nil {
return v, fmt.Errorf("querying old value for OldIPAddress: %w", err)
}
return oldValue.IPAddress, nil
}
// ClearIPAddress clears the value of the "ip_address" field.
func (m *TaskMutation) ClearIPAddress() {
m.ip_address = nil
m.clearedFields[task.FieldIPAddress] = struct{}{}
}
// IPAddressCleared returns if the "ip_address" field was cleared in this mutation.
func (m *TaskMutation) IPAddressCleared() bool {
_, ok := m.clearedFields[task.FieldIPAddress]
return ok
}
// ResetIPAddress resets all changes to the "ip_address" field.
func (m *TaskMutation) ResetIPAddress() {
m.ip_address = nil
delete(m.clearedFields, task.FieldIPAddress)
}
// Where appends a list predicates to the TaskMutation builder. // Where appends a list predicates to the TaskMutation builder.
func (m *TaskMutation) Where(ps ...predicate.Task) { func (m *TaskMutation) Where(ps ...predicate.Task) {
m.predicates = append(m.predicates, ps...) m.predicates = append(m.predicates, ps...)
@ -406,7 +456,7 @@ func (m *TaskMutation) Type() string {
// order to get all numeric fields that were incremented/decremented, call // order to get all numeric fields that were incremented/decremented, call
// AddedFields(). // AddedFields().
func (m *TaskMutation) Fields() []string { func (m *TaskMutation) Fields() []string {
fields := make([]string, 0, 5) fields := make([]string, 0, 6)
if m.name != nil { if m.name != nil {
fields = append(fields, task.FieldName) fields = append(fields, task.FieldName)
} }
@ -422,6 +472,9 @@ func (m *TaskMutation) Fields() []string {
if m.tags != nil { if m.tags != nil {
fields = append(fields, task.FieldTags) fields = append(fields, task.FieldTags)
} }
if m.ip_address != nil {
fields = append(fields, task.FieldIPAddress)
}
return fields return fields
} }
@ -440,6 +493,8 @@ func (m *TaskMutation) Field(name string) (ent.Value, bool) {
return m.CompletedAt() return m.CompletedAt()
case task.FieldTags: case task.FieldTags:
return m.Tags() return m.Tags()
case task.FieldIPAddress:
return m.IPAddress()
} }
return nil, false return nil, false
} }
@ -459,6 +514,8 @@ func (m *TaskMutation) OldField(ctx context.Context, name string) (ent.Value, er
return m.OldCompletedAt(ctx) return m.OldCompletedAt(ctx)
case task.FieldTags: case task.FieldTags:
return m.OldTags(ctx) return m.OldTags(ctx)
case task.FieldIPAddress:
return m.OldIPAddress(ctx)
} }
return nil, fmt.Errorf("unknown Task field %s", name) return nil, fmt.Errorf("unknown Task field %s", name)
} }
@ -503,6 +560,13 @@ func (m *TaskMutation) SetField(name string, value ent.Value) error {
} }
m.SetTags(v) m.SetTags(v)
return nil return nil
case task.FieldIPAddress:
v, ok := value.(string)
if !ok {
return fmt.Errorf("unexpected type %T for field %s", value, name)
}
m.SetIPAddress(v)
return nil
} }
return fmt.Errorf("unknown Task field %s", name) return fmt.Errorf("unknown Task field %s", name)
} }
@ -539,6 +603,9 @@ func (m *TaskMutation) ClearedFields() []string {
if m.FieldCleared(task.FieldTags) { if m.FieldCleared(task.FieldTags) {
fields = append(fields, task.FieldTags) fields = append(fields, task.FieldTags)
} }
if m.FieldCleared(task.FieldIPAddress) {
fields = append(fields, task.FieldIPAddress)
}
return fields return fields
} }
@ -559,6 +626,9 @@ func (m *TaskMutation) ClearField(name string) error {
case task.FieldTags: case task.FieldTags:
m.ClearTags() m.ClearTags()
return nil return nil
case task.FieldIPAddress:
m.ClearIPAddress()
return nil
} }
return fmt.Errorf("unknown Task nullable field %s", name) return fmt.Errorf("unknown Task nullable field %s", name)
} }
@ -582,6 +652,9 @@ func (m *TaskMutation) ResetField(name string) error {
case task.FieldTags: case task.FieldTags:
m.ResetTags() m.ResetTags()
return nil return nil
case task.FieldIPAddress:
m.ResetIPAddress()
return nil
} }
return fmt.Errorf("unknown Task field %s", name) return fmt.Errorf("unknown Task field %s", name)
} }

View file

@ -28,6 +28,10 @@ func init() {
taskDescUpdatedAt := taskFields[3].Descriptor() taskDescUpdatedAt := taskFields[3].Descriptor()
// task.DefaultUpdatedAt holds the default value on creation for the updated_at field. // task.DefaultUpdatedAt holds the default value on creation for the updated_at field.
task.DefaultUpdatedAt = taskDescUpdatedAt.Default.(func() time.Time) task.DefaultUpdatedAt = taskDescUpdatedAt.Default.(func() time.Time)
// taskDescIPAddress is the schema descriptor for ip_address field.
taskDescIPAddress := taskFields[6].Descriptor()
// task.DefaultIPAddress holds the default value on creation for the ip_address field.
task.DefaultIPAddress = taskDescIPAddress.Default.(string)
// taskDescID is the schema descriptor for id field. // taskDescID is the schema descriptor for id field.
taskDescID := taskFields[0].Descriptor() taskDescID := taskFields[0].Descriptor()
// task.DefaultID holds the default value on creation for the id field. // task.DefaultID holds the default value on creation for the id field.

View file

@ -17,8 +17,7 @@ func (Task) Fields() []ent.Field {
return []ent.Field{ return []ent.Field{
field.UUID("id", uuid.UUID{}). field.UUID("id", uuid.UUID{}).
Default(uuid.New), Default(uuid.New),
field.String("name"). field.String("name").Default("unknown"),
Default("unknown"),
field.Time("created_at").Default(time.Now).Annotations( field.Time("created_at").Default(time.Now).Annotations(
entsql.Default("CURRENT_TIMESTAMP"), entsql.Default("CURRENT_TIMESTAMP"),
), ),
@ -27,6 +26,7 @@ func (Task) Fields() []ent.Field {
), ),
field.Time("completed_at").Optional().Nillable(), field.Time("completed_at").Optional().Nillable(),
field.Strings("tags").Optional(), field.Strings("tags").Optional(),
field.String("ip_address").Optional().Default(""),
} }
} }

View file

@ -28,7 +28,9 @@ type Task struct {
// CompletedAt holds the value of the "completed_at" field. // CompletedAt holds the value of the "completed_at" field.
CompletedAt *time.Time `json:"completed_at,omitempty"` CompletedAt *time.Time `json:"completed_at,omitempty"`
// Tags holds the value of the "tags" field. // Tags holds the value of the "tags" field.
Tags []string `json:"tags,omitempty"` Tags []string `json:"tags,omitempty"`
// IPAddress holds the value of the "ip_address" field.
IPAddress string `json:"ip_address,omitempty"`
selectValues sql.SelectValues selectValues sql.SelectValues
} }
@ -39,7 +41,7 @@ func (*Task) scanValues(columns []string) ([]any, error) {
switch columns[i] { switch columns[i] {
case task.FieldTags: case task.FieldTags:
values[i] = new([]byte) values[i] = new([]byte)
case task.FieldName: case task.FieldName, task.FieldIPAddress:
values[i] = new(sql.NullString) values[i] = new(sql.NullString)
case task.FieldCreatedAt, task.FieldUpdatedAt, task.FieldCompletedAt: case task.FieldCreatedAt, task.FieldUpdatedAt, task.FieldCompletedAt:
values[i] = new(sql.NullTime) values[i] = new(sql.NullTime)
@ -99,6 +101,12 @@ func (t *Task) assignValues(columns []string, values []any) error {
return fmt.Errorf("unmarshal field tags: %w", err) return fmt.Errorf("unmarshal field tags: %w", err)
} }
} }
case task.FieldIPAddress:
if value, ok := values[i].(*sql.NullString); !ok {
return fmt.Errorf("unexpected type %T for field ip_address", values[i])
} else if value.Valid {
t.IPAddress = value.String
}
default: default:
t.selectValues.Set(columns[i], values[i]) t.selectValues.Set(columns[i], values[i])
} }
@ -151,6 +159,9 @@ func (t *Task) String() string {
builder.WriteString(", ") builder.WriteString(", ")
builder.WriteString("tags=") builder.WriteString("tags=")
builder.WriteString(fmt.Sprintf("%v", t.Tags)) builder.WriteString(fmt.Sprintf("%v", t.Tags))
builder.WriteString(", ")
builder.WriteString("ip_address=")
builder.WriteString(t.IPAddress)
builder.WriteByte(')') builder.WriteByte(')')
return builder.String() return builder.String()
} }

View file

@ -24,6 +24,8 @@ const (
FieldCompletedAt = "completed_at" FieldCompletedAt = "completed_at"
// FieldTags holds the string denoting the tags field in the database. // FieldTags holds the string denoting the tags field in the database.
FieldTags = "tags" FieldTags = "tags"
// FieldIPAddress holds the string denoting the ip_address field in the database.
FieldIPAddress = "ip_address"
// Table holds the table name of the task in the database. // Table holds the table name of the task in the database.
Table = "tasks" Table = "tasks"
) )
@ -36,6 +38,7 @@ var Columns = []string{
FieldUpdatedAt, FieldUpdatedAt,
FieldCompletedAt, FieldCompletedAt,
FieldTags, FieldTags,
FieldIPAddress,
} }
// ValidColumn reports if the column name is valid (part of the table columns). // ValidColumn reports if the column name is valid (part of the table columns).
@ -55,6 +58,8 @@ var (
DefaultCreatedAt func() time.Time DefaultCreatedAt func() time.Time
// DefaultUpdatedAt holds the default value on creation for the "updated_at" field. // DefaultUpdatedAt holds the default value on creation for the "updated_at" field.
DefaultUpdatedAt func() time.Time DefaultUpdatedAt func() time.Time
// DefaultIPAddress holds the default value on creation for the "ip_address" field.
DefaultIPAddress string
// DefaultID holds the default value on creation for the "id" field. // DefaultID holds the default value on creation for the "id" field.
DefaultID func() uuid.UUID DefaultID func() uuid.UUID
) )
@ -86,3 +91,8 @@ func ByUpdatedAt(opts ...sql.OrderTermOption) OrderOption {
func ByCompletedAt(opts ...sql.OrderTermOption) OrderOption { func ByCompletedAt(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldCompletedAt, opts...).ToFunc() return sql.OrderByField(FieldCompletedAt, opts...).ToFunc()
} }
// ByIPAddress orders the results by the ip_address field.
func ByIPAddress(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldIPAddress, opts...).ToFunc()
}

View file

@ -75,6 +75,11 @@ func CompletedAt(v time.Time) predicate.Task {
return predicate.Task(sql.FieldEQ(FieldCompletedAt, v)) return predicate.Task(sql.FieldEQ(FieldCompletedAt, v))
} }
// IPAddress applies equality check predicate on the "ip_address" field. It's identical to IPAddressEQ.
func IPAddress(v string) predicate.Task {
return predicate.Task(sql.FieldEQ(FieldIPAddress, v))
}
// NameEQ applies the EQ predicate on the "name" field. // NameEQ applies the EQ predicate on the "name" field.
func NameEQ(v string) predicate.Task { func NameEQ(v string) predicate.Task {
return predicate.Task(sql.FieldEQ(FieldName, v)) return predicate.Task(sql.FieldEQ(FieldName, v))
@ -280,6 +285,81 @@ func TagsNotNil() predicate.Task {
return predicate.Task(sql.FieldNotNull(FieldTags)) return predicate.Task(sql.FieldNotNull(FieldTags))
} }
// IPAddressEQ applies the EQ predicate on the "ip_address" field.
func IPAddressEQ(v string) predicate.Task {
return predicate.Task(sql.FieldEQ(FieldIPAddress, v))
}
// IPAddressNEQ applies the NEQ predicate on the "ip_address" field.
func IPAddressNEQ(v string) predicate.Task {
return predicate.Task(sql.FieldNEQ(FieldIPAddress, v))
}
// IPAddressIn applies the In predicate on the "ip_address" field.
func IPAddressIn(vs ...string) predicate.Task {
return predicate.Task(sql.FieldIn(FieldIPAddress, vs...))
}
// IPAddressNotIn applies the NotIn predicate on the "ip_address" field.
func IPAddressNotIn(vs ...string) predicate.Task {
return predicate.Task(sql.FieldNotIn(FieldIPAddress, vs...))
}
// IPAddressGT applies the GT predicate on the "ip_address" field.
func IPAddressGT(v string) predicate.Task {
return predicate.Task(sql.FieldGT(FieldIPAddress, v))
}
// IPAddressGTE applies the GTE predicate on the "ip_address" field.
func IPAddressGTE(v string) predicate.Task {
return predicate.Task(sql.FieldGTE(FieldIPAddress, v))
}
// IPAddressLT applies the LT predicate on the "ip_address" field.
func IPAddressLT(v string) predicate.Task {
return predicate.Task(sql.FieldLT(FieldIPAddress, v))
}
// IPAddressLTE applies the LTE predicate on the "ip_address" field.
func IPAddressLTE(v string) predicate.Task {
return predicate.Task(sql.FieldLTE(FieldIPAddress, v))
}
// IPAddressContains applies the Contains predicate on the "ip_address" field.
func IPAddressContains(v string) predicate.Task {
return predicate.Task(sql.FieldContains(FieldIPAddress, v))
}
// IPAddressHasPrefix applies the HasPrefix predicate on the "ip_address" field.
func IPAddressHasPrefix(v string) predicate.Task {
return predicate.Task(sql.FieldHasPrefix(FieldIPAddress, v))
}
// IPAddressHasSuffix applies the HasSuffix predicate on the "ip_address" field.
func IPAddressHasSuffix(v string) predicate.Task {
return predicate.Task(sql.FieldHasSuffix(FieldIPAddress, v))
}
// IPAddressIsNil applies the IsNil predicate on the "ip_address" field.
func IPAddressIsNil() predicate.Task {
return predicate.Task(sql.FieldIsNull(FieldIPAddress))
}
// IPAddressNotNil applies the NotNil predicate on the "ip_address" field.
func IPAddressNotNil() predicate.Task {
return predicate.Task(sql.FieldNotNull(FieldIPAddress))
}
// IPAddressEqualFold applies the EqualFold predicate on the "ip_address" field.
func IPAddressEqualFold(v string) predicate.Task {
return predicate.Task(sql.FieldEqualFold(FieldIPAddress, v))
}
// IPAddressContainsFold applies the ContainsFold predicate on the "ip_address" field.
func IPAddressContainsFold(v string) predicate.Task {
return predicate.Task(sql.FieldContainsFold(FieldIPAddress, v))
}
// And groups predicates with the AND operator between them. // And groups predicates with the AND operator between them.
func And(predicates ...predicate.Task) predicate.Task { func And(predicates ...predicate.Task) predicate.Task {
return predicate.Task(sql.AndPredicates(predicates...)) return predicate.Task(sql.AndPredicates(predicates...))

View file

@ -83,6 +83,20 @@ func (tc *TaskCreate) SetTags(s []string) *TaskCreate {
return tc return tc
} }
// SetIPAddress sets the "ip_address" field.
func (tc *TaskCreate) SetIPAddress(s string) *TaskCreate {
tc.mutation.SetIPAddress(s)
return tc
}
// SetNillableIPAddress sets the "ip_address" field if the given value is not nil.
func (tc *TaskCreate) SetNillableIPAddress(s *string) *TaskCreate {
if s != nil {
tc.SetIPAddress(*s)
}
return tc
}
// SetID sets the "id" field. // SetID sets the "id" field.
func (tc *TaskCreate) SetID(u uuid.UUID) *TaskCreate { func (tc *TaskCreate) SetID(u uuid.UUID) *TaskCreate {
tc.mutation.SetID(u) tc.mutation.SetID(u)
@ -144,6 +158,10 @@ func (tc *TaskCreate) defaults() {
v := task.DefaultUpdatedAt() v := task.DefaultUpdatedAt()
tc.mutation.SetUpdatedAt(v) tc.mutation.SetUpdatedAt(v)
} }
if _, ok := tc.mutation.IPAddress(); !ok {
v := task.DefaultIPAddress
tc.mutation.SetIPAddress(v)
}
if _, ok := tc.mutation.ID(); !ok { if _, ok := tc.mutation.ID(); !ok {
v := task.DefaultID() v := task.DefaultID()
tc.mutation.SetID(v) tc.mutation.SetID(v)
@ -216,6 +234,10 @@ func (tc *TaskCreate) createSpec() (*Task, *sqlgraph.CreateSpec) {
_spec.SetField(task.FieldTags, field.TypeJSON, value) _spec.SetField(task.FieldTags, field.TypeJSON, value)
_node.Tags = value _node.Tags = value
} }
if value, ok := tc.mutation.IPAddress(); ok {
_spec.SetField(task.FieldIPAddress, field.TypeString, value)
_node.IPAddress = value
}
return _node, _spec return _node, _spec
} }

View file

@ -109,6 +109,26 @@ func (tu *TaskUpdate) ClearTags() *TaskUpdate {
return tu return tu
} }
// SetIPAddress sets the "ip_address" field.
func (tu *TaskUpdate) SetIPAddress(s string) *TaskUpdate {
tu.mutation.SetIPAddress(s)
return tu
}
// SetNillableIPAddress sets the "ip_address" field if the given value is not nil.
func (tu *TaskUpdate) SetNillableIPAddress(s *string) *TaskUpdate {
if s != nil {
tu.SetIPAddress(*s)
}
return tu
}
// ClearIPAddress clears the value of the "ip_address" field.
func (tu *TaskUpdate) ClearIPAddress() *TaskUpdate {
tu.mutation.ClearIPAddress()
return tu
}
// Mutation returns the TaskMutation object of the builder. // Mutation returns the TaskMutation object of the builder.
func (tu *TaskUpdate) Mutation() *TaskMutation { func (tu *TaskUpdate) Mutation() *TaskMutation {
return tu.mutation return tu.mutation
@ -176,6 +196,12 @@ func (tu *TaskUpdate) sqlSave(ctx context.Context) (n int, err error) {
if tu.mutation.TagsCleared() { if tu.mutation.TagsCleared() {
_spec.ClearField(task.FieldTags, field.TypeJSON) _spec.ClearField(task.FieldTags, field.TypeJSON)
} }
if value, ok := tu.mutation.IPAddress(); ok {
_spec.SetField(task.FieldIPAddress, field.TypeString, value)
}
if tu.mutation.IPAddressCleared() {
_spec.ClearField(task.FieldIPAddress, field.TypeString)
}
if n, err = sqlgraph.UpdateNodes(ctx, tu.driver, _spec); err != nil { if n, err = sqlgraph.UpdateNodes(ctx, tu.driver, _spec); err != nil {
if _, ok := err.(*sqlgraph.NotFoundError); ok { if _, ok := err.(*sqlgraph.NotFoundError); ok {
err = &NotFoundError{task.Label} err = &NotFoundError{task.Label}
@ -276,6 +302,26 @@ func (tuo *TaskUpdateOne) ClearTags() *TaskUpdateOne {
return tuo return tuo
} }
// SetIPAddress sets the "ip_address" field.
func (tuo *TaskUpdateOne) SetIPAddress(s string) *TaskUpdateOne {
tuo.mutation.SetIPAddress(s)
return tuo
}
// SetNillableIPAddress sets the "ip_address" field if the given value is not nil.
func (tuo *TaskUpdateOne) SetNillableIPAddress(s *string) *TaskUpdateOne {
if s != nil {
tuo.SetIPAddress(*s)
}
return tuo
}
// ClearIPAddress clears the value of the "ip_address" field.
func (tuo *TaskUpdateOne) ClearIPAddress() *TaskUpdateOne {
tuo.mutation.ClearIPAddress()
return tuo
}
// Mutation returns the TaskMutation object of the builder. // Mutation returns the TaskMutation object of the builder.
func (tuo *TaskUpdateOne) Mutation() *TaskMutation { func (tuo *TaskUpdateOne) Mutation() *TaskMutation {
return tuo.mutation return tuo.mutation
@ -373,6 +419,12 @@ func (tuo *TaskUpdateOne) sqlSave(ctx context.Context) (_node *Task, err error)
if tuo.mutation.TagsCleared() { if tuo.mutation.TagsCleared() {
_spec.ClearField(task.FieldTags, field.TypeJSON) _spec.ClearField(task.FieldTags, field.TypeJSON)
} }
if value, ok := tuo.mutation.IPAddress(); ok {
_spec.SetField(task.FieldIPAddress, field.TypeString, value)
}
if tuo.mutation.IPAddressCleared() {
_spec.ClearField(task.FieldIPAddress, field.TypeString)
}
_node = &Task{config: tuo.config} _node = &Task{config: tuo.config}
_spec.Assign = _node.assignValues _spec.Assign = _node.assignValues
_spec.ScanValues = _node.scanValues _spec.ScanValues = _node.scanValues

View file

@ -35,14 +35,22 @@ github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/maddalax/htmgo/framework v0.0.0-20240929054559-c045e880a7c7 h1:aORZEDTAjTaF2FWIpiFOFnNpAUMl02wIUMvhs8du/AM= github.com/maddalax/htmgo/framework v0.0.0-20240929054559-c045e880a7c7 h1:aORZEDTAjTaF2FWIpiFOFnNpAUMl02wIUMvhs8du/AM=
github.com/maddalax/htmgo/framework v0.0.0-20240929054559-c045e880a7c7/go.mod h1:HYKI49Pb6oyY2opSJdTt145B1vWgfWIDohvlolynv80= github.com/maddalax/htmgo/framework v0.0.0-20240929054559-c045e880a7c7/go.mod h1:HYKI49Pb6oyY2opSJdTt145B1vWgfWIDohvlolynv80=
github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-sqlite3 v1.14.23 h1:gbShiuAP1W5j9UOksQ06aiiqPMxYecovVGwmTxWtuw0= github.com/mattn/go-sqlite3 v1.14.23 h1:gbShiuAP1W5j9UOksQ06aiiqPMxYecovVGwmTxWtuw0=
github.com/mattn/go-sqlite3 v1.14.23/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= github.com/mattn/go-sqlite3 v1.14.23/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7 h1:DpOJ2HYzCv8LZP15IdmG+YdwD2luVPHITV96TkirNBM= github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7 h1:DpOJ2HYzCv8LZP15IdmG+YdwD2luVPHITV96TkirNBM=
github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ= github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ=
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I=
github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/vmihailenco/msgpack/v4 v4.3.12/go.mod h1:gborTTJjAo/GWTqqRjrLCn9pgNN+NXzzngzBKDPIqw4= github.com/vmihailenco/msgpack/v4 v4.3.12/go.mod h1:gborTTJjAo/GWTqqRjrLCn9pgNN+NXzzngzBKDPIqw4=
@ -56,6 +64,8 @@ golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo=
golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0=
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
@ -63,6 +73,8 @@ golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224=
golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24=
golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ=
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=

View file

@ -3,15 +3,18 @@ package tasks
import ( import (
"context" "context"
"github.com/google/uuid" "github.com/google/uuid"
"github.com/maddalax/htmgo/framework/h"
"github.com/maddalax/htmgo/framework/service" "github.com/maddalax/htmgo/framework/service"
"time" "time"
"todolist/ent" "todolist/ent"
"todolist/ent/predicate" "todolist/ent/predicate"
"todolist/ent/task" "todolist/ent/task"
"todolist/internal/util"
) )
type Service struct { type Service struct {
db *ent.Client db *ent.Client
ipAddress string
} }
type CreateRequest struct { type CreateRequest struct {
@ -19,9 +22,10 @@ type CreateRequest struct {
Tags []string Tags []string
} }
func NewService(locator *service.Locator) Service { func NewService(ctx *h.RequestContext) Service {
return Service{ return Service{
db: service.Get[ent.Client](locator), ipAddress: util.GetClientIp(ctx.Request),
db: service.Get[ent.Client](ctx.ServiceLocator()),
} }
} }
@ -29,6 +33,7 @@ func (s *Service) Create(request CreateRequest) (*ent.Task, error) {
return s.db.Task.Create(). return s.db.Task.Create().
SetName(request.Name). SetName(request.Name).
SetTags(request.Tags). SetTags(request.Tags).
SetIPAddress(s.ipAddress).
Save(context.Background()) Save(context.Background())
} }
@ -37,7 +42,7 @@ func (s *Service) Get(id uuid.UUID) (*ent.Task, error) {
} }
func (s *Service) SetName(id uuid.UUID, name string) (*ent.Task, error) { func (s *Service) SetName(id uuid.UUID, name string) (*ent.Task, error) {
return s.db.Task.UpdateOneID(id).SetName(name).Save(context.Background()) return s.db.Task.UpdateOneID(id).Where(task.IPAddress(s.ipAddress)).SetName(name).Save(context.Background())
} }
func (s *Service) SetAllCompleted(value bool) error { func (s *Service) SetAllCompleted(value bool) error {
@ -51,6 +56,7 @@ func (s *Service) SetAllCompleted(value bool) error {
} }
_, err := updater. _, err := updater.
Where(task.IPAddress(s.ipAddress)).
SetUpdatedAt(time.Now()). SetUpdatedAt(time.Now()).
Save(ctx) Save(ctx)
@ -59,7 +65,7 @@ func (s *Service) SetAllCompleted(value bool) error {
func (s *Service) ClearCompleted() error { func (s *Service) ClearCompleted() error {
ctx := context.Background() ctx := context.Background()
_, err := s.db.Task.Delete().Where(task.CompletedAtNotNil()).Exec(ctx) _, err := s.db.Task.Delete().Where(task.CompletedAtNotNil(), task.IPAddress(s.ipAddress)).Exec(ctx)
return err return err
} }
@ -75,9 +81,11 @@ func (s *Service) SetCompleted(id uuid.UUID, value bool) (*ent.Task, error) {
return updater. return updater.
SetUpdatedAt(time.Now()). SetUpdatedAt(time.Now()).
Where(task.IPAddress(s.ipAddress)).
Save(ctx) Save(ctx)
} }
func (s *Service) List(ps ...predicate.Task) ([]*ent.Task, error) { func (s *Service) List(ps ...predicate.Task) ([]*ent.Task, error) {
ps = append(ps, task.IPAddress(s.ipAddress))
return s.db.Task.Query().Where(ps...).All(context.Background()) return s.db.Task.Query().Where(ps...).All(context.Background())
} }

View file

@ -0,0 +1,27 @@
package util
import (
"net/http"
"strings"
)
func GetClientIp(r *http.Request) string {
// Try to get the real client IP from the 'CF-Connecting-IP' header
if ip := r.Header.Get("CF-Connecting-IP"); ip != "" {
return ip
}
// If not available, fall back to 'X-Forwarded-For'
if ip := r.Header.Get("X-Forwarded-For"); ip != "" {
return ip
}
// Otherwise, use the default remote address (this will be Cloudflare's IP)
remote := r.RemoteAddr
if strings.HasPrefix(remote, "[::1]") {
return "localhost"
}
return remote
}

View file

@ -26,7 +26,7 @@ func getActiveTab(ctx *h.RequestContext) Tab {
} }
func Card(ctx *h.RequestContext) *h.Element { func Card(ctx *h.RequestContext) *h.Element {
service := tasks.NewService(ctx.ServiceLocator()) service := tasks.NewService(ctx)
list, _ := service.List() list, _ := service.List()
return h.Div( return h.Div(
@ -52,7 +52,6 @@ func Input(list []*ent.Task) *h.Element {
h.Input( h.Input(
"text", "text",
h.Required(), h.Required(),
h.Disabled(),
h.MaxLength(150), h.MaxLength(150),
h.AutoComplete("off"), h.AutoComplete("off"),
h.AutoFocus(), h.AutoFocus(),
@ -212,7 +211,7 @@ func UpdateName(ctx *h.RequestContext) *h.Partial {
return h.NewPartial(h.Div(h.Text("task must be less than 150 characters"))) return h.NewPartial(h.Div(h.Text("task must be less than 150 characters")))
} }
service := tasks.NewService(ctx.ServiceLocator()) service := tasks.NewService(ctx)
task, err := service.Get(id) task, err := service.Get(id)
if task == nil { if task == nil {
@ -235,7 +234,7 @@ func EditNameForm(ctx *h.RequestContext) *h.Partial {
return h.NewPartial(h.Div(h.Text("invalid id"))) return h.NewPartial(h.Div(h.Text("invalid id")))
} }
service := tasks.NewService(ctx.ServiceLocator()) service := tasks.NewService(ctx)
task, err := service.Get(id) task, err := service.Get(id)
if task == nil { if task == nil {
@ -253,7 +252,7 @@ func ToggleCompleted(ctx *h.RequestContext) *h.Partial {
return h.NewPartial(h.Div(h.Text("invalid id"))) return h.NewPartial(h.Div(h.Text("invalid id")))
} }
service := tasks.NewService(ctx.ServiceLocator()) service := tasks.NewService(ctx)
task, err := service.Get(id) task, err := service.Get(id)
if task == nil { if task == nil {
@ -277,7 +276,7 @@ func ToggleCompleted(ctx *h.RequestContext) *h.Partial {
} }
func CompleteAll(ctx *h.RequestContext) *h.Partial { func CompleteAll(ctx *h.RequestContext) *h.Partial {
service := tasks.NewService(ctx.ServiceLocator()) service := tasks.NewService(ctx)
service.SetAllCompleted(ctx.QueryParam("complete") == "true") service.SetAllCompleted(ctx.QueryParam("complete") == "true")
@ -287,7 +286,7 @@ func CompleteAll(ctx *h.RequestContext) *h.Partial {
} }
func ClearCompleted(ctx *h.RequestContext) *h.Partial { func ClearCompleted(ctx *h.RequestContext) *h.Partial {
service := tasks.NewService(ctx.ServiceLocator()) service := tasks.NewService(ctx)
_ = service.ClearCompleted() _ = service.ClearCompleted()
list, _ := service.List() list, _ := service.List()
@ -306,11 +305,11 @@ func Create(ctx *h.RequestContext) *h.Partial {
) )
} }
service := tasks.NewService(ctx.ServiceLocator()) service := tasks.NewService(ctx)
list, _ := service.List() list, _ := service.List()
if list != nil && len(list) >= 200 { if list != nil && len(list) >= 100 {
return h.NewPartial( return h.NewPartial(
h.Div( h.Div(
h.HxOnLoad(js.Alert("There are too many tasks, please complete and clear some.")), h.HxOnLoad(js.Alert("There are too many tasks, please complete and clear some.")),
@ -334,7 +333,7 @@ func Create(ctx *h.RequestContext) *h.Partial {
} }
func ChangeTab(ctx *h.RequestContext) *h.Partial { func ChangeTab(ctx *h.RequestContext) *h.Partial {
service := tasks.NewService(ctx.ServiceLocator()) service := tasks.NewService(ctx)
list, _ := service.List() list, _ := service.List()
tab := ctx.QueryParam("tab") tab := ctx.QueryParam("tab")