Skip to content
This repository has been archived by the owner on May 5, 2020. It is now read-only.

Rest auth #79

Merged
merged 22 commits into from
Sep 14, 2018
Merged

Rest auth #79

merged 22 commits into from
Sep 14, 2018

Conversation

rubengrill
Copy link
Contributor

@rubengrill rubengrill commented Jul 22, 2018

This PR adds a rest api (#71) and support for Django 2.0.
I also dropped support for Django < 1.11 to not waste time implementing the rest api.
In #52 it is briefly discussed to follow Django's recommendation here, to support what Django supports.

I did some backward incompatible changes, I will document those changes later in this PR to discuss if those are acceptable and if they are, what the strategy should be to handle those changes (new major version, deprecation warnings...).

In "Refactor forms" some changes are made to allow easier customization of the sent emails, following the design of Django's auth views/forms.

nopassword/backends/base.py Show resolved Hide resolved
nopassword/backends/base.py Show resolved Hide resolved
nopassword/backends/base.py Show resolved Hide resolved

def send_login_code(self, code, secure=False, host=None, **kwargs):
subject = getattr(settings, 'NOPASSWORD_LOGIN_EMAIL_SUBJECT', _('Login code'))
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Backward incompatible: Instead of a custom setting, we use a template instead (like django auth forms/views)

Copy link
Owner

Choose a reason for hiding this comment

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

Why do we want to use templates for this? Subjects can only be plain text in one line, so this feels a bit like we introduce a breaking change in configuration that is not really giving us anything?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It would be consistent with django default auth forms: https://github.com/django/django/blob/2.1/django/contrib/auth/forms.py#L239
Also it would be consisent to also use a template for the subject, not only for the message itself.
A use case I could think of where it might be desired is to have the site name in the subject, e.g. [example.com] Login with one-time password, where the current site is dependent on the request (sites framework).

Copy link
Owner

Choose a reason for hiding this comment

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

Sounds good to me

nopassword/backends/email.py Show resolved Hide resolved
@@ -5,23 +5,10 @@

urlpatterns = [
url(
r'^login/$',
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Backward incompatible: Renamed urls to reflect view name changes.

nopassword/views.py Show resolved Hide resolved
nopassword/views.py Show resolved Hide resolved
nopassword/views.py Show resolved Hide resolved
tests/urls.py Show resolved Hide resolved
@rubengrill
Copy link
Contributor Author

rubengrill commented Jul 23, 2018

@relekang Are the breaking changes acceptable in your opinion? If so, how should the they be handled?
I see three possible strategies:

  • Just document them and create a new major version
  • Change code to be compatible and add warnings
  • Don't do backward incompatible changes

@relekang
Copy link
Owner

Thanks @rubengrill, api endpoints is a good addition. I am leaving for vacation today so will review this in about two weeks, the pr is quite large so I won't manage it before I leave. Thank you for your patience ✌️

@sebslomski
Copy link

@rubengrill Thanks, I'm already using your PR for local development.
@relekang Really looking forward to having this on PyPi!

Copy link
Owner

@relekang relekang left a comment

Choose a reason for hiding this comment

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

@rubengrill I finally got some time to look this over. Over all it looks great 👏 I left some questions and comments. Before we can merge this all the changes that have done, on configuration and usage needs to be reflected in the documentation.

Could you also reword the commits to use conventional commits?

nopassword/backends/base.py Show resolved Hide resolved

def send_login_code(self, code, secure=False, host=None, **kwargs):
subject = getattr(settings, 'NOPASSWORD_LOGIN_EMAIL_SUBJECT', _('Login code'))
Copy link
Owner

Choose a reason for hiding this comment

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

Why do we want to use templates for this? Subjects can only be plain text in one line, so this feels a bit like we introduce a breaking change in configuration that is not really giving us anything?

msg = EmailMultiAlternatives(subject, text_content, from_email, to_email)
msg.attach_alternative(html_content, 'text/html')
msg.send()
if self.html_template_name is not None:
Copy link
Owner

Choose a reason for hiding this comment

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

What is the benefit of this change? In my opinion we should strive for an easier solution to adopt for the user than needing to extend the class. It would be perfect if the template existed then we would send the html version.

@@ -0,0 +1,14 @@
{% load i18n %}{% autoescape off %}
Copy link
Owner

Choose a reason for hiding this comment

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

This seems like the text based email? Why does it have an html file ending?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yes that's nonsense, I will change to be txt

nopassword/utils.py Show resolved Hide resolved
requirements.txt Outdated
@@ -1,4 +1,4 @@
twilio==5.4.0
mock>=1.0
djangorestframework<=4.0
Copy link
Owner

Choose a reason for hiding this comment

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

Shouldn't this be the same as in setup.py?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, that's right

tests/settings.py Show resolved Hide resolved
Copy link
Contributor Author

@rubengrill rubengrill left a comment

Choose a reason for hiding this comment

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

Hi @relekang , Thanks for your comments!

Just to be sure:

Before we can merge this all the changes that have done, on configuration and usage needs to be reflected in the documentation.

This means documenting the breaking changes and different usage is enough, it will be a new major version and there doesn't need to be code for backward compatibility?

Please check my comments to discuss the breaking changes. Afterwards I will start with integrating the feedback, changing the documentation and rewording the commits.

Thanks again for your time and feedback! :)

nopassword/backends/base.py Show resolved Hide resolved

def send_login_code(self, code, secure=False, host=None, **kwargs):
subject = getattr(settings, 'NOPASSWORD_LOGIN_EMAIL_SUBJECT', _('Login code'))
Copy link
Contributor Author

Choose a reason for hiding this comment

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

It would be consistent with django default auth forms: https://github.com/django/django/blob/2.1/django/contrib/auth/forms.py#L239
Also it would be consisent to also use a template for the subject, not only for the message itself.
A use case I could think of where it might be desired is to have the site name in the subject, e.g. [example.com] Login with one-time password, where the current site is dependent on the request (sites framework).

msg = EmailMultiAlternatives(subject, text_content, from_email, to_email)
msg.attach_alternative(html_content, 'text/html')
msg.send()
if self.html_template_name is not None:
Copy link
Contributor Author

Choose a reason for hiding this comment

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

The idea was to be consistent with how django default auth form/view handles that:
https://github.com/django/django/blob/2.1/django/contrib/auth/views.py#L211
https://github.com/django/django/blob/2.1/django/contrib/auth/forms.py#L268

I don't exactly know why django does it this way but I can imagine that providing a default html email template would just be too opinonated, as you want to use html templates to include headers, logos, tables, containers, ... so any default template will have to be changed by the vendor either way.

But you are absolutely right, providing a custom backend just to use a html template seems to be too much work (I guess same applies to the django views/forms here...).

I just saw that allauth has a neat approach:
It also doesn't provide a default html template, but at least it tries to render the html template.
When there is a TemplateDoesNotExist exception, it ignores this template.

Should we use this approach, to set html_template_name with a default, but we don't provide that template and wrap rendering in a try/catch?

@@ -0,0 +1,14 @@
{% load i18n %}{% autoescape off %}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

yes that's nonsense, I will change to be txt

nopassword/views.py Show resolved Hide resolved
requirements.txt Outdated
@@ -1,4 +1,4 @@
twilio==5.4.0
mock>=1.0
djangorestframework<=4.0
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, that's right

tests/settings.py Show resolved Hide resolved
@relekang
Copy link
Owner

@rubengrill I have a pretty busy week, but will look into all your comments on the end of the week.

This means documenting the breaking changes and different usage is enough, it will be a new major version and there doesn't need to be code for backward compatibility?

Yes, and all the breaking changes that I did not comment on in the first review I agree with fully 👍

@rubengrill
Copy link
Contributor Author

Hi @relekang, great, then I'll wait for your final comments to start with the fixes.
Looking forward to the feedback.

@relekang
Copy link
Owner

I think I commented on all your questions now 😊

@rubengrill
Copy link
Contributor Author

All fixes have been addressed, except this:

  • Update documentation (will follow soon)
  • Reword commits (will follow soon)
  • Tests rest api: I have trouble here building a separate environment, as then we would have 2n environments. Also the tests should somehow be separated as the rest tests shouldn't run on the regular environments, and running the regular tests again in the rest environments doesn't make much sense.

I also renamed the views/forms, I'm very sorry for this confusion.
When testing in an example project I realized that the old naming didn't play well with the default of LOGIN_URL = '/accounts/login/', where the user was asked for the login code right after being redirected from a view that requires login...

@relekang
Copy link
Owner

relekang commented Sep 3, 2018

The updated changes looks good to me, great work 😊

@rubengrill
Copy link
Contributor Author

Docs are updated now, last step is rewording commits to confirm to conventional commits, I'll do this after the docs are approved as well, as I don't know how rebasing will affect the comments in this PR and might make review harder.

I will also add some new issues we should address before releasing a new version.
We wanted to integrate this PR already into a project and at some points integration was more difficult than expected.

@relekang
Copy link
Owner

relekang commented Sep 7, 2018

The changes looks good 👍

Missed this earlier why did the test setup change to sqlite?

def verify_user(self, user):
return user.is_active
timeout = getattr(settings, 'NOPASSWORD_LOGIN_CODE_TIMEOUT', 900)
timestamp = datetime.now() - timedelta(seconds=timeout)

Choose a reason for hiding this comment

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

Please use timezone provided by django instead of datetime.

@rubengrill
Copy link
Contributor Author

I had some problems to get the tests running with the default configuration, some local problems with my postgresql database and some warnings of an outdated pip dependency.
The environment variable for using sqlite somehow didn't work, I had to hardcode using the sqlite database to get everything running.
That's why I thought it might be good for contributors to be able to just start working without having connections problems in the beginning.
Should this be reverted?

Makes more sense from outside of nopassword, as requesting a login code is the entry point of the login process.
This way the default value of LOGIN_URL (`/accounts/login/`) is correctly opening the login code request page.
@rubengrill
Copy link
Contributor Author

Renamed the first commits to confirm to conventional commits.

@relekang
Copy link
Owner

I think we can keep the sqlite for now. It seems CI is not working, so I will run all tests locally tomorrow and merge if it is all green. Great work @rubengrill 👏

@rubengrill
Copy link
Contributor Author

Awesome, looking forward to see it merged :)

@relekang relekang merged commit cf22def into relekang:master Sep 14, 2018
@relekang
Copy link
Owner

Thanks @rubengrill 👍

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants