mirror of
https://github.com/hay-kot/homebox.git
synced 2025-07-05 01:58:36 +00:00
fix: date and datetime regression (#282)
* use custom types.Date implementation * fix user registration bug * remove sanity check * fix datetime bug
This commit is contained in:
parent
44f13f751a
commit
607b06d2f2
10 changed files with 162 additions and 52 deletions
|
@ -13,6 +13,7 @@ import (
|
|||
"github.com/hay-kot/homebox/backend/internal/data/ent/label"
|
||||
"github.com/hay-kot/homebox/backend/internal/data/ent/location"
|
||||
"github.com/hay-kot/homebox/backend/internal/data/ent/predicate"
|
||||
"github.com/hay-kot/homebox/backend/internal/data/types"
|
||||
)
|
||||
|
||||
type ItemsRepository struct {
|
||||
|
@ -78,20 +79,20 @@ type (
|
|||
Manufacturer string `json:"manufacturer"`
|
||||
|
||||
// Warranty
|
||||
LifetimeWarranty bool `json:"lifetimeWarranty"`
|
||||
WarrantyExpires time.Time `json:"warrantyExpires"`
|
||||
WarrantyDetails string `json:"warrantyDetails"`
|
||||
LifetimeWarranty bool `json:"lifetimeWarranty"`
|
||||
WarrantyExpires types.Date `json:"warrantyExpires"`
|
||||
WarrantyDetails string `json:"warrantyDetails"`
|
||||
|
||||
// Purchase
|
||||
PurchaseTime time.Time `json:"purchaseTime"`
|
||||
PurchaseFrom string `json:"purchaseFrom"`
|
||||
PurchasePrice float64 `json:"purchasePrice,string"`
|
||||
PurchaseTime types.Date `json:"purchaseTime"`
|
||||
PurchaseFrom string `json:"purchaseFrom"`
|
||||
PurchasePrice float64 `json:"purchasePrice,string"`
|
||||
|
||||
// Sold
|
||||
SoldTime time.Time `json:"soldTime"`
|
||||
SoldTo string `json:"soldTo"`
|
||||
SoldPrice float64 `json:"soldPrice,string"`
|
||||
SoldNotes string `json:"soldNotes"`
|
||||
SoldTime types.Date `json:"soldTime"`
|
||||
SoldTo string `json:"soldTo"`
|
||||
SoldPrice float64 `json:"soldPrice,string"`
|
||||
SoldNotes string `json:"soldNotes"`
|
||||
|
||||
// Extras
|
||||
Notes string `json:"notes"`
|
||||
|
@ -126,19 +127,19 @@ type (
|
|||
Manufacturer string `json:"manufacturer"`
|
||||
|
||||
// Warranty
|
||||
LifetimeWarranty bool `json:"lifetimeWarranty"`
|
||||
WarrantyExpires time.Time `json:"warrantyExpires"`
|
||||
WarrantyDetails string `json:"warrantyDetails"`
|
||||
LifetimeWarranty bool `json:"lifetimeWarranty"`
|
||||
WarrantyExpires types.Date `json:"warrantyExpires"`
|
||||
WarrantyDetails string `json:"warrantyDetails"`
|
||||
|
||||
// Purchase
|
||||
PurchaseTime time.Time `json:"purchaseTime"`
|
||||
PurchaseFrom string `json:"purchaseFrom"`
|
||||
PurchaseTime types.Date `json:"purchaseTime"`
|
||||
PurchaseFrom string `json:"purchaseFrom"`
|
||||
|
||||
// Sold
|
||||
SoldTime time.Time `json:"soldTime"`
|
||||
SoldTo string `json:"soldTo"`
|
||||
SoldPrice float64 `json:"soldPrice,string"`
|
||||
SoldNotes string `json:"soldNotes"`
|
||||
SoldTime types.Date `json:"soldTime"`
|
||||
SoldTo string `json:"soldTo"`
|
||||
SoldPrice float64 `json:"soldPrice,string"`
|
||||
SoldNotes string `json:"soldNotes"`
|
||||
|
||||
// Extras
|
||||
Notes string `json:"notes"`
|
||||
|
@ -232,7 +233,7 @@ func mapItemOut(item *ent.Item) ItemOut {
|
|||
AssetID: AssetID(item.AssetID),
|
||||
ItemSummary: mapItemSummary(item),
|
||||
LifetimeWarranty: item.LifetimeWarranty,
|
||||
WarrantyExpires: item.WarrantyExpires,
|
||||
WarrantyExpires: types.DateFromTime(item.WarrantyExpires),
|
||||
WarrantyDetails: item.WarrantyDetails,
|
||||
|
||||
// Identification
|
||||
|
@ -241,11 +242,11 @@ func mapItemOut(item *ent.Item) ItemOut {
|
|||
Manufacturer: item.Manufacturer,
|
||||
|
||||
// Purchase
|
||||
PurchaseTime: item.PurchaseTime,
|
||||
PurchaseTime: types.DateFromTime(item.PurchaseTime),
|
||||
PurchaseFrom: item.PurchaseFrom,
|
||||
|
||||
// Sold
|
||||
SoldTime: item.SoldTime,
|
||||
SoldTime: types.DateFromTime(item.SoldTime),
|
||||
SoldTo: item.SoldTo,
|
||||
SoldPrice: item.SoldPrice,
|
||||
SoldNotes: item.SoldNotes,
|
||||
|
@ -526,17 +527,17 @@ func (e *ItemsRepository) UpdateByGroup(ctx context.Context, GID uuid.UUID, data
|
|||
SetModelNumber(data.ModelNumber).
|
||||
SetManufacturer(data.Manufacturer).
|
||||
SetArchived(data.Archived).
|
||||
SetPurchaseTime(data.PurchaseTime).
|
||||
SetPurchaseTime(data.PurchaseTime.Time()).
|
||||
SetPurchaseFrom(data.PurchaseFrom).
|
||||
SetPurchasePrice(data.PurchasePrice).
|
||||
SetSoldTime(data.SoldTime).
|
||||
SetSoldTime(data.SoldTime.Time()).
|
||||
SetSoldTo(data.SoldTo).
|
||||
SetSoldPrice(data.SoldPrice).
|
||||
SetSoldNotes(data.SoldNotes).
|
||||
SetNotes(data.Notes).
|
||||
SetLifetimeWarranty(data.LifetimeWarranty).
|
||||
SetInsured(data.Insured).
|
||||
SetWarrantyExpires(data.WarrantyExpires).
|
||||
SetWarrantyExpires(data.WarrantyExpires.Time()).
|
||||
SetWarrantyDetails(data.WarrantyDetails).
|
||||
SetQuantity(data.Quantity).
|
||||
SetAssetID(int(data.AssetID))
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/hay-kot/homebox/backend/internal/data/types"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
@ -237,15 +238,15 @@ func TestItemsRepository_Update(t *testing.T) {
|
|||
LabelIDs: nil,
|
||||
ModelNumber: fk.Str(10),
|
||||
Manufacturer: fk.Str(10),
|
||||
PurchaseTime: time.Now(),
|
||||
PurchaseTime: types.DateFromTime(time.Now()),
|
||||
PurchaseFrom: fk.Str(10),
|
||||
PurchasePrice: 300.99,
|
||||
SoldTime: time.Now(),
|
||||
SoldTime: types.DateFromTime(time.Now()),
|
||||
SoldTo: fk.Str(10),
|
||||
SoldPrice: 300.99,
|
||||
SoldNotes: fk.Str(10),
|
||||
Notes: fk.Str(10),
|
||||
WarrantyExpires: time.Now(),
|
||||
WarrantyExpires: types.DateFromTime(time.Now()),
|
||||
WarrantyDetails: fk.Str(10),
|
||||
LifetimeWarranty: true,
|
||||
}
|
||||
|
|
88
backend/internal/data/types/date.go
Normal file
88
backend/internal/data/types/date.go
Normal file
|
@ -0,0 +1,88 @@
|
|||
package types
|
||||
|
||||
import "time"
|
||||
|
||||
// Date is a custom type that implements the MarshalJSON interface
|
||||
// that applies date only formatting to the time.Time fields in order
|
||||
// to avoid common time and timezone pitfalls when working with Times.
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// "2019-01-01" -> time.Time{2019-01-01 00:00:00 +0000 UTC}
|
||||
// "2019-01-01T21:10:30Z" -> time.Time{2019-01-01 00:00:00 +0000 UTC}
|
||||
// "2019-01-01T21:10:30+01:00" -> time.Time{2019-01-01 00:00:00 +0000 UTC}
|
||||
type Date time.Time
|
||||
|
||||
func (d Date) Time() time.Time {
|
||||
return time.Time(d)
|
||||
}
|
||||
|
||||
// DateFromTime returns a Date type from a time.Time type by stripping
|
||||
// the time and timezone information.
|
||||
func DateFromTime(t time.Time) Date {
|
||||
dateOnlyTime := time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, time.UTC)
|
||||
return Date(dateOnlyTime)
|
||||
}
|
||||
|
||||
// DateFromString returns a Date type from a string by parsing the
|
||||
// string into a time.Time type and then stripping the time and
|
||||
// timezone information.
|
||||
//
|
||||
// Errors are ignored and an empty Date is returned.
|
||||
func DateFromString(s string) Date {
|
||||
if s == "" {
|
||||
return Date{}
|
||||
}
|
||||
|
||||
t, err := time.Parse("2006-01-02", s)
|
||||
if err != nil {
|
||||
// TODO: Remove - used by legacy importer
|
||||
t, err = time.Parse("01/02/2006", s)
|
||||
|
||||
if err != nil {
|
||||
return Date{}
|
||||
}
|
||||
}
|
||||
|
||||
return DateFromTime(t)
|
||||
}
|
||||
|
||||
func (d Date) String() string {
|
||||
if time.Time(d).IsZero() {
|
||||
return ""
|
||||
}
|
||||
|
||||
return time.Time(d).Format("2006-01-02")
|
||||
}
|
||||
|
||||
func (d Date) MarshalJSON() ([]byte, error) {
|
||||
if time.Time(d).IsZero() {
|
||||
return []byte(`""`), nil
|
||||
}
|
||||
|
||||
return []byte(`"` + d.String() + `"`), nil
|
||||
}
|
||||
|
||||
func (d *Date) UnmarshalJSON(data []byte) error {
|
||||
str := string(data)
|
||||
if str == `""` {
|
||||
*d = Date{}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Try YYYY-MM-DD format
|
||||
var t time.Time
|
||||
t, err := time.Parse("2006-01-02", str)
|
||||
if err != nil {
|
||||
// Try default interface
|
||||
err = t.UnmarshalJSON(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// strip the time and timezone information
|
||||
*d = DateFromTime(t)
|
||||
|
||||
return nil
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue