Skip to content
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

Merged
merged 11 commits into from May 3, 2017
Merged

644/datepicker #693

merged 11 commits into from May 3, 2017

Conversation

cornelinux
Copy link
Member

@cornelinux cornelinux commented Apr 28, 2017

The dateformat was changed to 2017-04-28T13:14+0200.

Merging #693 into master will increase coverage by <.01%.
The diff coverage is 100%.
Impacted file tree graph

@@            Coverage Diff             @@
##           master     #693      +/-   ##
==========================================
+ Coverage   95.33%   95.33%   +<.01%
==========================================
Files         121      121
Lines       14755    14762       +7
==========================================
+ Hits        14066    14073       +7
Misses        689      689
Impacted Files Coverage Δ
privacyidea/api/token.py 98.01% <ø> (ø) ⬆️
privacyidea/lib/utils.py 96.18% <100%> (+0.08%) ⬆️
privacyidea/lib/tokenclass.py 99.42% <100%> (-0.01%) ⬇️
privacyidea/lib/eventhandler/tokenhandler.py 93.87% <100%> (+0.12%) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update de7ed35...75d6487. Read the comment docs.

  •  File: privacyidea/lib/tokenclass.py:L918-927
  • 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.
  • Right, will change this to be on the safe side.
  • I wanted to start a review, so that I know, that I need to change here:
  • Please take look at 0cf82fb
  •  File: tests/test_lib_utils.py:L216-230
  • Fixed in 83769a6
  •  File: privacyidea/static/components/token/controllers/tokenDetailController.js:L1-38
  • 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.
  • 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 datepicker sets the correct timeformat.
The timeformat is used in all tests.

We need to document the timeformat and we
need to be able to *read* the old format from
the database and return the new format.

Working on #644
working on #644
@cornelinux cornelinux added this to the 2.19 milestone Apr 28, 2017
@codecov-io
Copy link

codecov-io commented Apr 28, 2017

Codecov Report

Merging #693 into master will increase coverage by <.01%.
The diff coverage is 100%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master     #693      +/-   ##
==========================================
+ Coverage   95.33%   95.33%   +<.01%     
==========================================
  Files         121      121              
  Lines       14755    14765      +10     
==========================================
+ Hits        14066    14076      +10     
  Misses        689      689
Impacted Files Coverage Δ
privacyidea/api/token.py 98.01% <ø> (ø) ⬆️
privacyidea/lib/policydecorators.py 98.14% <100%> (ø) ⬆️
privacyidea/lib/tokenclass.py 99.42% <100%> (ø) ⬆️
privacyidea/lib/eventhandler/tokenhandler.py 93.87% <100%> (+0.12%) ⬆️
privacyidea/lib/utils.py 96.18% <100%> (+0.08%) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update de7ed35...a86a0ad. Read the comment docs.

return datetime.datetime.now() > datetime.datetime.strptime(sdate,
DATE_FORMAT)
#date_change = datetime.datetime.strptime(sdate, DATE_FORMAT)
date_change = parse_date_string(sdate)
Copy link
Contributor

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.

Copy link
Member Author

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.

Copy link
Member Author

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:

Copy link
Member Author

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.

Copy link
Member Author

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

# 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():
Copy link
Contributor

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.

Copy link
Member Author

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?

Copy link
Member Author

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.

log.debug("Dateformat {1!s} did not match date {0!s}".format(
date_string, date_format))
try:
d = parse_date_string(date_string)
Copy link
Contributor

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 think parse_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?

Copy link
Member Author

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.

Copy link
Member Author

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))
Copy link
Contributor

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)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

touché

Copy link
Member Author

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
Copy link
Contributor

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.

Copy link
Member Author

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?

Copy link
Member Author

@cornelinux cornelinux left a 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.

# 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():
Copy link
Member Author

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?

return datetime.datetime.now() > datetime.datetime.strptime(sdate,
DATE_FORMAT)
#date_change = datetime.datetime.strptime(sdate, DATE_FORMAT)
date_change = parse_date_string(sdate)
Copy link
Member Author

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:

# 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():
Copy link
Member Author

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
Copy link
Member Author

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))
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

touché

log.debug("Dateformat {1!s} did not match date {0!s}".format(
date_string, date_format))
try:
d = parse_date_string(date_string)
Copy link
Member Author

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))
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 83769a6

log.debug("Dateformat {1!s} did not match date {0!s}".format(
date_string, date_format))
try:
d = parse_date_string(date_string)
Copy link
Member Author

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?

return datetime.datetime.now() > datetime.datetime.strptime(sdate,
DATE_FORMAT)
#date_change = datetime.datetime.strptime(sdate, DATE_FORMAT)
date_change = parse_date_string(sdate)
Copy link
Member Author

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.

return datetime.datetime.now() > datetime.datetime.strptime(sdate,
DATE_FORMAT)
#date_change = datetime.datetime.strptime(sdate, DATE_FORMAT)
date_change = parse_date_string(sdate)
Copy link
Member Author

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

@cornelinux cornelinux self-assigned this May 1, 2017
m = (m>9 ? '' : '0') + m;
o = date_obj.toTimeString().split(" ")[1];
// 10:20:11 GMT+0200 (CEST)
o = o.substring(3);
Copy link
Contributor

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.

Copy link
Member Author

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.

@cornelinux cornelinux merged commit a86a0ad into master May 3, 2017
cornelinux added a commit that referenced this pull request May 3, 2017
@tamaro-skaljic tamaro-skaljic deleted the 644/datepicker branch June 27, 2019 16:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants