Giter Site home page Giter Site logo

django-simple-email-confirmation's Introduction

django-simple-email-confirmation

A Django app providing simple email confirmation.

This app can be used to support three different ways of organizing your Users their email address(es). Each email address can be in a confirmed/unconfirmed state.

  • Users have one email address that is stored on the User
  • Users have one primary email address stored on the User model, and have N secondary emails stored in EmailAddress objects
  • Users have N email addresses stored in EmailAddress objects.

Examples

Create a new User, confirm their email:

from django.core.mail import send_mail
# ...

email = '[email protected]'
user = User.objects.create_user(email, email=email)
user.is_confirmed # False

send_mail(email, 'Use %s to confirm your email' % user.confirmation_key)
# User gets email, passes the confirmation_key back to your server

user.confirm_email(user.confirmation_key)
user.is_confirmed # True

Add another email to an existing User, confirm it, then set it as their primary.

new_email = '[email protected]'
confirmation_key = user.add_unconfirmed_email(new_email)
new_email in user.unconfirmed_emails # True

send_mail(new_email, 'Use %s to confirm your new email' % confirmation_key)
# User gets email, passes the confirmation_key back to your server

user.confirm_email(confirmation_key)
new_email in user.confirmed_emails # True

user.set_primary_email(new_email)
user.email # [email protected]

Installation

  1. From pypi using pip:

    pip install django-simple-email-confirmation
  2. Add simple_email_confirmation to your settings.INSTALLED_APPS:

    INSTALLED_APPS = (
        ...
        'simple_email_confirmation',
        ...
    )
  3. Add the provided mixin to your django 1.5+ custom user model:

    from django.contrib.auth.models import AbstractUser
    from simple_email_confirmation.models import SimpleEmailConfirmationUserMixin
    
    class User(SimpleEmailConfirmationUserMixin, AbstractUser):
        pass

    Note: you don't strictly have to do this final step. Without this, you won't have the nice helper functions and properties on your User objects but the remainder of the app should function fine.

  4. Change default settings (optional):

    By default, keys don't expire. If you want them to, set settings.SIMPLE_EMAIL_CONFIRMATION_PERIOD to a timedelta.

    from datetime import timedelta
    
    EMAIL_CONFIRMATION_PERIOD_DAYS = 7
    SIMPLE_EMAIL_CONFIRMATION_PERIOD = timedelta(days=EMAIL_CONFIRMATION_PERIOD_DAYS)

    By default, auto-add unconfirmed EmailAddress objects for new Users. If you want to change this behaviour, set settings.SIMPLE_EMAIL_CONFIRMATION_AUTO_ADD to False.

    SIMPLE_EMAIL_CONFIRMATION_AUTO_ADD = False

    By default, a length of keys is 12. If you want to change it, set settings.SIMPLE_EMAIL_CONFIRMATION_KEY_LENGTH to integer value (maximum 40).

    SIMPLE_EMAIL_CONFIRMATION_KEY_LENGTH = 16

    You are able to override the EmailAddress model provided with this app. This works in a similar fashion as Django's custom user model and allows you to add fields to the EmailAddress model, such as a uuid, or define your own model completely. To set a custom email address model, set settings.SIMPLE_EMAIL_CONFIRMATION_EMAIL_ADDRESS_MODEL to the model you would like to use in the <app_label>.<model_name> fashion.

    An admin interface is included with simple email confirmation. Although, it is designed to work with the EmailAddress provided. Functionality with the admin cannot be guaranteed when a custom model is used so it is recommended you provide your own admin definition.

    Note for existing apps that already use the provided model:

    Similar to Django's custom user model, migrating a custom email address model after the default one is already migrated is not supported and could have unforeseen side effects. The recommendation is to use a custom model from the beginning of development.

    SIMPLE_EMAIL_CONFIRMATION_EMAIL_ADDRESS_MODEL = 'yourapp.EmailAddress'

Migrating

0.23 to 1.0

A number of backwards incompatible changes are included in the 1.0 release.

  • Signal arguments have been refactored. Now, the email_confirmed, unconfirmed_email_created, and primary_email_changed signals send the user class as the sender argument and include the user instance as an additional user argument. You can update your code as follows:

    @receiver(email_confirmed)
    def listener(sender, user, email, **kwargs):
        pass
    
    @receiver(unconfirmed_email_created)
    def listener(sender, user, email, **kwargs):
        pass
    
    @receiver(primary_email_changed)
    def listener(sender, user, old_email, new_email, **kwargs):
        pass

Python/Django supported versions

  • Python: 2.7, 3.4, 3.5 and 3.6
  • Django: 1.8 to 2.0

Running the Tests

  1. Install tox and coverage

    pip install tox coverage
  2. From the repository root, run

    tox
    tox -e coverage

    It's that simple.

Found a Bug?

To file a bug or submit a patch, please head over to django-simple-email-confirmation on github.

Credits

Originally adapted from Pinax's django-email-confirmation, which was originally adapted from James Tauber's django-email-confirmation.

django-simple-email-confirmation's People

Contributors

brosner avatar djedi avatar dstufft avatar empty avatar fahadalbukhari avatar ferndot avatar feroda avatar g-as avatar imposeren avatar jakeharding avatar jeffbowen avatar jezdez avatar jtauber avatar kennell avatar lehins avatar luisza avatar matthewryanscott avatar mdamien avatar mfogel avatar ourcach avatar piiteer avatar sys13 avatar twidi avatar wlonk avatar zeezdev avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

django-simple-email-confirmation's Issues

Upgrade the pip version

Hello

I realized that the version of the code you install directly from pip is the 0.23, when the last version of the code you have here is the 0.6, with significant changes.

Is there any plans to upgrade the pip version? what about the 1.0 version you mention at the end of the documentation?

Thanks.

User mixin example is not clear

Adding the mixin to the User model is not clear to me as a django newbie:

  • Does it need to be in a custom Auth app in my project?
  • Do I need to alter the AUTH_USER_MODEL in the settings.py file?
  • Also do I need to perform migrations after this step?

I think this part could be made more clear in the docs.

Just a suggestion

In EmailAddress's unicode instead of return '{} ({})'.format(self.email, self.user) return return '{} <{}>'.format(self.user, self.email) which would result in a value u"Full Name <[email protected]>" that can be used as an email parameter to send_email.
It's just a suggestion, it would be beneficial to some, I think.

New release PyPI installation failure

@mdamien maybe you're already aware, but just in case...

New release is here but un-installable via pip.

If version number is unspecified, 0.12 is installed

If 0.20 is specified :

pip install django-simple-email-confirmation==0.20
Collecting django-simple-email-confirmation==0.20
  Could not find a version that satisfies the requirement django-simple-email-confirmation==0.20 (from versions: 0.9, 0.9.1, 0.10, 0.10.1, 0.10.2, 0.11, 0.12)
No matching distribution found for django-simple-email-confirmation==0.20

And BTW, thanks for stepping up man!

Do we really want to support usage without a mixin?

There is a lot of functionality included in our user mixin. Consequently, there is also much complexity inherent in ensuring that the app functions properly both with and without it.

I propose that we drop the line in our docs that mentions that the app can be used without applying the mixin. It would greatly simplify our maintenance and reduce the worry of adding new features to the mixin.

Please reply with any objections you may have!

Make migration error (Django 2.0)

I am trying to use django-simple-email-confirmation in my django project and install by pip, when I use it and trying to make migration, the following is happended:

"path\simple_email_confirmation\models.py", line 217, in EmailAddress
settings.AUTH_USER_MODEL, related_name='email_address_set',
TypeError: init() missing 1 required positional argument: 'on_delete'

And I fixed it by adding on_delete=models.CASCADE in simple_email_confirmation\models.py, Django 2.0 seems need to add it.

SQLall errors

When I run manage.py sqlall <app-name>, I get this:

auth.User.groups: (fields.E304) Reverse accessor for 'User.groups' clashes with reverse accessor for 'User.groups'.
        HINT: Add or change a related_name argument to the definition for 'User.groups' or 'User.groups'.
auth.User.user_permissions: (fields.E304) Reverse accessor for 'User.user_permissions' clashes with reverse accessor for 'User.user_permissions'.
        HINT: Add or change a related_name argument to the definition for 'User.user_permissions' or 'User.user_permissions'.
