New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
644/datepicker #693
644/datepicker #693
Conversation
Codecov Report
@@ Coverage Diff @@
## master #693 +/- ##
==========================================
+ Coverage 95.33% 95.33% +<.01%
==========================================
Files 121 121
Lines 14755 14765 +10
==========================================
+ Hits 14066 14076 +10
Misses 689 689
Continue to review full report at Codecov.
|
privacyidea/lib/tokenclass.py
Outdated
return datetime.datetime.now() > datetime.datetime.strptime(sdate, | ||
DATE_FORMAT) | ||
#date_change = datetime.datetime.strptime(sdate, DATE_FORMAT) | ||
date_change = parse_date_string(sdate) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we need to do something similar as in 75d6487 here:
Suppose a 2.18 token has a next_pin_change
token info value in the old DD/MM/YY hh:mm
format. Then, parse_date_string
will return a naive datetime object, which is then compared against the aware datetime.now(tzlocal())
object, which breaks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, will change this to be on the safe side.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wanted to start a review, so that I know, that I need to change here:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The user does never set a date in next_pin_change
manually. This is only achieved by using the tokenclass method. set_next_pin_change
.
You are right to use parse_legacy_time here, since it seems it could occur that old timestamps without TZ but with dayfirst are found in the database.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please take look at 0cf82fb
privacyidea/lib/tokenclass.py
Outdated
# The last auth is to far in the past | ||
if last_success_auth + tdelta < datetime.datetime.now(): | ||
if last_success_auth + tdelta < datetime.datetime.utcnow(): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right now, last auth is stored without timezone information in the database.
I'm wondering if it would be better to store it with timezone information in order to have a uniform format for datetime values in token info values? If we want to do that, we need to change the right side to an aware datetime object.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In lib/policydecorator.py
method auth_lastauth
the last authentication is stored as utc. So if we compare utc, we are on the same side, there would be no necissity to store the timezone. It might be faster, but harder to read for admins. I think I am ok with that. Waht do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The last_auth
time stamp / token info is generated internally and only used internally. No user input. This is why it was handled different as utc. I am happy to discuss this.
privacyidea/lib/utils.py
Outdated
log.debug("Dateformat {1!s} did not match date {0!s}".format( | ||
date_string, date_format)) | ||
try: | ||
d = parse_date_string(date_string) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we should use parse_legacy_time
here?
- It uses
dayfirst=True
-- currently, I thinkparse_date
would incorrectly parse dates in the"%d.%m.%Y %H:%M"
format (the MM/DD and DD/MM switch). - This way,
parse_date
would always return aware datetime objects -- better to have a uniform API?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will add more tests for parse_date and adapt it as needed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please see 83769a6
I think this is not the most sensible and most definite way?
d = parse_date("23.12.16") | ||
self.assertEqual(d, None) | ||
self.assertEqual(d, datetime(2016, 12, 23, 0, 0)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should probably add a test for the MM/DD confusion here. Right now, parse_date
behaves incorrectly (see above):
>>> privacyidea.lib.utils.parse_date('03.04.16') datetime.datetime(2016, 3, 4, 0, 0)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
touché
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in 83769a6
@@ -45,6 +45,8 @@ | |||
import json | |||
import logging | |||
import datetime | |||
from dateutil.parser import parse as parse_date_string |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
dateutil.parser.parse
is pretty cool because it supports a lot of formats, but this could also cause problems in the future: If, e.g., a datetime string in the DD/MM/YYYY
format is stored in the database for whatever reason, we once again run into the MM/DD/YYYY
confusion, but we wouldn't notice, because parse
just parses it! Because of that, I'm wondering if we should maybe build a wrapper that validates that the date string is in an expected format first and gives a warning if it isn't.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We have this somehow with parse_legacy_time
. But the should^TM be no MM/DD/YY
in the database. And starting with 2.19 there will be no such date ever be written to the database again.
This is why till now I was fine with living with that and did try not to complicate things. What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I committed changes where they seemed obvious. Please take a look at the changes.
I think there are two comments, that need some discussion.
privacyidea/lib/tokenclass.py
Outdated
# The last auth is to far in the past | ||
if last_success_auth + tdelta < datetime.datetime.now(): | ||
if last_success_auth + tdelta < datetime.datetime.utcnow(): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In lib/policydecorator.py
method auth_lastauth
the last authentication is stored as utc. So if we compare utc, we are on the same side, there would be no necissity to store the timezone. It might be faster, but harder to read for admins. I think I am ok with that. Waht do you think?
privacyidea/lib/tokenclass.py
Outdated
return datetime.datetime.now() > datetime.datetime.strptime(sdate, | ||
DATE_FORMAT) | ||
#date_change = datetime.datetime.strptime(sdate, DATE_FORMAT) | ||
date_change = parse_date_string(sdate) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wanted to start a review, so that I know, that I need to change here:
privacyidea/lib/tokenclass.py
Outdated
# The last auth is to far in the past | ||
if last_success_auth + tdelta < datetime.datetime.now(): | ||
if last_success_auth + tdelta < datetime.datetime.utcnow(): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The last_auth
time stamp / token info is generated internally and only used internally. No user input. This is why it was handled different as utc. I am happy to discuss this.
@@ -45,6 +45,8 @@ | |||
import json | |||
import logging | |||
import datetime | |||
from dateutil.parser import parse as parse_date_string |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We have this somehow with parse_legacy_time
. But the should^TM be no MM/DD/YY
in the database. And starting with 2.19 there will be no such date ever be written to the database again.
This is why till now I was fine with living with that and did try not to complicate things. What do you think?
d = parse_date("23.12.16") | ||
self.assertEqual(d, None) | ||
self.assertEqual(d, datetime(2016, 12, 23, 0, 0)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
touché
privacyidea/lib/utils.py
Outdated
log.debug("Dateformat {1!s} did not match date {0!s}".format( | ||
date_string, date_format)) | ||
try: | ||
d = parse_date_string(date_string) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will add more tests for parse_date and adapt it as needed.
d = parse_date("23.12.16") | ||
self.assertEqual(d, None) | ||
self.assertEqual(d, datetime(2016, 12, 23, 0, 0)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in 83769a6
privacyidea/lib/utils.py
Outdated
log.debug("Dateformat {1!s} did not match date {0!s}".format( | ||
date_string, date_format)) | ||
try: | ||
d = parse_date_string(date_string) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please see 83769a6
I think this is not the most sensible and most definite way?
privacyidea/lib/tokenclass.py
Outdated
return datetime.datetime.now() > datetime.datetime.strptime(sdate, | ||
DATE_FORMAT) | ||
#date_change = datetime.datetime.strptime(sdate, DATE_FORMAT) | ||
date_change = parse_date_string(sdate) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The user does never set a date in next_pin_change
manually. This is only achieved by using the tokenclass method. set_next_pin_change
.
You are right to use parse_legacy_time here, since it seems it could occur that old timestamps without TZ but with dayfirst are found in the database.
privacyidea/lib/tokenclass.py
Outdated
return datetime.datetime.now() > datetime.datetime.strptime(sdate, | ||
DATE_FORMAT) | ||
#date_change = datetime.datetime.strptime(sdate, DATE_FORMAT) | ||
date_change = parse_date_string(sdate) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please take look at 0cf82fb
m = (m>9 ? '' : '0') + m; | ||
o = date_obj.toTimeString().split(" ")[1]; | ||
// 10:20:11 GMT+0200 (CEST) | ||
o = o.substring(3); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, will this work on all browsers? We should find out if toTimeString
is guaranteed to give the offset relative to GMT (which corresponds to UTC).
Maybe using getTimezoneOffset
would be safer.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As you can see i pushed this in a86a0ad.
I rebased my local 644/datepicker branch on master, but was not abel to push it.
Obviously there is no other way then to merge it manually into master. Please drop me a note, when merging is OK.
The dateformat was changed to
2017-04-28T13:14+0200
.98.01% <ø> (ø)
96.18% <100%> (+0.08%)
99.42% <100%> (-0.01%)
93.87% <100%> (+0.12%)
Continue to review full report at Codecov.
Suppose a 2.18 token has a
next_pin_change
token info value in the oldDD/MM/YY hh:mm
format. Then,parse_date_string
will return a naive datetime object, which is then compared against the awaredatetime.now(tzlocal())
object, which breaks.toTimeString
is guaranteed to give the offset relative to GMT (which corresponds to UTC).Maybe using
getTimezoneOffset
would be safer.I rebased my local 644/datepicker branch on master, but was not abel to push it.
Obviously there is no other way then to merge it manually into master. Please drop me a note, when merging is OK.