update tasks so they are by ip due to spammers
This commit is contained in:
parent
fce0dfe746
commit
13538191c9
13 changed files with 324 additions and 25 deletions
|
|
@ -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{
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ 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)
|
||||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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(""),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -29,6 +29,8 @@ type Task struct {
|
|||
CompletedAt *time.Time `json:"completed_at,omitempty"`
|
||||
// Tags holds the value of the "tags" field.
|
||||
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()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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...))
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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=
|
||||
|
|
|
|||
|
|
@ -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
|
||||
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())
|
||||
}
|
||||
|
|
|
|||
27
examples/todo-list/internal/util/ip.go
Normal file
27
examples/todo-list/internal/util/ip.go
Normal 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
|
||||
}
|
||||
|
|
@ -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")
|
||||
|
|
|
|||
Loading…
Reference in a new issue