app-name.User.groups: (fields.E304) Reverse accessor for 'User.groups' clashes with reverse accessor for 'User.groups'.
        HINT: Add or change a related_name argument to the definition for 'User.groups' or 'User.groups'.
app-name.User.user_permissions: (fields.E304) Reverse accessor for 'User.user_permissions' clashes with reverse accessor for 'User.user_permissions'.
        HINT: Add or change a related_name argument to the definition for 'User.user_permissions' or 'User.user_permissions'.

I followed the instructions exactly and each user is also bound to a profile with a OneToOneField.

Specify custom EmailAddress model

It would be nice to be able to override the default EmailAddress model. In my case, I would like to use UUID PKs instead of the default AutoField.

Others might want to attach additional fields to the model.

Support Django Rest Framework

I extended this package to support Django Rest Framework for a personal project. This is a functionality that is not supported by any other email verification package for Django (that I have found).

Would there be interest in merging this into this package (like what django-filter does). Or, should I create a separate package to bolt on the functionality?

Dependency cycle

When I have:
AUTH_USER_MODEL = 'MyApp.User' and User model is in MyApp.migrations.0001_initial that depends on ('simple_email_confirmation', '0001_initial')

simple_email_confirmation has migrations 0001_initial that depends on migrations.swappable_dependency(settings.AUTH_USER_MODEL) which means MyApp.migrations.0001_initial

This causes the django migrations not work.

deprecated warning in django 1.8

RemovedInDjango19Warning: Model class simple_email_confirmation.models.EmailAddress doesn't declare an explicit app_label and either isn't in an application in INSTALLED_APPS or else was imported before its application was loaded. This will no longer be supported in Django 1.9.

Confirmation key generating problem

So, I'm using this app in my django project, and I noticed one strange thing.

When I create a user using form.

    if request.method == 'POST' and 'email' in request.POST:

            args['form'] = EmployeeCreationForm()

            form = EmployeeCreationForm(request.POST)

            if form.is_valid():

                    user = form.save()

And I try to access: user.confirmation_key
Sometimes I get user's confirmation key, or I can get EmaillAdress DoesNotExist exception.
It doesn't depend on any code. I tested it about 10 times, it happens on random.
So, I came up with this code:

    try:    

            confirmation_key = user.confirmation_key

            msg_html = render_to_string('email/confirmation.html', {'key' : confirmation_key})

            return send_mail('Confirmation email', '[email protected]', [user.email], html_message=msg_html,
    )
        except:
            confirmation_key = user.add_unconfirmed_email(user.email)

            msg_html = render_to_string('email/confirmation.html', {'key' : confirmation_key})

            return send_mail('Confirmation email', '[email protected]', [user.email], html_message=msg_html,
    )

So, I try to access user.confirmation_key, if I catch DoesNotExist, I create it manually.

Of course, it shouldn't work that way.

