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: "completed_at", Type: field.TypeTime, 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 = &schema.Table{

View file

@ -31,8 +31,8 @@ const (
// TaskMutation represents an operation that mutates the Task nodes in the graph.
type TaskMutation struct {
config
op Op
typ string
op Op
typ string
id *uuid.UUID
name *string
created_at *time.Time
@ -40,10 +40,11 @@ type TaskMutation struct {
completed_at *time.Time
tags *[]string
appendtags []string
ip_address *string
clearedFields map[string]struct{}
done bool
oldValue func(context.Context) (*Task, error)
predicates []predicate.Task
done bool
oldValue func(context.Context) (*Task, error)
predicates []predicate.Task
}
var _ ent.Mutation = (*TaskMutation)(nil)
@ -372,6 +373,55 @@ func (m *TaskMutation) ResetTags() {
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.
func (m *TaskMutation) Where(ps ...predicate.Task) {
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
// AddedFields().
func (m *TaskMutation) Fields() []string {
fields := make([]string, 0, 5)
fields := make([]string, 0, 6)
if m.name != nil {
fields = append(fields, task.FieldName)
}
@ -422,6 +472,9 @@ func (m *TaskMutation) Fields() []string {
if m.tags != nil {
fields = append(fields, task.FieldTags)
}
if m.ip_address != nil {
fields = append(fields, task.FieldIPAddress)
}
return fields
}
@ -440,6 +493,8 @@ func (m *TaskMutation) Field(name string) (ent.Value, bool) {
return m.CompletedAt()
case task.FieldTags:
return m.Tags()
case task.FieldIPAddress:
return m.IPAddress()
}
return nil, false
}
@ -459,6 +514,8 @@ func (m *TaskMutation) OldField(ctx context.Context, name string) (ent.Value, er
return m.OldCompletedAt(ctx)
case task.FieldTags:
return m.OldTags(ctx)
case task.FieldIPAddress:
return m.OldIPAddress(ctx)
}
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)
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)
}
@ -539,6 +603,9 @@ func (m *TaskMutation) ClearedFields() []string {
if m.FieldCleared(task.FieldTags) {
fields = append(fields, task.FieldTags)
}
if m.FieldCleared(task.FieldIPAddress) {
fields = append(fields, task.FieldIPAddress)
}
return fields
}
@ -559,6 +626,9 @@ func (m *TaskMutation) ClearField(name string) error {
case task.FieldTags:
m.ClearTags()
return nil
case task.FieldIPAddress:
m.ClearIPAddress()
return nil
}
return fmt.Errorf("unknown Task nullable field %s", name)
}
@ -582,6 +652,9 @@ func (m *TaskMutation) ResetField(name string) error {
case task.FieldTags:
m.ResetTags()
return nil
case task.FieldIPAddress:
m.ResetIPAddress()
return nil
}
return fmt.Errorf("unknown Task field %s", name)
}

View file

@ -28,6 +28,10 @@ func init() {
taskDescUpdatedAt := taskFields[3].Descriptor()
// task.DefaultUpdatedAt holds the default value on creation for the updated_at field.
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 := taskFields[0].Descriptor()
// 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{
field.UUID("id", uuid.UUID{}).
Default(uuid.New),
field.String("name").
Default("unknown"),
field.String("name").Default("unknown"),
field.Time("created_at").Default(time.Now).Annotations(
entsql.Default("CURRENT_TIMESTAMP"),
),
@ -27,6 +26,7 @@ func (Task) Fields() []ent.Field {
),
field.Time("completed_at").Optional().Nillable(),
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 *time.Time `json:"completed_at,omitempty"`
// 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
}
@ -39,7 +41,7 @@ func (*Task) scanValues(columns []string) ([]any, error) {
switch columns[i] {
case task.FieldTags:
values[i] = new([]byte)
case task.FieldName:
case task.FieldName, task.FieldIPAddress:
values[i] = new(sql.NullString)
case task.FieldCreatedAt, task.FieldUpdatedAt, task.FieldCompletedAt:
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)
}
}
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:
t.selectValues.Set(columns[i], values[i])
}
@ -151,6 +159,9 @@ func (t *Task) String() string {
builder.WriteString(", ")
builder.WriteString("tags=")
builder.WriteString(fmt.Sprintf("%v", t.Tags))
builder.WriteString(", ")
builder.WriteString("ip_address=")
builder.WriteString(t.IPAddress)
builder.WriteByte(')')
return builder.String()
}

View file

