mirror of
https://github.com/hrfee/jfa-go.git
synced 2026-01-18 16:47:42 +01:00
search: fix server-side date behaviour
OffsetMinutesFromUTC was being passed incorrectly by the web app (getTimezoneOffset if UTC - Timezone, we wanted Timezone - UTC), now fixed. This value is now used if given in comparisons. Times are truncated to minute-deep precision, and Any date comparison ignores empty date fields (i.e. a unix timestamp being 0 or a time.Time.IsZero() == true).
This commit is contained in:
@@ -249,7 +249,7 @@ func matchTimeAsQuery(query *badgerhold.Query, q QueryDTO) *badgerhold.Query {
|
|||||||
}
|
}
|
||||||
criterion := andField(query, "Time")
|
criterion := andField(query, "Time")
|
||||||
query = criterion.MatchFunc(func(ra *badgerhold.RecordAccess) (bool, error) {
|
query = criterion.MatchFunc(func(ra *badgerhold.RecordAccess) (bool, error) {
|
||||||
return q.Value.(DateAttempt).Compare(ra.Field().(time.Time)) == int(operator), nil
|
return q.Value.(DateAttempt).CompareWithOperator(ra.Field().(time.Time), operator), nil
|
||||||
})
|
})
|
||||||
return query
|
return query
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,7 +30,12 @@ export const parseDateString = (value: string): ParsedDate => {
|
|||||||
// note Date.fromString is also provided by dateParser.
|
// note Date.fromString is also provided by dateParser.
|
||||||
date: (Date as any).fromString(value) as Date
|
date: (Date as any).fromString(value) as Date
|
||||||
};
|
};
|
||||||
out.attempt.offsetMinutesFromUTC = out.date.getTimezoneOffset();
|
if (("invalid" in (out.date as any))) {
|
||||||
|
out.invalid = true;
|
||||||
|
} else {
|
||||||
|
// getTimezoneOffset returns UTC - Timezone, so invert it to get distance from UTC -to- timezone.
|
||||||
|
out.attempt.offsetMinutesFromUTC = -1 * out.date.getTimezoneOffset();
|
||||||
|
}
|
||||||
// Month in Date objects is 0-based, so make our parsed date that way too
|
// Month in Date objects is 0-based, so make our parsed date that way too
|
||||||
if ("month" in out.attempt) out.attempt.month -= 1;
|
if ("month" in out.attempt) out.attempt.month -= 1;
|
||||||
return out;
|
return out;
|
||||||
|
|||||||
@@ -219,7 +219,7 @@ export class DateQuery extends Query {
|
|||||||
}
|
}
|
||||||
let out = parseDateString(valueString);
|
let out = parseDateString(valueString);
|
||||||
let isValid = true;
|
let isValid = true;
|
||||||
if ("invalid" in (out.date as any)) { isValid = false; };
|
if (out.invalid) isValid = false;
|
||||||
|
|
||||||
return [out, op, isValid];
|
return [out, op, isValid];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -174,6 +174,7 @@ interface ParsedDate {
|
|||||||
attempt: DateAttempt;
|
attempt: DateAttempt;
|
||||||
date: Date;
|
date: Date;
|
||||||
text: string;
|
text: string;
|
||||||
|
invalid?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
declare var config: Object;
|
declare var config: Object;
|
||||||
|
|||||||
39
usercache.go
39
usercache.go
@@ -243,10 +243,34 @@ type DateAttempt struct {
|
|||||||
OffsetMinutesFromUTC *int `json:"offsetMinutesFromUTC,omitempty"`
|
OffsetMinutesFromUTC *int `json:"offsetMinutesFromUTC,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CompareWithOperator roughly compares a time.Time to a DateAttempt according to the given operator.
|
||||||
|
// **Considers zero-dates as invalid!** (i.e. any comparison to a subject.IsZero() will be false).
|
||||||
|
func (d DateAttempt) CompareWithOperator(subject time.Time, operator CompareResult) bool {
|
||||||
|
if subject.IsZero() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return d.Compare(subject) == int(operator)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CompareUnixWithOperator roughly compares a unix timestamp to a DateAttempt according to the given operator.
|
||||||
|
// **Considers zero-dates as invalid!** (i.e. any comparison to a time.Unix(subject, 0).IsZero() or (subject == 0) will be false).
|
||||||
|
func (d DateAttempt) CompareUnixWithOperator(subject int64, operator CompareResult) bool {
|
||||||
|
if subject == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
subjectTime := time.Unix(subject, 0)
|
||||||
|
if subjectTime.IsZero() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return d.Compare(subjectTime) == int(operator)
|
||||||
|
}
|
||||||
|
|
||||||
// Compare roughly compares a time.Time to a DateAttempt.
|
// Compare roughly compares a time.Time to a DateAttempt.
|
||||||
// We want to compare only the fields given in DateAttempt,
|
// We want to compare only the fields given in DateAttempt,
|
||||||
// so we copy subjectDate and apply on those fields from this._value.
|
// so we copy subjectDate and apply on those fields from this._value.
|
||||||
func (d DateAttempt) Compare(subject time.Time) int {
|
func (d DateAttempt) Compare(subject time.Time) int {
|
||||||
|
// Remove anything more precise than a second
|
||||||
|
subject = subject.Truncate(time.Minute)
|
||||||
yy, mo, dd := subject.Date()
|
yy, mo, dd := subject.Date()
|
||||||
hh, mm, _ := subject.Clock()
|
hh, mm, _ := subject.Clock()
|
||||||
if d.Year != nil {
|
if d.Year != nil {
|
||||||
@@ -265,8 +289,17 @@ func (d DateAttempt) Compare(subject time.Time) int {
|
|||||||
if d.Minute != nil {
|
if d.Minute != nil {
|
||||||
mm = *d.Minute
|
mm = *d.Minute
|
||||||
}
|
}
|
||||||
|
|
||||||
|
location := time.UTC
|
||||||
|
if d.OffsetMinutesFromUTC != nil {
|
||||||
|
location = time.FixedZone("", 60*(*d.OffsetMinutesFromUTC))
|
||||||
|
}
|
||||||
|
|
||||||
// FIXME: Transmit timezone in request maybe?
|
// FIXME: Transmit timezone in request maybe?
|
||||||
return subject.Compare(time.Date(yy, mo, dd, hh, mm, 0, 0, time.UTC))
|
daAsTime := time.Date(yy, mo, dd, hh, mm, 0, 0, location)
|
||||||
|
comp := subject.Compare(daAsTime)
|
||||||
|
|
||||||
|
return comp
|
||||||
}
|
}
|
||||||
|
|
||||||
// CompareUnix roughly compares a unix timestamp to a DateAttempt.
|
// CompareUnix roughly compares a unix timestamp to a DateAttempt.
|
||||||
@@ -310,7 +343,7 @@ func (q QueryDTO) AsFilter() Filter {
|
|||||||
switch q.Class {
|
switch q.Class {
|
||||||
case DateQuery:
|
case DateQuery:
|
||||||
return func(a *respUser) bool {
|
return func(a *respUser) bool {
|
||||||
return q.Value.(DateAttempt).CompareUnix(a.LastActive) == int(operator)
|
return q.Value.(DateAttempt).CompareUnixWithOperator(a.LastActive, operator)
|
||||||
}
|
}
|
||||||
case BoolQuery:
|
case BoolQuery:
|
||||||
return func(a *respUser) bool {
|
return func(a *respUser) bool {
|
||||||
@@ -329,7 +362,7 @@ func (q QueryDTO) AsFilter() Filter {
|
|||||||
switch q.Class {
|
switch q.Class {
|
||||||
case DateQuery:
|
case DateQuery:
|
||||||
return func(a *respUser) bool {
|
return func(a *respUser) bool {
|
||||||
return q.Value.(DateAttempt).CompareUnix(a.Expiry) == int(operator)
|
return q.Value.(DateAttempt).CompareUnixWithOperator(a.Expiry, operator)
|
||||||
}
|
}
|
||||||
case BoolQuery:
|
case BoolQuery:
|
||||||
return func(a *respUser) bool {
|
return func(a *respUser) bool {
|
||||||
|
|||||||
Reference in New Issue
Block a user