Any thoughts?
I believe it is a problem with signals (they can't reach on time or something)

Django version 1.8.2

Also, here is some messages from my terminal:
simple_email_confirmation/models.py:203: RemovedInDjango19Warning: Model class simple_email_confirmation.models.EmailAddress doesn't declare an explicit app_label and either isn't in an application in INSTALLED_APPS or else was imported before its application was loaded. This will no longer be supported in Django 1.9.
class EmailAddress(models.Model):

simple_email_confirmation/models.py:203: RemovedInDjango19Warning: Model class simple_email_confirmation.models.EmailAddress doesn't declare an explicit app_label and either isn't in an application in INSTALLED_APPS or else was imported before its application was loaded. This will no longer be supported in Django 1.9.
class EmailAddress(models.Model):

makemigrations fails on django 1.8.4

After following the instructions on the README, I get this error message from the console when trying to run makemigrations command:

ERRORS:
auth.User.groups: (fields.E304) Reverse accessor for 'User.groups' clashes with reverse accessor for 'User.groups'.
HINT: Add or change a related_name argument to the definition for 'User.groups' or 'User.groups'.
auth.User.user_permissions: (fields.E304) Reverse accessor for 'User.user_permissions' clashes with reverse accessor for 'User.user_permissions'.
HINT: Add or change a related_name argument to the definition for 'User.user_permissions' or 'User.user_permissions'.
myauth.User.groups: (fields.E304) Reverse accessor for 'User.groups' clashes with reverse accessor for 'User.groups'.
HINT: Add or change a related_name argument to the definition for 'User.groups' or 'User.groups'.
myauth.User.user_permissions: (fields.E304) Reverse accessor for 'User.user_permissions' clashes with reverse accessor for 'User.user_permissions'.
HINT: Add or change a related_name argument to the definition for 'User.user_permissions' or 'User.user_permissions'.

My guess was because AUTH_USER_MODEL wasn't pointing to my new User model. However, after setting it to myapp.models.User I got this error message about a missing table:

Traceback (most recent call last):
File "", line 1, in
File "/usr/local/lib/python2.7/dist-packages/django/contrib/auth/models.py", line 187, in create_user
**extra_fields)
File "/usr/local/lib/python2.7/dist-packages/django/contrib/auth/models.py", line 182, in _create_user
user.save(using=self._db)
File "/usr/local/lib/python2.7/dist-packages/django/db/models/base.py", line 734, in save
force_update=force_update, update_fields=update_fields)
File "/usr/local/lib/python2.7/dist-packages/django/db/models/base.py", line 771, in save_base
update_fields=update_fields, raw=raw, using=using)
File "/usr/local/lib/python2.7/dist-packages/django/dispatch/dispatcher.py", line 201, in send
response = receiver(signal=self, sender=sender, **named)
File "/usr/local/lib/python2.7/dist-packages/simple_email_confirmation/models.py", line 278, in auto_add
user.add_unconfirmed_email(email)
File "/usr/local/lib/python2.7/dist-packages/simple_email_confirmation/models.py", line 115, in add_unconfirmed_email
address = self.email_address_set.create_unconfirmed(email)
File "/usr/local/lib/python2.7/dist-packages/simple_email_confirmation/models.py", line 180, in create_unconfirmed
address = self.create(user=user, email=email, key=key)
File "/usr/local/lib/python2.7/dist-packages/django/db/models/fields/related.py", line 752, in create
return super(RelatedManager, self.db_manager(db)).create(**kwargs)
File "/usr/local/lib/python2.7/dist-packages/django/db/models/manager.py", line 127, in manager_method
return getattr(self.get_queryset(), name)(_args, *_kwargs)
File "/usr/local/lib/python2.7/dist-packages/django/db/models/query.py", line 348, in create
obj.save(force_insert=True, using=self.db)
File "/usr/local/lib/python2.7/dist-packages/django/db/models/base.py", line 734, in save
force_update=force_update, update_fields=update_fields)
File "/usr/local/lib/python2.7/dist-packages/django/db/models/base.py", line 762, in save_base
updated = self._save_table(raw, cls, force_insert, force_update, using, update_fields)
File "/usr/local/lib/python2.7/dist-packages/django/db/models/base.py", line 846, in _save_table
result = self._do_insert(cls._base_manager, using, fields, update_pk, raw)
File "/usr/local/lib/python2.7/dist-packages/django/db/models/base.py", line 885, in _do_insert
using=using, raw=raw)
File "/usr/local/lib/python2.7/dist-packages/django/db/models/manager.py", line 127, in manager_method
return getattr(self.get_queryset(), name)(_args, *_kwargs)
File "/usr/local/lib/python2.7/dist-packages/django/db/models/query.py", line 920, in _insert
return query.get_compiler(using=using).execute_sql(return_id)
File "/usr/local/lib/python2.7/dist-packages/django/db/models/sql/compiler.py", line 974, in execute_sql
cursor.execute(sql, params)
File "/usr/local/lib/python2.7/dist-packages/django/db/backends/utils.py", line 79, in execute
return super(CursorDebugWrapper, self).execute(sql, params)
File "/usr/local/lib/python2.7/dist-packages/django/db/backends/utils.py", line 64, in execute
return self.cursor.execute(sql, params)
File "/usr/local/lib/python2.7/dist-packages/django/db/utils.py", line 97, in exit
six.reraise(dj_exc_type, dj_exc_value, traceback)
File "/usr/local/lib/python2.7/dist-packages/django/db/backends/utils.py", line 64, in execute
return self.cursor.execute(sql, params)
File "/usr/local/lib/python2.7/dist-packages/django/db/backends/sqlite3/base.py", line 318, in execute
return Database.Cursor.execute(self, query, params)
OperationalError: no such table: simple_email_confirmation_emailaddress