@ -24,6 +24,8 @@ const (
FieldCompletedAt = "completed_at"
// FieldTags holds the string denoting the tags field in the database.
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 = "tasks"
)
@ -36,6 +38,7 @@ var Columns = []string{
FieldUpdatedAt,
FieldCompletedAt,
FieldTags,
FieldIPAddress,
}
// ValidColumn reports if the column name is valid (part of the table columns).
@ -55,6 +58,8 @@ var (
DefaultCreatedAt func() time.Time
// DefaultUpdatedAt holds the default value on creation for the "updated_at" field.
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 func() uuid.UUID
)
@ -86,3 +91,8 @@ func ByUpdatedAt(opts ...sql.OrderTermOption) OrderOption {
func ByCompletedAt(opts ...sql.OrderTermOption) OrderOption {
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))
}
// 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.
func NameEQ(v string) predicate.Task {
return predicate.Task(sql.FieldEQ(FieldName, v))
@ -280,6 +285,81 @@ func TagsNotNil() predicate.Task {
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.
func And(predicates ...predicate.Task) predicate.Task {
return predicate.Task(sql.AndPredicates(predicates...))

View file

@ -83,6 +83,20 @@ func (tc *TaskCreate) SetTags(s []string) *TaskCreate {
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.
func (tc *TaskCreate) SetID(u uuid.UUID) *TaskCreate {
tc.mutation.SetID(u)
@ -144,6 +158,10 @@ func (tc *TaskCreate) defaults() {
v := task.DefaultUpdatedAt()
tc.mutation.SetUpdatedAt(v)
}
if _, ok := tc.mutation.IPAddress(); !ok {
v := task.DefaultIPAddress
tc.mutation.SetIPAddress(v)
}
if _, ok := tc.mutation.ID(); !ok {
v := task.DefaultID()
tc.mutation.SetID(v)
@ -216,6 +234,10 @@ func (tc *TaskCreate) createSpec() (*Task, *sqlgraph.CreateSpec) {
_spec.SetField(task.FieldTags, field.TypeJSON, value)
_node.Tags = value
}
if value, ok := tc.mutation.IPAddress(); ok {
_spec.SetField(task.FieldIPAddress, field.TypeString, value)
_node.IPAddress = value
}
return _node, _spec
}

View file

@ -109,6 +109,26 @@ func (tu *TaskUpdate) ClearTags() *TaskUpdate {
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.
func (tu *TaskUpdate) Mutation() *TaskMutation {
return tu.mutation
@ -176,6 +196,12 @@ func (tu *TaskUpdate) sqlSave(ctx context.Context) (n int, err error) {
if tu.mutation.TagsCleared() {
_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 _, ok := err.(*sqlgraph.NotFoundError); ok {
err = &NotFoundError{task.Label}
@ -276,6 +302,26 @@ func (tuo *TaskUpdateOne) ClearTags() *TaskUpdateOne {
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.
func (tuo *TaskUpdateOne) Mutation() *TaskMutation {
return tuo.mutation
@ -373,6 +419,12 @@ func (tuo *TaskUpdateOne) sqlSave(ctx context.Context) (_node *Task, err error)
if tuo.mutation.TagsCleared() {
_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}
_spec.Assign = _node.assignValues
_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/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/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/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/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/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
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/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/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
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.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo=
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/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
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/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
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=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=

View file

@ -3,15 +3,18 @@ package tasks
import (
"context"
"github.com/google/uuid"
"github.com/maddalax/htmgo/framework/h"
"github.com/maddalax/htmgo/framework/service"
"time"
"todolist/ent"
"todolist/ent/predicate"
"todolist/ent/task"
"todolist/internal/util"
)
type Service struct {
db *ent.Client
db *ent.Client
ipAddress string
}
type CreateRequest struct {
@ -19,9 +22,10 @@ type CreateRequest struct {
Tags []string
}
func NewService(locator *service.Locator) Service {
func NewService(ctx *h.RequestContext) 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().
SetName(request.Name).
SetTags(request.Tags).
SetIPAddress(s.ipAddress).
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) {
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 {
@ -51,6 +56,7 @@ func (s *Service) SetAllCompleted(value bool) error {
}
_, err := updater.
Where(task.IPAddress(s.ipAddress)).
SetUpdatedAt(time.Now()).
Save(ctx)
@ -59,7 +65,7 @@ func (s *Service) SetAllCompleted(value bool) error {
func (s *Service) ClearCompleted() error {
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
}
@ -75,9 +81,11 @@ func (s *Service) SetCompleted(id uuid.UUID, value bool) (*ent.Task, error) {
return updater.
SetUpdatedAt(time.Now()).
Where(task.IPAddress(s.ipAddress)).
Save(ctx)
}
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())
}

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 {
service := tasks.NewService(ctx.ServiceLocator())
service := tasks.NewService(ctx)
list, _ := service.List()
return h.Div(
@ -52,7 +52,6 @@ func Input(list []*ent.Task) *h.Element {
h.Input(
"text",
h.Required(),
h.Disabled(),
h.MaxLength(150),
h.AutoComplete("off"),
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")))
}
service := tasks.NewService(ctx.ServiceLocator())
service := tasks.NewService(ctx)
task, err := service.Get(id)
if task == nil {
@ -235,7 +234,7 @@ func EditNameForm(ctx *h.RequestContext) *h.Partial {
return h.NewPartial(h.Div(h.Text("invalid id")))
}
service := tasks.NewService(ctx.ServiceLocator())
service := tasks.NewService(ctx)
task, err := service.Get(id)
if task == nil {
@ -253,7 +252,7 @@ func ToggleCompleted(ctx *h.RequestContext) *h.Partial {
return h.NewPartial(h.Div(h.Text("invalid id")))
}
service := tasks.NewService(ctx.ServiceLocator())
service := tasks.NewService(ctx)
task, err := service.Get(id)
if task == nil {
@ -277,7 +276,7 @@ func ToggleCompleted(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")
@ -287,7 +286,7 @@ func CompleteAll(ctx *h.RequestContext) *h.Partial {
}
func ClearCompleted(ctx *h.RequestContext) *h.Partial {
service := tasks.NewService(ctx.ServiceLocator())
service := tasks.NewService(ctx)
_ = service.ClearCompleted()
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()
if list != nil && len(list) >= 200 {
if list != nil && len(list) >= 100 {
return h.NewPartial(
h.Div(
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 {
service := tasks.NewService(ctx.ServiceLocator())
service := tasks.NewService(ctx)
list, _ := service.List()
tab := ctx.QueryParam("tab")