Migrations for existing users?

Hello!

I installed this app to use in my project and it seems to work nicely. However I realised that the users created before the installation of this app return false for .is_confirmed(). This prevents them from logging in. I tried making a data migration for running user.confirm_email(user.confirmation_key) but user.confirmation_key throws an error saying EmailAddress matching query does not exist. Does this mean that the old users entirely lack some database connections to at all be functioning with this app?

How can I properly migrate to mitigate this issue? Thanks!

Package breaks in Django >=3.0.0

Tested with django==3.0.0 and django==3.0.1

File "/home/k/.virtualenvs/focsec/lib/python3.6/site-packages/simple_email_confirmation/models.py", line 9, in <module>
    from django.utils.encoding import python_2_unicode_compatible
ImportError: cannot import name 'python_2_unicode_compatible'

It seems that this was dropped in Django 3.0.0 (see release notes) and can simply be fixed by importing directly from six

LICENSE file?

First and foremost, thank you for creating a great django module. Its a pleasure to use.

Would it be possible to have a LICENSE file added? I'd like to respect author's intent when using their code.

Token's deleted from database gives error

When the token it's deleted from the database it gives an error when confirm the user with this token.

simple_email_confirmation.models.EmailAddress.DoesNotExist: EmailAddress matching query does not exist
image

'User' object has no attribute 'is_confirmed'

Hello,
I use Django 2.1.3, and django-simple-email-confirmation 0.23

When I want to check if request.user is confirmed or not, I get the error:
'User' object has no attribute 'is_confirmed'

code:
if request.user.is_confirmed:

ownership transfer

As per @mfogel's commit, I was thinking of Jazzband (github, website), which has been designed for this particular case. I believe this project definitely falls into the scope of the guidelines, minus a few tweaks. What do you guys think?

User.user.permissiom

Unhandled exception in thread started by <function check_errors..wrapper at 0x0000021DA49B3A60>
Traceback (most recent call last):
File "C:\Users\nEW u\PycharmProjects\prayrollproj3\venv\lib\site-packages\django\utils\autoreload.py", line 225, in wrapper
fn(*args, **kwargs)
File "C:\Users\nEW u\PycharmProjects\prayrollproj3\venv\lib\site-packages\django\core\management\commands\runserver.py", line 117, in inner_run
self.check(display_num_errors=True)
File "C:\Users\nEW u\PycharmProjects\prayrollproj3\venv\lib\site-packages\django\core\management\base.py", line 425, in check
raise SystemCheckError(msg)
django.core.management.base.SystemCheckError: SystemCheckError: System check identified some issues:

ERRORS:
auth.User.groups: (fields.E304) Reverse accessor for 'User.groups' clashes with reverse accessor for 'User.groups'.
HINT: Add or change a related_name argument to the definition for 'User.groups' or 'User.groups'.
auth.User.user_permissions: (fields.E304) Reverse accessor for 'User.user_permissions' clashes with reverse accessor for 'User.user_permissions'.
HINT: Add or change a related_name argument to the definition for 'User.user_permissions' or 'User.user_permissions'.
paymentapp.User.groups: (fields.E304) Reverse accessor for 'User.groups' clashes with reverse accessor for 'User.groups'.
HINT: Add or change a related_name argument to the definition for 'User.groups' or 'User.groups'.
paymentapp.User.user_permissions: (fields.E304) Reverse accessor for 'User.user_permissions' clashes with reverse accessor for 'User.user_permissions'.
HINT: Add or change a related_name argument to the definition for 'User.user_permissions' or 'User.user_permissions'.

Regarding key_length

Should the key length be increased from the regular 12 digit to a more bigger number?

def generate_key(self):
"Generate a new random key and return it"
# sticking with the django defaults
return get_random_string(length=30)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.