Compare commits

...

175 Commits

Author SHA1 Message Date
Adam Lord
cdd04aa9be
Merge pull request #657 from weslord/patch-1
Update deprecation notice with link to fork
2022-02-25 13:28:51 -08:00
Wes Lord
146777283e Update deprecation notice with link to fork
A deprecation notice meant for this repo was accidentally applied to
https://github.com/Tivix/django-cron instead.

I've directly copied the text from that commit.
2022-02-24 15:07:25 -08:00
Sumit Chachra
3c36004c44
Merge pull request #603 from raunaqss/patch-1
Update ReadMe with state of repo
2021-03-07 21:54:38 -08:00
Raunaq Singh
0ad457cea6
Update ReadMe with state of repo
According to this issue: https://github.com/Tivix/django-rest-auth/issues/568. This repository is currently unmaintained. This information should be obvious to new users planning to use this package. Hence making this PR.

Thanks.
2020-02-25 12:20:57 +05:30
mario
624ad01afb
Merge pull request #313 from aspyct/feature/fr_localization
Added French translations
2019-04-18 20:02:52 +02:00
mario
04c692bba6
Merge pull request #468 from kneufeld/master
expand JWT acronym in docs
2019-04-18 20:01:15 +02:00
mario
4cf813262f
Merge pull request #481 from OskarPersson/old-password-error-msg
Use translated msg when providing incorrect old password
2019-04-18 19:58:54 +02:00
mario
bd843f9460
Merge pull request #526 from brunobarretofreitas/portugueseBrazilTranslation
Brazilian Portuguese Translation
2019-04-18 19:56:04 +02:00
Bruno Barreto Freitas
07d2bd5c56 Brazilian Portuguese Translation
- django.po file
2019-04-16 10:27:43 -03:00
mario
998b2b1fbc feat: prep for new release (0.9.5) 2019-04-01 09:51:08 +02:00
mario
c7ff94ced7 feat: prep for new release (0.9.4) 2019-04-01 07:51:51 +02:00
mario
ac44fbe07a
Merge pull request #483 from vthorey/vthorey/installation-doc
Vthorey/installation doc
2019-03-29 19:28:05 +01:00
mario
39252820f7
Merge pull request #521 from toracle/master
Added a korean translation
2019-03-29 19:25:34 +01:00
mario
043cb85374
Merge pull request #522 from gsheni/patch-1
Update installation.rst
2019-03-29 19:24:36 +01:00
Gaurav Sheni
f39d93042e
Update installation.rst 2019-03-26 11:07:27 -04:00
Jeongsoo Park
d2cd31a560 update revision date 2019-03-20 17:52:51 +09:00
Jeongsoo Park
11e877ba50 add a korean translation mo file 2019-03-20 17:51:09 +09:00
Jeongsoo Park
64b5572172 add a korean translation 2019-03-20 17:44:18 +09:00
mario
bb3b082895
Merge pull request #345 from gbezyuk/master
LoginView.get_response modified in order to respect rest_framework_jwt.JWT_AUTH_COOKIE setting
2019-03-16 14:57:01 +01:00
mario
5c556cd09a
Merge pull request #463 from erdtsksn/feat/translation-tr
feat: Add Turkish(tr) translation
2019-02-03 20:00:03 +01:00
mario
22a76d91ac
Merge pull request #470 from magnunleno/fix/add-missing-allauth-requirement
Adds django-allauth to dev-requirements.txt
2019-02-03 19:47:02 +01:00
mario
51d6bf4542
Merge pull request #472 from yihuang/master
add translation for Chinese
2019-02-03 19:02:42 +01:00
mario
c7cc41e07c
Merge pull request #506 from Jasper0819X/master
disable django_logout if REST_SESSION_LOGIN is False
2019-02-03 19:02:25 +01:00
Jasper Wan
a3d38f4c59 disable django_logout if REST_SESSION_LOGIN is False 2019-02-03 11:42:24 +08:00
Valentino
e891a76c3f Add example of github API in installation doc. 2018-11-12 16:58:07 +01:00
vthorey
25b94db0cc
Update installation.rst 2018-11-12 16:49:36 +01:00
Oskar Persson
c437ca22ff Translate msg when providing incorrect old password 2018-11-09 15:58:09 +01:00
yihuang
9913f8eb03 add translation for Chinese 2018-10-28 11:46:19 +08:00
Magnun Leno
ca39ba7ea9 Adds django-allauth to dev-requirements.txt 2018-10-27 02:14:25 -03:00
Kurt Neufeld
f5fe62ce91 expand JWT acronym in docs 2018-10-25 11:28:24 -06:00
erdtsksn
5d318b3a4b feat: Add Turkish(tr) translation
oth: There is no .mo file because there is a .gitignore entry for that.
2018-10-22 11:38:21 +03:00
mario
479a40d2cc
Merge pull request #437 from dgilge/request
Pass request to authenticate
2018-09-08 17:07:43 +02:00
mario
25263b3e4a
Merge pull request #442 from illagrenan/master
Add Czech (cs) translations
2018-09-08 17:03:22 +02:00
mario
834e4c4747
Merge pull request #434 from dgilge/DRF3.8
Add DRF 3.8 to Travis config
2018-09-08 17:00:13 +02:00
mario
f5fcf9f083
Merge pull request #452 from rpkilby/gardening
Minor package maintenance
2018-09-08 16:54:51 +02:00
Ryan P Kilby
4b07c3ca92 Add wheel & metdata config 2018-08-21 21:29:15 -07:00
Ryan P Kilby
691c73d556 Update .gitignore from GH 2018-08-21 21:18:41 -07:00
Ryan P Kilby
f0941b4cc2 Merge tools configs into setup.cfg 2018-08-21 21:16:52 -07:00
Ryan P Kilby
033ee8f483 Remove deprecated EZ setup 2018-08-21 21:12:28 -07:00
Václav Dohnal
53f901b3c8 refresh .mo file 2018-06-27 23:22:38 +02:00
Vašek Dohnal
3af4f1a343
fix typo 2018-06-27 23:21:56 +02:00
Vašek Dohnal
b778a5085b
add full project name 2018-06-27 23:20:10 +02:00
Vašek Dohnal
98212a83f5
fix typo 2018-06-27 23:19:48 +02:00
Václav Dohnal
fa3000e8bd add cs translations 2018-06-27 23:18:39 +02:00
Václav Dohnal
b9fd4aba96 add czech (cs) translations stub 2018-06-27 23:06:34 +02:00
Daniel
a1845aef43 Pass request to authenticate 2018-06-14 00:06:20 +02:00
Daniel
db60e43397 Exclude Python 2.7 for Django 2.0 2018-06-11 09:02:02 +02:00
Daniel
90760548f6 Add DRF 3.8 to Travis config 2018-06-11 08:46:59 +02:00
Maxim Kukhtenkov
95fafe5e0f Remove Django 1.8 from Travis config 2018-06-06 17:10:43 -04:00
Maxim Kukhtenkov
801bad7c61 Update copyright and version number in Docs config 2018-06-06 15:01:22 -04:00
Maxim Kukhtenkov
a3057b7aa1 Flake8 fix - unused import 2018-01-20 20:25:58 -05:00
Maxim Kukhtenkov
c009bb9975 Change conditional import from allauth.socialaccount 2018-01-20 20:10:18 -05:00
Maxim Kukhtenkov
bcd6ab4401 Update configs and changelog for version 0.9.3 + additional fixes 2018-01-19 19:44:31 -05:00
Maxim Kukhtenkov
6a84d85d91 Add change in documentation and tests for social connect 2018-01-19 18:29:38 -05:00
Maxim Kukhtenkov
3eb546f633 Add extra info to docs for social connect
#347
2018-01-18 21:11:36 -05:00
Maxim Kukhtenkov
fed6b9840c Refactor social connect views and serializers
# 347
2018-01-18 21:08:41 -05:00
Maxim Kukhtenkov
41ae498be0
Merge pull request #387 from aleksihakli/master
Implement connect social accounts functionality
2018-01-18 21:02:45 -05:00
Aleksi Häkli
8a4afe746c
Implement connect social accounts functionality
Add serializers and views for connecting accounts with minimal
specialization of the existing django-rest-auth interfaces.

Also add viewset which enables listing social account infmration
via the REST API for social authentication driven client applications.

Resolves #347 in GitHub.
2018-01-18 16:56:42 +02:00
Maxim Kukhtenkov
a892ca3fa5 Upgrade requirements for demo project 2017-12-16 16:48:34 -05:00
Maxim Kukhtenkov
5e6c5a75ea Changes in demo project settings for Django 2.0 compatibility 2017-12-05 12:39:57 -05:00
Maxim Kukhtenkov
98d5ce314f Fix unit tests 2017-12-05 00:39:32 -05:00
Maxim Kukhtenkov
7ad440f7a2 Remove Django 1.10 from tests and move imports to top of the file 2017-12-05 00:23:37 -05:00
Maxim Kukhtenkov
fcca39643e
Merge pull request #391 from michael-k/patch-1
Run tests against Django 2.0
2017-12-05 00:20:31 -05:00
Michael K
3a2a256821 Fixes import path for django's reverse 2017-12-04 15:02:36 +01:00
Michael
864aa60f92 Run tests against Django 2.0
https://www.djangoproject.com/weblog/2017/dec/02/django-20-released/
2017-12-04 15:02:36 +01:00
mario
ed16455712
Merge pull request #386 from ducheneaut/patch-1
Prevent double-validation in LoginSerializer
2017-11-27 08:15:33 +01:00
Nic Ducheneaut
8bd8d604ff
Prevent double-validation in LoginSerializer
Modified branching statement to prevent double-validation when using "email" as the authentication method with Allauth.
2017-11-25 14:10:44 -08:00
mario
658664a7d4 Merge branch 'master' into pr/367 2017-11-12 10:36:13 +01:00
mario
ee791a402e
Merge pull request #367 from philippeluickx/d/pre_existing_acounts_check
Checking for pre-existing accounts
2017-11-12 10:35:36 +01:00
mario
f89471f980 pep8 cleanups 2017-11-12 10:32:27 +01:00
mario
a670fa9687
Merge pull request #372 from sloria/test-py36
Test against Python 3.6
2017-10-31 21:20:05 +01:00
mario
1b51eb8732
Merge pull request #380 from Tivix/travis-conf-fixes
Travis conf fixes
2017-10-31 18:27:42 +01:00
mario
2c1649daf1 fix: revert setup.py changes 2017-10-31 17:13:57 +01:00
mario
be2ac99a34 fix: changed travis.yml and setup.py configuration 2017-10-31 16:34:29 +01:00
mario
e4c04528a2 Merge pull request #373 from sloria/versioning-compat
Handle extra args and kwargs in all POST endpoints
2017-10-25 14:56:40 +02:00
Steven Loria
b34250ec94
Handle extra args and kwargs in all POST endpoints
This fixes compatibility with DRF's versioning
2017-10-24 20:14:12 -04:00
Steven Loria
05e5c647fa
Test against Python 3.6 2017-10-24 19:51:45 -04:00
Philippe Luickx
945008d326 Checking for pre-existing accounts from a different flow when using social connect 2017-10-05 12:06:05 +03:00
Maxim Kukhtenkov
42d039b473 Fix urlpatterns format in docs 2017-10-03 10:17:48 -04:00
Maxim Kukhtenkov
7e708d9ca7 Update configs and changelog for version 0.9.2 2017-10-02 15:52:33 -04:00
mario
30c89b1cc6 chore: added new test case for custom permission classes + general test module cleanups 2017-10-02 21:38:06 +02:00
Maxim Kukhtenkov
8afba8ca16 Merge pull request #341 from bIgBV/add-request-to-context
Pass request in the context when initializing `LoginSerializer`
2017-10-02 12:57:07 -04:00
Maxim Kukhtenkov
7a0fa017d3 Add MANIFEST.in change from #335 to master branch 2017-10-02 12:31:02 -04:00
Maxim Kukhtenkov
d16ec273e6 Merge pull request #366 from sobolevn/patch-1
Updates README.rst with svg badges
2017-10-02 11:56:54 -04:00
Nikita Sobolev
99b68b2914 Updates README.rst with svg badges 2017-10-02 18:46:47 +03:00
Maxim Kukhtenkov
53398f8727 Merge pull request #327 from blablacio/user-details-serializer-context
Pass context to user defined USER_DETAILS_SERIALIZER
2017-10-02 11:26:37 -04:00
Mateusz Sikora
b124aaf273 Merge pull request #334 from jrief/fixes/bypass-user-object
return user object from upstream method invocation
2017-09-21 09:43:41 +02:00
Grigoriy Beziuk
46fd16700a also for cookie deletion 2017-06-30 14:23:56 +03:00
Grigoriy Beziuk
2672263100 Merge pull request #2 from gbezyuk-on-software/master
LoginView.get_response modified in order to respect rest_framework_jwt.JWT_AUTH_COOKIE setting
2017-06-30 14:04:58 +03:00
Grigoriy Beziuk
18e98d333b Merge pull request #1 from Tivix/master
merge upstream
2017-06-30 14:04:02 +03:00
Grigoriy Beziuk
6da0703b0d LoginView.get_response modified in order to respect rest_framework_jwt.JWT_AUTH_COOKIE setting 2017-06-30 13:59:10 +03:00
David Gunter
9d1f65eedc Merge pull request #338 from verkaufer/jwt_docs_fix
Update JWT Support documentation
2017-06-28 11:36:04 -07:00
bIgBV
98306a35c1 Pass request in the context when initializing LoginSerializer 2017-06-24 18:50:50 +05:30
David Gunter
f0175b4aac Update JWT Support documentation to explain how the library uses django-rest-framework-jwt to handle token encoding. 2017-06-15 16:30:21 -07:00
mario
606858fba7 Merge pull request #336 from Vitiell0/patch-1
Add step to remind user to migrate their database
2017-06-12 17:34:31 +02:00
Daniel Vitiello
8981317b1c Add step to remind user to migrate their database
I didn't do this and spent a while tracking down errors with CSRF and Token Validation.
2017-06-04 16:54:03 -05:00
mario
eb9e6eb05a Merge pull request #331 from nattyg93/patch-1
Fix docs settings typo
2017-05-31 19:10:45 +02:00
Jacob Rief
90219295a4 return user object from upstream method invocation 2017-05-30 09:26:16 +02:00
Nathanael Gordon
937162bd97 Fix docs settings typo 2017-05-17 23:36:09 +10:00
Maxim Kukhtenkov
cbda9ee075 Add Django 1.11 to Travis CI 2017-05-15 10:36:19 -04:00
mario
13863991ca Merge pull request #321 from mpuhacz/polish-translation
polish translation
2017-05-14 21:52:27 +02:00
Vladislav Manchev
052094d43c Pass context to user defined USER_DETAILS_SERIALIZER 2017-04-26 23:20:10 +02:00
Maxim Kukhtenkov
8c58782e30 Change requirements in setup.py: allauth is only required for tests 2017-03-20 19:28:32 -07:00
mario
dd3eb3e8c6 fix: few fixes for #312 2017-03-19 21:21:32 +01:00
mario
e665b95643 Merge pull request #312 from swstack/custom-registration-permissions
Custom registration permissions
2017-03-19 13:24:31 +01:00
mpuhacz
bf96f6ab8e polish translation 2017-03-11 15:50:27 +01:00
mpuhacz
d0d348bf6b polish translation 2017-03-11 12:33:25 +01:00
mpuhacz
50325ddb4f polish translation 2017-03-11 12:10:55 +01:00
Maxim Kukhtenkov
819fbf768f Update configs and changelog for version 0.9.1 2017-03-05 22:05:08 -08:00
Maxim Kukhtenkov
469e4af82b Compile translations 2017-03-05 22:02:28 -08:00
Maxim Kukhtenkov
5b94deb5c5 Merge pull request #300 from Cahersan/master
Added Spanish translations
2017-03-05 21:55:25 -08:00
Maxim Kukhtenkov
48dba428d8 Merge pull request #308 from joaoricardo000/master
Added djangorestframework-jwt as test requirement, and typo
2017-03-05 21:45:56 -08:00
Maxim Kukhtenkov
955ff3a280 Change retrieving user details serializer to avoid import error
#309
2017-03-05 21:37:14 -08:00
Antoine d'Otreppe
3f7035eb68 Added French translations 2017-02-14 13:28:42 +01:00
Stephen Stack
be17865b00 registration: allow custom permission classes 2017-02-12 17:35:28 -06:00
Stephen Stack
9cf4c4e730 deps: dev-requirements.txt to install developer dependencies 2017-02-12 16:47:03 -06:00
Stephen Stack
49eaf0feea deps: require django-allauth>=0.25.0 2017-02-12 16:41:11 -06:00
Joao Ricardo
60a12107ba Add djangorestframework-jwt on test_require 2017-01-29 13:18:44 -02:00
Joao Ricardo
60a585339b Fix typo on test variable name 2017-01-29 13:17:33 -02:00
Carlos
09a30742f7 Added Spanish translations 2017-01-13 11:49:02 +01:00
Maxim Kukhtenkov
beb073f35f Update travis.yml and add latest Django 1.10 to tests 2016-12-31 12:59:49 -08:00
Maxim Kukhtenkov
971072ae37 Add sensitive_post_parameters decorator to several views 2016-12-31 12:55:19 -08:00
Maxim Kukhtenkov
ce58da58b2 Update configs and changelog for version 0.9.0 2016-12-22 13:29:51 -08:00
Maxim Kukhtenkov
951f3ce284 Compile translations and small text fixes 2016-12-22 11:57:23 -08:00
Maxim Kukhtenkov
aa677d51c0 PEP8 cleanup and small text fixes 2016-12-21 14:08:56 -08:00
Maxim Kukhtenkov
5bcf31f545 Remove redundant required=True from serializer fields 2016-12-21 13:47:24 -08:00
Maxim Kukhtenkov
9df9608631 Add get_queryset method to UserDetailsView due to issue with Swagger
#275
2016-12-21 11:40:18 -08:00
Maxim Kukhtenkov
e81ed716ec Add verification e-mail sent message
#240
2016-12-21 11:31:04 -08:00
Maxim Kukhtenkov
a673db87f8 Merge pull request #200 from mariuccio/master
'detail' keyword in success response messages
2016-12-21 11:12:59 -08:00
Maxim Kukhtenkov
592ea78edc Merge pull request #289 from squallcs12/refactor/allow-VerifyEmailView-work-with-swagger
Make VerifyEmailView display data field in swagger
2016-12-21 11:05:28 -08:00
Maxim Kukhtenkov
5ec3b73dec Merge pull request #284 from Akay7/RussianLanguage
Russian language
2016-12-10 13:52:13 -05:00
Maxim Kukhtenkov
d20a601fdd Merge pull request #286 from Tivix/jwt-serializer-with-custom-user-model
JWT serializer with custom user model
2016-12-09 10:12:52 -05:00
Bang Dao
d2917e9f3f refactor allow VerifyEmailView display data field in swagger 2016-12-09 16:53:09 +07:00
Maxim Kukhtenkov
f200b8d6f0 Remove redundant required=True from serializer fields
`required=True` is default setting
2016-12-07 21:47:07 -05:00
Maxim Kukhtenkov
f79537de77 Update API endpoints docs and docstring
https://github.com/Tivix/django-rest-auth/issues/280
2016-12-07 19:12:01 -05:00
Maxim Kukhtenkov
6812deeeb4 Rename variable for clarity
We have two variables named `token` which have different data types
2016-12-02 16:35:13 -08:00
Maxim Kukhtenkov
f09bbaf877 Merge pull request #283 from DigiCred/master
fix: social login using auth code flow
2016-12-02 16:08:13 -08:00
Maxim Kukhtenkov
ca62f44061 Append more information to comment
Explain why we are defining JWTUserDetailsSerializer in registration/serializers.py instead of getting it from app_settings.py
2016-11-30 20:03:34 -08:00
Maxim Kukhtenkov
45bda640e5 Add note to docs for defining custom REGISTER_SERIALIZER
#198
2016-11-30 19:49:25 -08:00
Maxim Kukhtenkov
ebf6a92b17 Merge pull request #288 from Tivix/logout_on_get
Logout on get
2016-11-30 19:41:14 -08:00
Maxim Kukhtenkov
cef8d67968 Move note under info on accepted params 2016-11-30 19:38:47 -08:00
Maxim Kukhtenkov
42ae22152a Remove dependency on allauth for logout on GET 2016-11-30 17:39:57 -08:00
Ankit Popli
139dd4a4e4
refactor: remove redundant check as suggested by @maxim-kht 2016-11-28 11:42:06 +05:30
Maxim Kukhtenkov
dd6db3563f Allow using custom UserDetailsSerializer with JWTSerializer - update 2016-11-27 17:57:55 -08:00
Maxim Kukhtenkov
7fc875a4f5 Change handling for logout on GET
+ Make it require allauth
+ Add a note to docs that it’s not a recommended setting
2016-11-27 03:37:05 -08:00
Egor Poderyagin
49ddf00d57 update messages in agreement to comment of pull request 2016-11-27 09:38:18 +03:00
Egor Poderyagin
89b48ce053 update language file 2016-11-27 09:25:48 +03:00
Egor Poderyagin
a9c6900e26 Merge branch 'RussianLanguage' of https://github.com/Akay7/django-rest-auth into RussianLanguage 2016-11-27 08:05:30 +03:00
Ankit Popli
4599adf92b
fix: social login using auth code flow
'access_token' in attrs always returns True, we need to check whether
the token is empty or not
2016-11-25 20:33:43 +05:30
Maxim Kukhtenkov
667e70c40f Update configs and changelog for version 0.8.2 2016-11-01 11:10:15 -07:00
Maxim Kukhtenkov
a989de8624 Merge pull request #277 from Tivix/demo-site-swagger
Add swagger API docs to demo project
2016-11-01 10:56:14 -07:00
Maxim Kukhtenkov
a907efc06b Allow using custom UserDetailsSerializer with JWTSerializer 2016-10-31 20:45:33 -07:00
Maxim Kukhtenkov
70d03e3e9b Update docstring for UserDetailsView and cleanup 2016-10-31 20:17:31 -07:00
Maxim Kukhtenkov
5330e0cfb1 Add swagger API docs to demo project 2016-10-27 17:42:07 -07:00
Maxim Kukhtenkov
37375461df Add info to docs and comments
+ Add comments by @chubz regarding django-allauth hmac pattern from PR #233
+ Cleanup
2016-10-24 14:23:44 -07:00
Maxim Kukhtenkov
35fe1ae590 Return pk in /rest-auth/user/ instead of id 2016-10-17 10:27:03 -07:00
Maxim Kukhtenkov
e662736e4a Merge pull request #256 from briva/patch-1
Return ID user on /rest-auth/user/
2016-10-17 10:26:22 -07:00
Maxim Kukhtenkov
0472b44241 Merge pull request #273 from Tivix/revert-209-patch-1
Revert "allows registration throttle control"
2016-10-17 10:11:18 -07:00
Maxim Kukhtenkov
83e200e576 Revert "allows registration throttle control" 2016-10-17 10:11:04 -07:00
Le Pogam Brivael
f793447bae Return ID user on /rest-auth/user/ 2016-09-05 12:44:17 +02:00
mario
3b80fcbca9 fix: removed --use-mirrors from pip 2016-08-31 18:09:01 +02:00
mario
4246511fb1 Merge pull request #235 from syamvilakudy/patch-1
Added missing variable "token"
2016-08-31 00:05:32 +02:00
mario
53094041b8 Merge pull request #236 from greenstatic/master
changed login into logout in the templates logout_form.html
2016-08-31 00:01:33 +02:00
mario
8365d729ac Merge pull request #248 from jberends/master
Refactored demo.settings to use TEMPLATE dictionary settings for django
2016-08-31 00:01:01 +02:00
mario
f07429c252 Merge pull request #244 from Akay7/FixImportAllauthError
Fix import allauth error
2016-08-30 23:58:15 +02:00
jberends
8949b1ffde Refactored the settings of the demo to confirm to the use of TEMPLATE_* settings in django. 2016-08-29 14:58:47 +02:00
Poderyagin Egor
2546b17067 fix import allauth error 2016-08-12 10:46:25 +03:00
Egor
5086eebfdb Merge pull request #5 from Tivix/master
Pull updates
2016-08-01 09:00:38 +04:00
Poderyagin Egor
2d54117863 added russian language 2016-08-01 07:51:44 +03:00
greenstatic
abc72e88f0 changed login into logout in the templates logout_form.html 2016-07-29 21:23:52 +02:00
Syam Mohan
acf15b6360 Added missing variable "token" 2016-07-29 18:24:49 +05:30
mario
e9215f4105 Bump to v0.8.1 2016-07-28 22:45:39 +02:00
mariuccio
f9b6a6cd9f 'detail' keyword in success response messages 2016-03-31 10:58:14 +02:00
Egor
1a964f9056 Merge pull request #4 from Akay7/CanLoginWithCustomUserModel
update for accept login users of CustomUserModel objects where doesn'…
2016-02-17 08:46:50 +03:00
Egor
2acf4dd115 Merge pull request #3 from Tivix/master
get new updates
2016-02-16 15:41:33 +03:00
53 changed files with 1875 additions and 296 deletions

77
.gitignore vendored
View File

@ -1,26 +1,35 @@
# Byte-compiled / optimized / DLL files # Byte-compiled / optimized / DLL files
__pycache__/ __pycache__/
*.py[cod] *.py[cod]
*$py.class
# C extensions # C extensions
*.so *.so
# Distribution / packaging # Distribution / packaging
.Python .Python
env/
bin/
build/ build/
develop-eggs/ develop-eggs/
dist/ dist/
downloads/
eggs/ eggs/
.eggs/
lib/ lib/
lib64/ lib64/
parts/ parts/
sdist/ sdist/
var/ var/
wheels/
*.egg-info/ *.egg-info/
.installed.cfg .installed.cfg
*.egg *.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs # Installer logs
pip-log.txt pip-log.txt
@ -30,28 +39,66 @@ pip-delete-this-directory.txt
htmlcov/ htmlcov/
.tox/ .tox/
.coverage .coverage
.coverage.*
.cache .cache
nosetests.xml nosetests.xml
coverage.xml coverage.xml
coverage_html *.cover
.hypothesis/
.pytest_cache/
# Mr Developer # Translations
.mr.developer.cfg *.mo
.project *.pot
.pydevproject
# Rope
.ropeproject
# Django stuff: # Django stuff:
*.log *.log
*.pot local_settings.py
db.sqlite3
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation # Sphinx documentation
docs/_build/ docs/_build/
.DS_Store # PyBuilder
db.sqlite3 target/
# IntelliJ IDE files # Jupyter Notebook
.idea .ipynb_checkpoints
# pyenv
.python-version
# celery beat schedule file
celerybeat-schedule
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/

View File

@ -2,20 +2,25 @@ language: python
python: python:
- "2.7" - "2.7"
- "3.5" - "3.5"
- "3.6"
env: env:
- DJANGO=1.8.13 - DJANGO=1.11.* DRF=3.7.*
- DJANGO=1.9.7 - DJANGO=1.11.* DRF=3.8.*
- DJANGO=2.0.* DRF=3.7.*
- DJANGO=2.0.* DRF=3.8.*
install: install:
- pip install -q Django==$DJANGO --use-mirrors - pip install -q Django==$DJANGO djangorestframework==$DRF
- pip install coveralls - pip install coveralls
- pip install -r rest_auth/tests/requirements.pip - pip install -r rest_auth/tests/requirements.pip
matrix:
exclude:
- python: "3.5"
env: DJANGO=1.8.13
script: script:
- coverage run --source=rest_auth setup.py test - coverage run --source=rest_auth setup.py test
after_success: after_success:
- coveralls - coveralls
before_script: before_script:
- flake8 . --config=flake8 - flake8 . --config=flake8
matrix:
exclude:
- python: "2.7"
env: DJANGO=2.0.* DRF=3.7.*
- python: "2.7"
env: DJANGO=2.0.* DRF=3.8.*

View File

@ -2,3 +2,4 @@ include AUTHORS
include LICENSE include LICENSE
include MANIFEST.in include MANIFEST.in
include README.md include README.md
graft rest_auth

View File

@ -1,11 +1,17 @@
===========
Deprecated
===========
Please use https://github.com/iMerica/dj-rest-auth as this project is no longer maintained. Thanks!
Welcome to django-rest-auth Welcome to django-rest-auth
=========================== ===========================
.. image:: https://travis-ci.org/Tivix/django-rest-auth.png .. image:: https://travis-ci.org/Tivix/django-rest-auth.svg
:target: https://travis-ci.org/Tivix/django-rest-auth :target: https://travis-ci.org/Tivix/django-rest-auth
.. image:: https://coveralls.io/repos/Tivix/django-rest-auth/badge.png .. image:: https://coveralls.io/repos/Tivix/django-rest-auth/badge.svg
:target: https://coveralls.io/r/Tivix/django-rest-auth?branch=master :target: https://coveralls.io/r/Tivix/django-rest-auth?branch=master
@ -28,4 +34,4 @@ https://github.com/Tivix/django-rest-auth
Stack Overflow Stack Overflow
----------- -----------
http://stackoverflow.com/questions/tagged/django-rest-auth http://stackoverflow.com/questions/tagged/django-rest-auth

View File

@ -10,8 +10,8 @@ https://docs.djangoproject.com/en/1.7/ref/settings/
# Build paths inside the project like this: os.path.join(BASE_DIR, ...) # Build paths inside the project like this: os.path.join(BASE_DIR, ...)
import os import os
BASE_DIR = os.path.dirname(os.path.dirname(__file__))
BASE_DIR = os.path.dirname(os.path.dirname(__file__))
# Quick-start development settings - unsuitable for production # Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/1.7/howto/deployment/checklist/ # See https://docs.djangoproject.com/en/1.7/howto/deployment/checklist/
@ -22,19 +22,8 @@ SECRET_KEY = 'ma3c@7uu!%e0=tynp+i6+q%$)9v@$t(eulqurym_b=48z82&5n'
# SECURITY WARNING: don't run with debug turned on in production! # SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True DEBUG = True
TEMPLATE_DEBUG = True
ALLOWED_HOSTS = [] ALLOWED_HOSTS = []
TEMPLATE_CONTEXT_PROCESSORS = (
'django.contrib.auth.context_processors.auth',
"django.core.context_processors.request",
# Disabling due to alluth>=0.21.0 changes
# "allauth.account.context_processors.account",
# "allauth.socialaccount.context_processors.socialaccount",
)
# Application definition # Application definition
INSTALLED_APPS = ( INSTALLED_APPS = (
@ -55,23 +44,25 @@ INSTALLED_APPS = (
'rest_auth.registration', 'rest_auth.registration',
'allauth.socialaccount', 'allauth.socialaccount',
'allauth.socialaccount.providers.facebook', 'allauth.socialaccount.providers.facebook',
'rest_framework_swagger',
) )
MIDDLEWARE_CLASSES = ( MIDDLEWARE = (
'django.contrib.sessions.middleware.SessionMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware', 'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware', 'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware', 'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware',
) )
# For backwards compatibility for Django 1.8
MIDDLEWARE_CLASSES = MIDDLEWARE
ROOT_URLCONF = 'demo.urls' ROOT_URLCONF = 'demo.urls'
WSGI_APPLICATION = 'demo.wsgi.application' WSGI_APPLICATION = 'demo.wsgi.application'
# Database # Database
# https://docs.djangoproject.com/en/1.7/ref/settings/#databases # https://docs.djangoproject.com/en/1.7/ref/settings/#databases
@ -95,15 +86,30 @@ USE_L10N = True
USE_TZ = True USE_TZ = True
# Static files (CSS, JavaScript, Images) # Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.7/howto/static-files/ # https://docs.djangoproject.com/en/1.7/howto/static-files/
STATIC_URL = '/static/' STATIC_URL = '/static/'
TEMPLATE_DIRS = [os.path.join(BASE_DIR, 'templates')] # TEMPLATE_DIRS = [os.path.join(BASE_DIR, 'templates')]
REST_SESSION_LOGIN = False TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates'), ],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
REST_SESSION_LOGIN = True
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend' EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
SITE_ID = 1 SITE_ID = 1
ACCOUNT_EMAIL_REQUIRED = False ACCOUNT_EMAIL_REQUIRED = False
@ -116,3 +122,8 @@ REST_FRAMEWORK = {
'rest_framework.authentication.TokenAuthentication', 'rest_framework.authentication.TokenAuthentication',
) )
} }
SWAGGER_SETTINGS = {
'LOGIN_URL': 'login',
'LOGOUT_URL': 'logout',
}

View File

@ -2,6 +2,8 @@ from django.conf.urls import include, url
from django.contrib import admin from django.contrib import admin
from django.views.generic import TemplateView, RedirectView from django.views.generic import TemplateView, RedirectView
from rest_framework_swagger.views import get_swagger_view
urlpatterns = [ urlpatterns = [
url(r'^$', TemplateView.as_view(template_name="home.html"), name='home'), url(r'^$', TemplateView.as_view(template_name="home.html"), name='home'),
url(r'^signup/$', TemplateView.as_view(template_name="signup.html"), url(r'^signup/$', TemplateView.as_view(template_name="signup.html"),
@ -36,6 +38,7 @@ urlpatterns = [
url(r'^rest-auth/', include('rest_auth.urls')), url(r'^rest-auth/', include('rest_auth.urls')),
url(r'^rest-auth/registration/', include('rest_auth.registration.urls')), url(r'^rest-auth/registration/', include('rest_auth.registration.urls')),
url(r'^account/', include('allauth.urls')), url(r'^account/', include('allauth.urls')),
url(r'^admin/', include(admin.site.urls)), url(r'^admin/', admin.site.urls),
url(r'^accounts/profile/$', RedirectView.as_view(url='/', permanent=True), name='profile-redirect'), url(r'^accounts/profile/$', RedirectView.as_view(url='/', permanent=True), name='profile-redirect'),
url(r'^docs/$', get_swagger_view(title='API Docs'), name='api_docs')
] ]

View File

@ -1,4 +1,6 @@
django>=1.8.0 django>=1.9.0
django-rest-auth==0.8.0 django-rest-auth==0.9.5
djangorestframework>=3.7.0
django-allauth>=0.24.1 django-allauth>=0.24.1
six==1.9.0 six==1.9.0
django-rest-swagger==2.0.7

View File

@ -7,7 +7,7 @@
<meta name="description" content="Django-rest-auth demo"> <meta name="description" content="Django-rest-auth demo">
<meta name="author" content="Tivix, Inc."> <meta name="author" content="Tivix, Inc.">
<title>Starter Template for Bootstrap</title> <title>django-rest-auth demo</title>
<!-- Latest compiled and minified CSS --> <!-- Latest compiled and minified CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css"> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
@ -60,6 +60,7 @@
<li class="active"><a href="/">Demo</a></li> <li class="active"><a href="/">Demo</a></li>
<li><a target="_blank" href="http://django-rest-auth.readthedocs.org/en/latest/">Documentation</a></li> <li><a target="_blank" href="http://django-rest-auth.readthedocs.org/en/latest/">Documentation</a></li>
<li><a target="_blank" href="https://github.com/Tivix/django-rest-auth">Source code</a></li> <li><a target="_blank" href="https://github.com/Tivix/django-rest-auth">Source code</a></li>
<li><a target="_blank" href="{% url 'api_docs' %}">API Docs</a></li>
</ul> </ul>
</div><!--/.nav-collapse --> </div><!--/.nav-collapse -->
</div> </div>

View File

@ -11,7 +11,7 @@
<div class="form-group"> <div class="form-group">
<div class="col-sm-offset-2 col-sm-10"> <div class="col-sm-offset-2 col-sm-10">
<button type="submit" class="btn btn-default">Login</button> <button type="submit" class="btn btn-default">Logout</button>
</div> </div>
</div> </div>

4
dev-requirements.txt Normal file
View File

@ -0,0 +1,4 @@
--editable .
responses>=0.5.0
djangorestframework-jwt
django-allauth

View File

@ -6,16 +6,15 @@ Basic
- /rest-auth/login/ (POST) - /rest-auth/login/ (POST)
- username (string) - username
- email (string) - email
- password (string) - password
Returns Token key
- /rest-auth/logout/ (POST, GET) - /rest-auth/logout/ (POST)
.. note:: ``ACCOUNT_LOGOUT_ON_GET = True`` to allow logout using GET (this is the exact same conf from allauth) .. note:: ``ACCOUNT_LOGOUT_ON_GET = True`` to allow logout using GET - this is the exact same configuration from allauth. NOT recommended, see: http://django-allauth.readthedocs.io/en/latest/views.html#logout
- token
- /rest-auth/password/reset/ (POST) - /rest-auth/password/reset/ (POST)
@ -36,18 +35,16 @@ Basic
- new_password2 - new_password2
- old_password - old_password
.. note:: ``OLD_PASSWORD_FIELD_ENABLED = True`` to use old_password. .. note:: ``OLD_PASSWORD_FIELD_ENABLED = True`` to use old_password.
.. note:: ``LOGOUT_ON_PASSWORD_CHANGE = False`` to keep the user logged in after password change .. note:: ``LOGOUT_ON_PASSWORD_CHANGE = False`` to keep the user logged in after password change
- /rest-auth/user/ (GET) - /rest-auth/user/ (GET, PUT, PATCH)
- /rest-auth/user/ (PUT/PATCH)
- username - username
- first_name - first_name
- last_name - last_name
- email
Returns pk, username, email, first_name, last_name
Registration Registration
@ -75,6 +72,8 @@ Basing on example from installation section :doc:`Installation </installation>`
- access_token - access_token
- code - code
.. note:: ``access_token`` OR ``code`` can be used as standalone arguments, see https://github.com/Tivix/django-rest-auth/blob/master/rest_auth/registration/views.py
- /rest-auth/twitter/ (POST) - /rest-auth/twitter/ (POST)
- access_token - access_token

View File

@ -1,6 +1,54 @@
Changelog Changelog
========= =========
0.9.5
-----
- fixed package distribution issue
0.9.4
-----
- Compatibility fixes (#437, #506)
- JWT auth cookie fix (#345)
- config & packaging fixes
- updated docs
- added new translations (Czech, Chinese, Turkish, Korean)
0.9.3
-----
- added social connect views
- added check for pre-existing accounts in social login
- prevent double-validation in LoginSerializer
- unit tests and demo project changes for Django 2.0
0.9.2
-----
- added permission classes configuration for registration
- added more info to JWT docs
- added Polish translations
0.9.1
-----
- fixed import error when extending rest_auth serializers
- added sensitive fields decorator
- added Spanish translations
0.9.0
-----
- allowed using custom UserDetailsSerializer with JWTSerializer
- fixed error with logout on GET
- updated api endpoints and configuration docs
- bugfixes
- minor text fixes
0.8.2
-----
- fixed allauth import error
- added swagger docs to demo project
0.8.1
-----
- added support for django-allauth hmac email confirmation pattern
0.8.0 0.8.0
----- -----
- added support for django-rest-framework-jwt - added support for django-rest-framework-jwt

View File

@ -44,16 +44,16 @@ master_doc = 'index'
# General information about the project. # General information about the project.
project = u'django-rest-auth' project = u'django-rest-auth'
copyright = u'2014, Tivix Inc.' copyright = u'2018, Tivix Inc.'
# The version info for the project you're documenting, acts as replacement for # The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the # |version| and |release|, also used in various other places throughout the
# built documents. # built documents.
# #
# The short X.Y version. # The short X.Y version.
version = '0.3.0' version = '0.9.5'
# The full version, including alpha/beta/rc tags. # The full version, including alpha/beta/rc tags.
release = '0.3.0' release = '0.9.5'
# The language for content autogenerated by Sphinx. Refer to documentation # The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages. # for a list of supported languages.

View File

@ -36,7 +36,9 @@ Configuration
You can define your custom serializers for registration endpoint. You can define your custom serializers for registration endpoint.
Possible key values: Possible key values:
- REGISTER_SERIALIZER - serializer class in ``rest_auth.register.views.RegisterView``, default value ``rest_auth.registration.serializers.RegisterSerializer`` - REGISTER_SERIALIZER - serializer class in ``rest_auth.registration.views.RegisterView``, default value ``rest_auth.registration.serializers.RegisterSerializer``
.. note:: The custom REGISTER_SERIALIZER must define a ``def save(self, request)`` method that returns a user model instance
- **REST_AUTH_TOKEN_MODEL** - model class for tokens, default value ``rest_framework.authtoken.models`` - **REST_AUTH_TOKEN_MODEL** - model class for tokens, default value ``rest_framework.authtoken.models``
@ -49,20 +51,3 @@ Configuration
- **OLD_PASSWORD_FIELD_ENABLED** - set it to True if you want to have old password verification on password change enpoint (default: False) - **OLD_PASSWORD_FIELD_ENABLED** - set it to True if you want to have old password verification on password change enpoint (default: False)
- **LOGOUT_ON_PASSWORD_CHANGE** - set to False if you want to keep the current user logged in after a password change - **LOGOUT_ON_PASSWORD_CHANGE** - set to False if you want to keep the current user logged in after a password change
Throttling
=============
You may specify custom throttling for ``rest_auth.register.views.RegisterView`` by specifying DRF settings:
.. code-block:: python
REST_FRAMEWORK = {
'DEFAULT_THROTTLE_RATES': {
'anon': '6/m',
'register_view':'1/h',
},
}

View File

@ -7,14 +7,14 @@ FAQ
.. code-block:: python .. code-block:: python
url(r'^account-confirm-email/(?P<key>\w+)/$', TemplateView.as_view(), url(r'^account-confirm-email/(?P<key>[-:\w]+)/$', TemplateView.as_view(),
name='account_confirm_email'), name='account_confirm_email'),
This url is used by django-allauth. Empty TemplateView is defined just to allow reverse() call inside app - when email with verification link is being sent. This url is used by django-allauth. Empty TemplateView is defined just to allow reverse() call inside app - when email with verification link is being sent.
You should override this view/url to handle it in your API client somehow and then, send post to /verify-email/ endpoint with proper key. You should override this view/url to handle it in your API client somehow and then, send post to /verify-email/ endpoint with proper key.
If you don't want to use API on that step, then just use ConfirmEmailView view from: If you don't want to use API on that step, then just use ConfirmEmailView view from:
djang-allauth https://github.com/pennersr/django-allauth/blob/master/allauth/account/views.py#L190 django-allauth https://github.com/pennersr/django-allauth/blob/master/allauth/account/views.py
2. I get an error: Reverse for 'password_reset_confirm' not found. 2. I get an error: Reverse for 'password_reset_confirm' not found.

View File

@ -26,12 +26,18 @@ Installation
.. code-block:: python .. code-block:: python
urlpatterns = patterns('', urlpatterns = [
..., ...,
url(r'^rest-auth/', include('rest_auth.urls')) url(r'^rest-auth/', include('rest_auth.urls'))
) ]
4. Migrate your database
.. code-block:: python
python manage.py migrate
You're good to go now! You're good to go now!
@ -60,11 +66,11 @@ Registration (optional)
.. code-block:: python .. code-block:: python
urlpatterns = patterns('', urlpatterns = [
..., ...,
url(r'^rest-auth/', include('rest_auth.urls')), url(r'^rest-auth/', include('rest_auth.urls')),
url(r'^rest-auth/registration/', include('rest_auth.registration.urls')) url(r'^rest-auth/registration/', include('rest_auth.registration.urls'))
) ]
Social Authentication (optional) Social Authentication (optional)
@ -114,10 +120,10 @@ Facebook
.. code-block:: python .. code-block:: python
urlpatterns += patterns('', urlpatterns += [
..., ...,
url(r'^rest-auth/facebook/$', FacebookLogin.as_view(), name='fb_login') url(r'^rest-auth/facebook/$', FacebookLogin.as_view(), name='fb_login')
) ]
Twitter Twitter
@ -125,15 +131,15 @@ Twitter
If you are using Twitter for your social authentication, it is a bit different since Twitter uses OAuth 1.0. If you are using Twitter for your social authentication, it is a bit different since Twitter uses OAuth 1.0.
3. Create new view as a subclass of ``rest_auth.views.LoginView`` with ``TwitterOAuthAdapter`` adapter and ``TwitterLoginSerializer`` as an attribute: 3. Create new view as a subclass of ``rest_auth.registration.views.SocialLoginView`` with ``TwitterOAuthAdapter`` adapter and ``TwitterLoginSerializer`` as an attribute:
.. code-block:: python .. code-block:: python
from allauth.socialaccount.providers.twitter.views import TwitterOAuthAdapter from allauth.socialaccount.providers.twitter.views import TwitterOAuthAdapter
from rest_auth.views import LoginView from rest_auth.registration.views import SocialLoginView
from rest_auth.social_serializers import TwitterLoginSerializer from rest_auth.social_serializers import TwitterLoginSerializer
class TwitterLogin(LoginView): class TwitterLogin(SocialLoginView):
serializer_class = TwitterLoginSerializer serializer_class = TwitterLoginSerializer
adapter_class = TwitterOAuthAdapter adapter_class = TwitterOAuthAdapter
@ -141,23 +147,114 @@ If you are using Twitter for your social authentication, it is a bit different s
.. code-block:: python .. code-block:: python
urlpatterns += patterns('', urlpatterns += [
..., ...,
url(r'^rest-auth/twitter/$', TwitterLogin.as_view(), name='twitter_login') url(r'^rest-auth/twitter/$', TwitterLogin.as_view(), name='twitter_login')
) ]
.. note:: Starting from v0.21.0, django-allauth has dropped support for context processors. Check out http://django-allauth.readthedocs.org/en/latest/changelog.html#from-0-21-0 for more details. .. note:: Starting from v0.21.0, django-allauth has dropped support for context processors. Check out http://django-allauth.readthedocs.org/en/latest/changelog.html#from-0-21-0 for more details.
JWT Support (optional) GitHub
---------------------- ######
By default, ``django-rest-auth`` uses Django's Token-based authentication. If you want to use JWT authentication, you need to install the following: If you are using GitHub for your social authentication, it uses code and not AccessToken directly.
1. Install ``django-rest-framework-jwt`` http://getblimp.github.io/django-rest-framework-jwt/ . Right now this is the only supported JWT library. 3. Create new view as a subclass of ``rest_auth.views.SocialLoginView`` with ``GitHubOAuth2Adapter`` adapter, an ``OAuth2Client`` and a callback_url as attributes:
2. Add the following to your settings .. code-block:: python
from allauth.socialaccount.providers.github.views import GitHubOAuth2Adapter
from allauth.socialaccount.providers.oauth2.client import OAuth2Client
from rest_auth.registration.views import SocialLoginView
class GithubLogin(SocialLoginView):
adapter_class = GitHubOAuth2Adapter
callback_url = CALLBACK_URL_YOU_SET_ON_GITHUB
client_class = OAuth2Client
4. Create url for GitHubLogin view:
.. code-block:: python
urlpatterns += [
...,
url(r'^rest-auth/github/$', GitHubLogin.as_view(), name='github_login')
]
Additional Social Connect Views
###############################
If you want to allow connecting existing accounts in addition to login, you can use connect views:
.. code-block:: python
from allauth.socialaccount.providers.facebook.views import FacebookOAuth2Adapter
from allauth.socialaccount.providers.github.views import GitHubOAuth2Adapter
from allauth.socialaccount.providers.twitter.views import TwitterOAuthAdapter
from allauth.socialaccount.providers.oauth2.client import OAuth2Client
from rest_auth.registration.views import SocialConnectView
from rest_auth.social_serializers import TwitterConnectSerializer
class FacebookConnect(SocialConnectView):
adapter_class = FacebookOAuth2Adapter
class TwitterConnect(SocialConnectView):
serializer_class = TwitterConnectSerializer
adapter_class = TwitterOAuthAdapter
class GithubConnect(SocialConnectView):
adapter_class = GitHubOAuth2Adapter
callback_url = CALLBACK_URL_YOU_SET_ON_GITHUB
client_class = OAuth2Client
In urls.py:
.. code-block:: python
urlpatterns += [
...,
url(r'^rest-auth/facebook/connect/$', FacebookConnect.as_view(), name='fb_connect')
url(r'^rest-auth/twitter/connect/$', TwitterConnect.as_view(), name='twitter_connect')
url(r'^rest-auth/github/connect/$', GithubConnect.as_view(), name='github_connect')
]
You can also use the following views to check all social accounts attached to the current authenticated user and disconnect selected social accounts:
.. code-block:: python
from rest_auth.registration.views import (
SocialAccountListView, SocialAccountDisconnectView
)
urlpatterns += [
...,
url(
r'^socialaccounts/$',
SocialAccountListView.as_view(),
name='social_account_list'
),
url(
r'^socialaccounts/(?P<pk>\d+)/disconnect/$',
SocialAccountDisconnectView.as_view(),
name='social_account_disconnect'
)
]
JSON Web Token (JWT) Support (optional)
---------------------------------------
By default ``django-rest-auth`` uses Django's Token-based authentication. If you want to use JWT authentication, follow these steps:
1. Install `djangorestframework-jwt <http://getblimp.github.io/django-rest-framework-jwt/>`_
- ``djangorestframework-jwt`` is currently the only supported JWT library.
2. The ``JWT_PAYLOAD_HANDLER`` and ``JWT_ENCODE_HANDLER`` settings are imported from the ``django-rest-framework-jwt`` settings object.
- Refer to `the library's documentation <http://getblimp.github.io/django-rest-framework-jwt/#additional-settings>`_ for information on using different encoders.
3. Add the following configuration value to your settings file to enable JWT authentication.
.. code-block:: python .. code-block:: python
REST_USE_JWT = True REST_USE_JWT = True

4
flake8
View File

@ -1,4 +0,0 @@
[flake8]
max-line-length = 160
exclude = docs/*,demo/*
ignore = F403

Binary file not shown.

View File

@ -0,0 +1,102 @@
# Czech translations of Tivix/django-rest-auth
#
# This file is distributed under the same license as the Tivix/django-rest-auth package.
#
msgid ""
msgstr ""
"Project-Id-Version: Tivix/django-rest-auth\n"
"Report-Msgid-Bugs-To: https://github.com/Tivix/django-rest-auth/issues\n"
"POT-Creation-Date: 2018-06-27 23:05+0200\n"
"PO-Revision-Date: 2018-06-27 23:22+0200\n"
"Language: cs\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n"
"Last-Translator: Václav Dohnal <vaclav.dohnal@gmail.com>\n"
"Language-Team: N/A\n"
"X-Generator: Poedit 2.0.8\n"
#: .\registration\serializers.py:67
msgid "View is not defined, pass it as a context variable"
msgstr "View není definováno, předejte jej jako proměnnou kontextu"
#: .\registration\serializers.py:72
msgid "Define adapter_class in view"
msgstr "Definujte adapter_class ve view"
#: .\registration\serializers.py:91
msgid "Define callback_url in view"
msgstr "Definujte callback_url ve view"
#: .\registration\serializers.py:95
msgid "Define client_class in view"
msgstr "Definujte client_class ve view"
#: .\registration\serializers.py:116
msgid "Incorrect input. access_token or code is required."
msgstr "Nesprávný vstup. access_token je povinný."
#: .\registration\serializers.py:125
msgid "Incorrect value"
msgstr "Nesprávná hodnota"
#: .\registration\serializers.py:139
msgid "User is already registered with this e-mail address."
msgstr "Uživatel s touto adresou je již registrován."
#: .\registration\serializers.py:185
msgid "A user is already registered with this e-mail address."
msgstr "Uživatel s touto adresou je již registrován."
#: .\registration\serializers.py:193
msgid "The two password fields didn't match."
msgstr "Zadaná hesla se neshodují."
#: .\registration\views.py:51
msgid "Verification e-mail sent."
msgstr "Ověřovací e-mail odeslán."
#: .\registration\views.py:98
msgid "ok"
msgstr "ok"
#: .\serializers.py:30
msgid "Must include \"email\" and \"password\"."
msgstr "Musí obsahovat \"e-mail\" a \"heslo\"."
#: .\serializers.py:41
msgid "Must include \"username\" and \"password\"."
msgstr "Musí obsahovat \"uživatelské jméno\" a \"heslo\"."
#: .\serializers.py:54
msgid "Must include either \"username\" or \"email\" and \"password\"."
msgstr "Musí obsahovat \"uživatelské jméno\" nebo \"e-mail\" a \"heslo\"."
#: .\serializers.py:95
msgid "User account is disabled."
msgstr "Uživatelský účet je zakázán."
#: .\serializers.py:98
msgid "Unable to log in with provided credentials."
msgstr "Pomocí zadaných údajů se nelze přihlásit."
#: .\serializers.py:107
msgid "E-mail is not verified."
msgstr "E-mail není ověřený."
#: .\views.py:127
msgid "Successfully logged out."
msgstr "Byli jste úspěšně odhlášeni."
#: .\views.py:175
msgid "Password reset e-mail has been sent."
msgstr "E-mail pro resetování hesla byl odeslán."
#: .\views.py:201
msgid "Password has been reset with the new password."
msgstr "Vaše heslo bylo resetováno."
#: .\views.py:223
msgid "New password has been saved."
msgstr "Nové heslo bylo uloženo."

View File

@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-02-02 14:11+0100\n" "POT-Creation-Date: 2017-03-05 21:56-0800\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
@ -18,19 +18,19 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: registration/serializers.py:54 #: registration/serializers.py:53
msgid "View is not defined, pass it as a context variable" msgid "View is not defined, pass it as a context variable"
msgstr "\"View\" ist nicht definiert, übergib es als Contextvariable" msgstr "\"View\" ist nicht definiert, übergib es als Contextvariable"
#: registration/serializers.py:59 #: registration/serializers.py:58
msgid "Define adapter_class in view" msgid "Define adapter_class in view"
msgstr "Definier \"adapter_class\" in view" msgstr "Definier \"adapter_class\" in view"
#: registration/serializers.py:78 #: registration/serializers.py:77
msgid "Define callback_url in view" msgid "Define callback_url in view"
msgstr "Definier \"callback_url\" in view" msgstr "Definier \"callback_url\" in view"
#: registration/serializers.py:82 #: registration/serializers.py:81
msgid "Define client_class in view" msgid "Define client_class in view"
msgstr "Definier \"client_class\" in view" msgstr "Definier \"client_class\" in view"
@ -50,50 +50,49 @@ msgstr "Ein User mit dieser E-Mail Adresse ist schon registriert."
msgid "The two password fields didn't match." msgid "The two password fields didn't match."
msgstr "Die beiden Passwörter sind nicht identisch." msgstr "Die beiden Passwörter sind nicht identisch."
#: registration/views.py:64 #: registration/views.py:91
msgid "ok" msgid "ok"
msgstr "Ok" msgstr "Ok"
#: serializers.py:29 #: serializers.py:30
msgid "Must include \"email\" and \"password\"." msgid "Must include \"email\" and \"password\"."
msgstr "Muss \"email\" und \"password\" enthalten." msgstr "Muss \"email\" und \"password\" enthalten."
#: serializers.py:40 #: serializers.py:41
msgid "Must include \"username\" and \"password\"." msgid "Must include \"username\" and \"password\"."
msgstr "Muss \"username\" und \"password\" enthalten." msgstr "Muss \"username\" und \"password\" enthalten."
#: serializers.py:53 #: serializers.py:54
msgid "Must include either \"username\" or \"email\" and \"password\"." msgid "Must include either \"username\" or \"email\" and \"password\"."
msgstr "Muss entweder \"username\" oder \"email\" und password \"password\"" msgstr "Muss entweder \"username\" oder \"email\" und password \"password\""
#: serializers.py:94 #: serializers.py:95
msgid "User account is disabled." msgid "User account is disabled."
msgstr "Der Useraccount ist deaktiviert." msgstr "Der Useraccount ist deaktiviert."
#: serializers.py:97 #: serializers.py:98
msgid "Unable to log in with provided credentials." msgid "Unable to log in with provided credentials."
msgstr "Kann nicht mit den angegeben Zugangsdaten anmelden." msgstr "Kann nicht mit den angegeben Zugangsdaten anmelden."
#: serializers.py:106 #: serializers.py:107
msgid "E-mail is not verified." msgid "E-mail is not verified."
msgstr "E-Mail Adresse ist nicht verifiziert." msgstr "E-Mail Adresse ist nicht verifiziert."
#: serializers.py:152 #: views.py:126
msgid "Error"
msgstr "Fehler"
#: views.py:71
msgid "Successfully logged out." msgid "Successfully logged out."
msgstr "Erfolgreich ausgeloggt." msgstr "Erfolgreich ausgeloggt."
#: views.py:111 #: views.py:174
msgid "Password reset e-mail has been sent." msgid "Password reset e-mail has been sent."
msgstr "Die E-Mail zum Zurücksetzen des Passwortes wurde verschickt." msgstr "Die E-Mail zum Zurücksetzen des Passwortes wurde verschickt."
#: views.py:132 #: views.py:200
msgid "Password has been reset with the new password." msgid "Password has been reset with the new password."
msgstr "Das Passwort wurde mit dem neuen Passwort ersetzt." msgstr "Das Passwort wurde mit dem neuen Passwort ersetzt."
#: views.py:150 #: views.py:222
msgid "New password has been saved." msgid "New password has been saved."
msgstr "Das neue Passwort wurde gespeichert." msgstr "Das neue Passwort wurde gespeichert."
#~ msgid "Error"
#~ msgstr "Fehler"

Binary file not shown.

View File

@ -0,0 +1,99 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-03-05 21:56-0800\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: Carlos de las Heras <cahersan@gmail.com>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: registration/serializers.py:53
msgid "View is not defined, pass it as a context variable"
msgstr "\"View\" no está definida, pásala como una variable de contexto"
#: registration/serializers.py:58
msgid "Define adapter_class in view"
msgstr "Defina \"adapter_class\" en view"
#: registration/serializers.py:77
msgid "Define callback_url in view"
msgstr "Defina \"callback_url\" en view"
#: registration/serializers.py:81
msgid "Define client_class in view"
msgstr "Defina \"client_class\" en view"
#: registration/serializers.py:102
msgid "Incorrect input. access_token or code is required."
msgstr "Entrada incorrecta. Se requiere \"access_token\" o \"code\"."
#: registration/serializers.py:111
msgid "Incorrect value"
msgstr "Valor incorrecto"
#: registration/serializers.py:140
msgid "A user is already registered with this e-mail address."
msgstr "Ya existe un usuario registrado con esa dirección de correo electrónico."
#: registration/serializers.py:148
msgid "The two password fields didn't match."
msgstr "Las contraseñas no coinciden"
#: registration/views.py:44
msgid "Verification e-mail sent."
msgstr "Se ha enviado un correo de verificación."
#: registration/views.py:91
msgid "ok"
msgstr "Ok"
#: serializers.py:30
msgid "Must include \"email\" and \"password\"."
msgstr "Debe incluir \"correo electrónico\" y \"contraseña\"."
#: serializers.py:41
msgid "Must include \"username\" and \"password\"."
msgstr "Debe incluir \"nombre de usuario\" y \"contraseña\"."
#: serializers.py:54
msgid "Must include either \"username\" or \"email\" and \"password\"."
msgstr "Debe incluir \"nombre de usuario\" o \"correo electrónico\" y \"contraseña\"."
#: serializers.py:95
msgid "User account is disabled."
msgstr "Cuenta de usuario deshabilitada"
#: serializers.py:98
msgid "Unable to log in with provided credentials."
msgstr "No puede iniciar sesión con las credenciales proporcionadas."
#: serializers.py:107
msgid "E-mail is not verified."
msgstr "El correo electrónico no ha sido verificado."
#: views.py:126
msgid "Successfully logged out."
msgstr "Sesión cerrada con éxito."
#: views.py:174
msgid "Password reset e-mail has been sent."
msgstr "Se ha enviado un correo electrónico para restablecer la contraseña."
#: views.py:200
msgid "Password has been reset with the new password."
msgstr "La contraseña ha sido restablecida con la nueva contraseña."
#: views.py:222
msgid "New password has been saved."
msgstr "La nueva contraseña ha sido guardada."

Binary file not shown.

View File

@ -0,0 +1,98 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-12-22 11:37-0800\n"
"PO-Revision-Date: 2017-02-14 13:27+0100\n"
"Language: fr\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"Last-Translator: \n"
"Language-Team: \n"
"X-Generator: Poedit 1.8.11\n"
#: registration/serializers.py:53
msgid "View is not defined, pass it as a context variable"
msgstr "La “View” nest pas définie, passez la en variable contextuelle"
#: registration/serializers.py:58
msgid "Define adapter_class in view"
msgstr "Définissez “adapter_class” dans la vue"
#: registration/serializers.py:77
msgid "Define callback_url in view"
msgstr "Définissez “callback_url” dans la vue"
#: registration/serializers.py:81
msgid "Define client_class in view"
msgstr "Définissez “client_class” dans la vue"
#: registration/serializers.py:102
msgid "Incorrect input. access_token or code is required."
msgstr "Paramètres incorrects. Il faut “access_token” ou “code”."
#: registration/serializers.py:111
msgid "Incorrect value"
msgstr "Paramètre incorrect"
#: registration/serializers.py:140
msgid "A user is already registered with this e-mail address."
msgstr "Un utilisateur existe déjà avec cette adresse email."
#: registration/serializers.py:148
msgid "The two password fields didn't match."
msgstr "Les deux mots de passes ne sont pas les mêmes."
#: registration/views.py:82
msgid "ok"
msgstr "Ok"
#: serializers.py:30
msgid "Must include \"email\" and \"password\"."
msgstr "Doit inclure “email” et “password”."
#: serializers.py:41
msgid "Must include \"username\" and \"password\"."
msgstr "Doit inclure “username” et “password”."
#: serializers.py:54
msgid "Must include either \"username\" or \"email\" and \"password\"."
msgstr "Doit inclure un “username” ou “email”, et un “password”."
#: serializers.py:95
msgid "User account is disabled."
msgstr "Le compte utilisateur est désactivé."
#: serializers.py:98
msgid "Unable to log in with provided credentials."
msgstr "Connexion impossible avec les informations fournies."
#: serializers.py:107
msgid "E-mail is not verified."
msgstr "Ladresse email na pas été vérifiée."
#: views.py:114
msgid "Successfully logged out."
msgstr "Déconnexion effectuée avec succès."
#: views.py:162
msgid "Password reset e-mail has been sent."
msgstr "Lemail de réinitialisation du mot de passe a été envoyé."
#: views.py:184
msgid "Password has been reset with the new password."
msgstr "Le mot de passe a été réinitialisé."
#: views.py:202
msgid "New password has been saved."
msgstr "Le nouveau mot de passe est sauvé."
#~ msgid "Error"
#~ msgstr "Fehler"

Binary file not shown.

View File

@ -0,0 +1,99 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-03-05 21:56-0800\n"
"PO-Revision-Date: 2018-03-20 17:52+0900\n"
"Last-Translator: Jeonsgoo Park <toracle@gmail.com>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: ko\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: registration/serializers.py:53
msgid "View is not defined, pass it as a context variable"
msgstr "View가 정의되지 않았습니다. 컨텍스트 변수에 포함해주세요"
#: registration/serializers.py:58
msgid "Define adapter_class in view"
msgstr "view에 adapter_class를 정의하세요"
#: registration/serializers.py:77
msgid "Define callback_url in view"
msgstr "view에 callback_url을 정의하세요"
#: registration/serializers.py:81
msgid "Define client_class in view"
msgstr "view에 client_class를 정의하세요"
#: registration/serializers.py:102
msgid "Incorrect input. access_token or code is required."
msgstr "올바르지 않은 입력입니다. access_token이나 code가 필요합니다."
#: registration/serializers.py:111
msgid "Incorrect value"
msgstr "올바르지 않은 값"
#: registration/serializers.py:140
msgid "A user is already registered with this e-mail address."
msgstr "이미 이 이메일 주소로 등록된 사용자가 있습니다."
#: registration/serializers.py:148
msgid "The two password fields didn't match."
msgstr "두 개의 패스워드 필드가 서로 맞지 않습니다."
#: registration/views.py:44
msgid "Verification e-mail sent."
msgstr "확인 이메일을 발송했습니다."
#: registration/views.py:91
msgid "ok"
msgstr "ok"
#: serializers.py:30
msgid "Must include \"email\" and \"password\"."
msgstr "\"email\"과 \"password\"를 반드시 포함해야 합니다."
#: serializers.py:41
msgid "Must include \"username\" and \"password\"."
msgstr "\"username\"과 \"password\"를 반드시 포함해야 합니다."
#: serializers.py:54
msgid "Must include either \"username\" or \"email\" and \"password\"."
msgstr "\"username\"이나 \"email\", 그리고 \"password\"를 반드시 포함해야 합니다."
#: serializers.py:95
msgid "User account is disabled."
msgstr "사용자 계정이 비활성화 되어있습니다."
#: serializers.py:98
msgid "Unable to log in with provided credentials."
msgstr "주어진 자격 증명으로 로그인이 불가능합니다."
#: serializers.py:107
msgid "E-mail is not verified."
msgstr "이메일 주소가 확인되지 않았습니다."
#: views.py:126
msgid "Successfully logged out."
msgstr "로그아웃되었습니다."
#: views.py:174
msgid "Password reset e-mail has been sent."
msgstr "패스워드 초기화 이메일이 발송되었습니다."
#: views.py:200
msgid "Password has been reset with the new password."
msgstr "새로운 패스워드로 패스워드가 초기화 되었습니다."
#: views.py:222
msgid "New password has been saved."
msgstr "새로운 패스워드가 저장되었습니다."

Binary file not shown.

View File

@ -0,0 +1,99 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-03-05 21:56-0800\n"
"PO-Revision-Date: 2017-03-11 12:10+0100\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
"Language-Team: \n"
"X-Generator: Poedit 1.8.11\n"
"Last-Translator: \n"
"Language: pl\n"
#: registration/serializers.py:53
msgid "View is not defined, pass it as a context variable"
msgstr "Widok nie został zdefiniowany, przekaż go przez zmienną \"context\""
#: registration/serializers.py:58
msgid "Define adapter_class in view"
msgstr "Zdefiniuj \"adapter_class\" w widoku"
#: registration/serializers.py:77
msgid "Define callback_url in view"
msgstr "Zdefiniuj \"callback_url\" w widoku"
#: registration/serializers.py:81
msgid "Define client_class in view"
msgstr "Zdefiniuj \"client_class\" w widoku"
#: registration/serializers.py:102
msgid "Incorrect input. access_token or code is required."
msgstr "Podano błędne dane. \"access_token\" lub \"code\" są wymagne."
#: registration/serializers.py:111
msgid "Incorrect value"
msgstr "Niepoprawna wartość."
#: registration/serializers.py:140
msgid "A user is already registered with this e-mail address."
msgstr "Istnieje już użytkownik z takim adresem email."
#: registration/serializers.py:148
msgid "The two password fields didn't match."
msgstr "Hasła nie są identyczne."
#: registration/views.py:44
msgid "Verification e-mail sent."
msgstr "Email weryfikacyjny został wysłany."
#: registration/views.py:91
msgid "ok"
msgstr "ok"
#: serializers.py:30
msgid "Must include \"email\" and \"password\"."
msgstr "Musisz podać email i hasło."
#: serializers.py:41
msgid "Must include \"username\" and \"password\"."
msgstr "Musisz podać nazwę użytkownika i hasło."
#: serializers.py:54
msgid "Must include either \"username\" or \"email\" and \"password\"."
msgstr "Musisz podać nazwę użytkownika (lub email) i hasło."
#: serializers.py:95
msgid "User account is disabled."
msgstr "Konto użytkownika zostało wyłączone."
#: serializers.py:98
msgid "Unable to log in with provided credentials."
msgstr "Podane dane do logowania są niepoprawne."
#: serializers.py:107
msgid "E-mail is not verified."
msgstr "Email nie został zweryfikowany."
#: views.py:126
msgid "Successfully logged out."
msgstr "Wylogowano."
#: views.py:174
msgid "Password reset e-mail has been sent."
msgstr "Email z linkiem do resetu hasła został wysłany."
#: views.py:200
msgid "Password has been reset with the new password."
msgstr "Hasło zostało zresetowane."
#: views.py:222
msgid "New password has been saved."
msgstr "Nowe hasło zostało zapisane."

View File

@ -0,0 +1,99 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# Bruno Barreto Freitas <brunobarretofreitas@outlook.com>, 2019.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2019-04-16 09:48-0800\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: Bruno Barreto Freitas <brunobarretofreitas@outlook.com>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: registration/serializers.py:53
msgid "View is not defined, pass it as a context variable"
msgstr "\"View\" não está definida, passe-a como uma variável de contexto"
#: registration/serializers.py:58
msgid "Define adapter_class in view"
msgstr "Defina \"adapter_class\" na view"
#: registration/serializers.py:77
msgid "Define callback_url in view"
msgstr "Defina \"callback_url\" na view"
#: registration/serializers.py:81
msgid "Define client_class in view"
msgstr "Defina \"client_class\" na view"
#: registration/serializers.py:102
msgid "Incorrect input. access_token or code is required."
msgstr "Entrada incorreta. \"access_token\" ou \"code\" são obrigatórios."
#: registration/serializers.py:111
msgid "Incorrect value"
msgstr "Valor incorreto"
#: registration/serializers.py:140
msgid "A user is already registered with this e-mail address."
msgstr "Já existe um usuário cadastrado com este endereço de e-mail."
#: registration/serializers.py:148
msgid "The two password fields didn't match."
msgstr "Os dois campos de senha não correspondem."
#: registration/views.py:44
msgid "Verification e-mail sent."
msgstr "E-mail de verificação enviado."
#: registration/views.py:91
msgid "ok"
msgstr "Ok"
#: serializers.py:30
msgid "Must include \"email\" and \"password\"."
msgstr "Deve-se incluir \"email\" e \"password\"."
#: serializers.py:41
msgid "Must include \"username\" and \"password\"."
msgstr "Deve-se incluir \"username\" e \"password\"."
#: serializers.py:54
msgid "Must include either \"username\" or \"email\" and \"password\"."
msgstr "Deve-se incluir \"username\" ou \"email\" e \"password\"."
#: serializers.py:95
msgid "User account is disabled."
msgstr "Conta de usuário está desativada"
#: serializers.py:98
msgid "Unable to log in with provided credentials."
msgstr "Não foi possível realizar o login com as credenciais fornecidas."
#: serializers.py:107
msgid "E-mail is not verified."
msgstr "E-mail não foi verificado."
#: views.py:126
msgid "Successfully logged out."
msgstr "Logout realizado com sucesso."
#: views.py:174
msgid "Password reset e-mail has been sent."
msgstr "E-mail de redefinição de senha foi enviado."
#: views.py:200
msgid "Password has been reset with the new password."
msgstr "Senha foi redefinida com a nova senha."
#: views.py:222
msgid "New password has been saved."
msgstr "Nova senha foi salva com sucesso."

Binary file not shown.

View File

@ -0,0 +1,101 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-03-05 21:56-0800\n"
"PO-Revision-Date: 2016-08-01 07:48+0300\n"
"Last-Translator: \n"
"Language-Team: \n"
"Language: ru\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
"%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n"
"%100>=11 && n%100<=14)? 2 : 3);\n"
"X-Generator: Poedit 1.8.5\n"
#: registration/serializers.py:53
msgid "View is not defined, pass it as a context variable"
msgstr "View неизвестен, передайте его как переменную контекста"
#: registration/serializers.py:58
msgid "Define adapter_class in view"
msgstr "Установите adapter_class в view"
#: registration/serializers.py:77
msgid "Define callback_url in view"
msgstr "Установите callback_url в view"
#: registration/serializers.py:81
msgid "Define client_class in view"
msgstr "Установите client_class в view"
#: registration/serializers.py:102
msgid "Incorrect input. access_token or code is required."
msgstr "Некорректный ввод. Необходим access_token или code."
#: registration/serializers.py:111
msgid "Incorrect value"
msgstr "Некорректное значение"
#: registration/serializers.py:140
msgid "A user is already registered with this e-mail address."
msgstr "Пользователь с таким e-mail адресом уже зарегистрирован."
#: registration/serializers.py:148
msgid "The two password fields didn't match."
msgstr "Пароли не совпадают."
#: registration/views.py:44
msgid "Verification e-mail sent."
msgstr "Письмо с подтверждением выслано."
#: registration/views.py:91
msgid "ok"
msgstr "ок"
#: serializers.py:30
msgid "Must include \"email\" and \"password\"."
msgstr "Должно включать \"email\" и \"password\"."
#: serializers.py:41
msgid "Must include \"username\" and \"password\"."
msgstr "Должно включать \"username\" и \"password\"."
#: serializers.py:54
msgid "Must include either \"username\" or \"email\" and \"password\"."
msgstr "Должно включать либо \"username\" либо \"email\" и \"password\"."
#: serializers.py:95
msgid "User account is disabled."
msgstr "Пользовательский аккаунт отключён."
#: serializers.py:98
msgid "Unable to log in with provided credentials."
msgstr "Невозможно войти в систему с указанными учётными данными."
#: serializers.py:107
msgid "E-mail is not verified."
msgstr "E-mail не подтверждён."
#: views.py:126
msgid "Successfully logged out."
msgstr "Успешно вышли."
#: views.py:174
msgid "Password reset e-mail has been sent."
msgstr "Письмо с инструкциями по восстановлению пароля выслано."
#: views.py:200
msgid "Password has been reset with the new password."
msgstr "Пароль изменён на новый."
#: views.py:222
msgid "New password has been saved."
msgstr "Новый пароль сохранён."

View File

@ -0,0 +1,95 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-03-05 21:56-0800\n"
"PO-Revision-Date: 2018-10-13 19:37+0300\n"
"Language: tr\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"Last-Translator: \n"
"Language-Team: \n"
"X-Generator: Poedit 2.2\n"
#: registration/serializers.py:67
msgid "View is not defined, pass it as a context variable"
msgstr "“View” tanımlanmadı, “context” değişkeni olarak tanımla"
#: registration/serializers.py:72
msgid "Define adapter_class in view"
msgstr "“view” içerisinde “adapter_class” tanımla"
#: registration/serializers.py:91
msgid "Define callback_url in view"
msgstr "“view” içerisinde “callback_url” tanımla"
#: registration/serializers.py:95
msgid "Define client_class in view"
msgstr "“view” içerisinde “client_class” tanımla"
#: registration/serializers.py:116
msgid "Incorrect input. access_token or code is required."
msgstr "Geçersiz girdi. “access_token” veya “code” gerekli."
#: registration/serializers.py:125
msgid "Incorrect value"
msgstr "Geçersiz değer"
#: registration/serializers.py:185
msgid "A user is already registered with this e-mail address."
msgstr "Bu e-posta adresi ile bir kullanıcı zaten kayıt olmuştu."
#: registration/serializers.py:193
msgid "The two password fields didn't match."
msgstr "İki şifre alanı eşleşmiyor."
#: registration/views.py:98
msgid "ok"
msgstr "tamam"
#: serializers.py:33
msgid "Must include \"email\" and \"password\"."
msgstr "\"email\" ve \"password\" içermelidir."
#: serializers.py:44
msgid "Must include \"username\" and \"password\"."
msgstr "“username\" und \"password\" içermelidir."
#: serializers.py:57
msgid "Must include either \"username\" or \"email\" and \"password\"."
msgstr "Ya ”username\" yada \"email\" ve \"password\" içermelidir."
#: serializers.py:98
msgid "User account is disabled."
msgstr "Kullanıcı hesap pasiftir."
#: serializers.py:101
msgid "Unable to log in with provided credentials."
msgstr "Sağlanan kimlik bilgileri ile giriş yapılamıyor."
#: serializers.py:110
msgid "E-mail is not verified."
msgstr "E-posta adresi doğrulanmadı."
#: views.py:127
msgid "Successfully logged out."
msgstr "Başarılı bir şekilde çıkış yapıldı."
#: views.py:175
msgid "Password reset e-mail has been sent."
msgstr "Şifre sıfırlama e-postası gönderildi."
#: views.py:201
msgid "Password has been reset with the new password."
msgstr "Yeni şifre ile şifre sıfırlandı."
#: views.py:223
msgid "New password has been saved."
msgstr "Yeni şifre kaydedildi."

Binary file not shown.

View File

@ -0,0 +1,104 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-10-28 11:41+0800\n"
"PO-Revision-Date: 2018-10-28 11:45+0806\n"
"Last-Translator: b' <admin@xx.com>'\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"
"X-Translated-Using: django-rosetta 0.9.0\n"
#: registration/serializers.py:67
msgid "View is not defined, pass it as a context variable"
msgstr "View未定义请通过context变量传入"
#: registration/serializers.py:72
msgid "Define adapter_class in view"
msgstr "请在View中定义adapter_class"
#: registration/serializers.py:91
msgid "Define callback_url in view"
msgstr "请在view中定义callback_url"
#: registration/serializers.py:95
msgid "Define client_class in view"
msgstr "请在view中定义client_class"
#: registration/serializers.py:116
msgid "Incorrect input. access_token or code is required."
msgstr "输入错误。access_token或code是必填项。"
#: registration/serializers.py:125
msgid "Incorrect value"
msgstr "错误的值"
#: registration/serializers.py:139
msgid "User is already registered with this e-mail address."
msgstr "该邮箱地址已被注册。"
#: registration/serializers.py:185
msgid "A user is already registered with this e-mail address."
msgstr "该邮箱地址已被注册。"
#: registration/serializers.py:193
msgid "The two password fields didn't match."
msgstr "两次输入的密码不相同"
#: registration/views.py:51
msgid "Verification e-mail sent."
msgstr "验证邮件已发送。"
#: registration/views.py:98
msgid "ok"
msgstr "好的"
#: serializers.py:33
msgid "Must include \"email\" and \"password\"."
msgstr "比如包含\"email\"和\"password\"。"
#: serializers.py:44
msgid "Must include \"username\" and \"password\"."
msgstr "比如包含\"username\"和\"password\"。"
#: serializers.py:57
msgid "Must include either \"username\" or \"email\" and \"password\"."
msgstr "比如包含\"username\"\"email\"\"password\"其中一个。"
#: serializers.py:98
msgid "User account is disabled."
msgstr "用户账号已被禁用。"
#: serializers.py:101
msgid "Unable to log in with provided credentials."
msgstr "无法使用提供的信息登录。"
#: serializers.py:110
msgid "E-mail is not verified."
msgstr "邮箱未验证。"
#: views.py:127
msgid "Successfully logged out."
msgstr "已成功登出。"
#: views.py:175
msgid "Password reset e-mail has been sent."
msgstr "密码重置邮件已发送。"
#: views.py:201
msgid "Password has been reset with the new password."
msgstr "密码重置成功。"
#: views.py:223
msgid "New password has been saved."
msgstr "新密码已设置成功。"

Binary file not shown.

View File

@ -0,0 +1,103 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-10-28 11:41+0800\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"
#: registration/serializers.py:67
msgid "View is not defined, pass it as a context variable"
msgstr ""
#: registration/serializers.py:72
msgid "Define adapter_class in view"
msgstr ""
#: registration/serializers.py:91
msgid "Define callback_url in view"
msgstr ""
#: registration/serializers.py:95
msgid "Define client_class in view"
msgstr ""
#: registration/serializers.py:116
msgid "Incorrect input. access_token or code is required."
msgstr ""
#: registration/serializers.py:125
msgid "Incorrect value"
msgstr ""
#: registration/serializers.py:139
msgid "User is already registered with this e-mail address."
msgstr ""
#: registration/serializers.py:185
msgid "A user is already registered with this e-mail address."
msgstr ""
#: registration/serializers.py:193
msgid "The two password fields didn't match."
msgstr ""
#: registration/views.py:51
msgid "Verification e-mail sent."
msgstr ""
#: registration/views.py:98
msgid "ok"
msgstr ""
#: serializers.py:33
msgid "Must include \"email\" and \"password\"."
msgstr ""
#: serializers.py:44
msgid "Must include \"username\" and \"password\"."
msgstr ""
#: serializers.py:57
msgid "Must include either \"username\" or \"email\" and \"password\"."
msgstr ""
#: serializers.py:98
msgid "User account is disabled."
msgstr ""
#: serializers.py:101
msgid "Unable to log in with provided credentials."
msgstr ""
#: serializers.py:110
msgid "E-mail is not verified."
msgstr ""
#: views.py:127
msgid "Successfully logged out."
msgstr ""
#: views.py:175
msgid "Password reset e-mail has been sent."
msgstr ""
#: views.py:201
msgid "Password has been reset with the new password."
msgstr ""
#: views.py:223
msgid "New password has been saved."
msgstr ""

View File

@ -1,5 +1,6 @@
from django.conf import settings from django.conf import settings
from rest_framework.permissions import AllowAny
from rest_auth.registration.serializers import ( from rest_auth.registration.serializers import (
RegisterSerializer as DefaultRegisterSerializer) RegisterSerializer as DefaultRegisterSerializer)
from ..utils import import_callable from ..utils import import_callable
@ -9,3 +10,10 @@ serializers = getattr(settings, 'REST_AUTH_REGISTER_SERIALIZERS', {})
RegisterSerializer = import_callable( RegisterSerializer = import_callable(
serializers.get('REGISTER_SERIALIZER', DefaultRegisterSerializer)) serializers.get('REGISTER_SERIALIZER', DefaultRegisterSerializer))
def register_permission_classes():
permission_classes = [AllowAny, ]
for klass in getattr(settings, 'REST_AUTH_REGISTER_PERMISSION_CLASSES', tuple()):
permission_classes.append(import_callable(klass))
return tuple(permission_classes)

View File

@ -1,6 +1,6 @@
from django.http import HttpRequest from django.http import HttpRequest
from django.conf import settings
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.contrib.auth import get_user_model
try: try:
from allauth.account import app_settings as allauth_settings from allauth.account import app_settings as allauth_settings
@ -8,15 +8,29 @@ try:
get_username_max_length) get_username_max_length)
from allauth.account.adapter import get_adapter from allauth.account.adapter import get_adapter
from allauth.account.utils import setup_user_email from allauth.account.utils import setup_user_email
from allauth.socialaccount.helpers import complete_social_login
from allauth.socialaccount.models import SocialAccount
from allauth.socialaccount.providers.base import AuthProcess
except ImportError: except ImportError:
raise ImportError('allauth needs to be added to INSTALLED_APPS.') raise ImportError("allauth needs to be added to INSTALLED_APPS.")
from rest_framework import serializers from rest_framework import serializers
from requests.exceptions import HTTPError from requests.exceptions import HTTPError
# Import is needed only if we are using social login, in which
# case the allauth.socialaccount will be declared
if 'allauth.socialaccount' in settings.INSTALLED_APPS: class SocialAccountSerializer(serializers.ModelSerializer):
from allauth.socialaccount.helpers import complete_social_login """
serialize allauth SocialAccounts for use with a REST API
"""
class Meta:
model = SocialAccount
fields = (
'id',
'provider',
'uid',
'last_login',
'date_joined',
)
class SocialLoginSerializer(serializers.Serializer): class SocialLoginSerializer(serializers.Serializer):
@ -31,12 +45,13 @@ class SocialLoginSerializer(serializers.Serializer):
def get_social_login(self, adapter, app, token, response): def get_social_login(self, adapter, app, token, response):
""" """
:param adapter: allauth.socialaccount Adapter subclass.
:param adapter: allauth.socialaccount Adapter subclass. Usually OAuthAdapter or Auth2Adapter Usually OAuthAdapter or Auth2Adapter
:param app: `allauth.socialaccount.SocialApp` instance :param app: `allauth.socialaccount.SocialApp` instance
:param token: `allauth.socialaccount.SocialToken` instance :param token: `allauth.socialaccount.SocialToken` instance
:param response: Provider's response for OAuth1. Not used in the :param response: Provider's response for OAuth1. Not used in the
:return: :return: A populated instance of the `allauth.socialaccount.SocialLoginView` instance :returns: A populated instance of the
`allauth.socialaccount.SocialLoginView` instance
""" """
request = self._get_request() request = self._get_request()
social_login = adapter.complete_login(request, app, token, response=response) social_login = adapter.complete_login(request, app, token, response=response)
@ -49,12 +64,12 @@ class SocialLoginSerializer(serializers.Serializer):
if not view: if not view:
raise serializers.ValidationError( raise serializers.ValidationError(
_('View is not defined, pass it as a context variable') _("View is not defined, pass it as a context variable")
) )
adapter_class = getattr(view, 'adapter_class', None) adapter_class = getattr(view, 'adapter_class', None)
if not adapter_class: if not adapter_class:
raise serializers.ValidationError(_('Define adapter_class in view')) raise serializers.ValidationError(_("Define adapter_class in view"))
adapter = adapter_class(request) adapter = adapter_class(request)
app = adapter.get_provider().get_app(request) app = adapter.get_provider().get_app(request)
@ -63,21 +78,21 @@ class SocialLoginSerializer(serializers.Serializer):
# http://stackoverflow.com/questions/8666316/facebook-oauth-2-0-code-and-token # http://stackoverflow.com/questions/8666316/facebook-oauth-2-0-code-and-token
# Case 1: We received the access_token # Case 1: We received the access_token
if('access_token' in attrs): if attrs.get('access_token'):
access_token = attrs.get('access_token') access_token = attrs.get('access_token')
# Case 2: We received the authorization code # Case 2: We received the authorization code
elif('code' in attrs): elif attrs.get('code'):
self.callback_url = getattr(view, 'callback_url', None) self.callback_url = getattr(view, 'callback_url', None)
self.client_class = getattr(view, 'client_class', None) self.client_class = getattr(view, 'client_class', None)
if not self.callback_url: if not self.callback_url:
raise serializers.ValidationError( raise serializers.ValidationError(
_('Define callback_url in view') _("Define callback_url in view")
) )
if not self.client_class: if not self.client_class:
raise serializers.ValidationError( raise serializers.ValidationError(
_('Define client_class in view') _("Define client_class in view")
) )
code = attrs.get('code') code = attrs.get('code')
@ -97,25 +112,57 @@ class SocialLoginSerializer(serializers.Serializer):
access_token = token['access_token'] access_token = token['access_token']
else: else:
raise serializers.ValidationError(_('Incorrect input. access_token or code is required.')) raise serializers.ValidationError(
_("Incorrect input. access_token or code is required."))
token = adapter.parse_token({'access_token': access_token}) social_token = adapter.parse_token({'access_token': access_token})
token.app = app social_token.app = app
try: try:
login = self.get_social_login(adapter, app, token, access_token) login = self.get_social_login(adapter, app, social_token, access_token)
complete_social_login(request, login) complete_social_login(request, login)
except HTTPError: except HTTPError:
raise serializers.ValidationError(_('Incorrect value')) raise serializers.ValidationError(_("Incorrect value"))
if not login.is_existing: if not login.is_existing:
# We have an account already signed up in a different flow
# with the same email address: raise an exception.
# This needs to be handled in the frontend. We can not just
# link up the accounts due to security constraints
if allauth_settings.UNIQUE_EMAIL:
# Do we have an account already with this email address?
account_exists = get_user_model().objects.filter(
email=login.user.email,
).exists()
if account_exists:
raise serializers.ValidationError(
_("User is already registered with this e-mail address.")
)
login.lookup() login.lookup()
login.save(request, connect=True) login.save(request, connect=True)
attrs['user'] = login.account.user attrs['user'] = login.account.user
return attrs return attrs
class SocialConnectMixin(object):
def get_social_login(self, *args, **kwargs):
"""
Set the social login process state to connect rather than login
Refer to the implementation of get_social_login in base class and to the
allauth.socialaccount.helpers module complete_social_login function.
"""
social_login = super(SocialConnectMixin, self).get_social_login(*args, **kwargs)
social_login.state['process'] = AuthProcess.CONNECT
return social_login
class SocialConnectSerializer(SocialConnectMixin, SocialLoginSerializer):
pass
class RegisterSerializer(serializers.Serializer): class RegisterSerializer(serializers.Serializer):
username = serializers.CharField( username = serializers.CharField(
max_length=get_username_max_length(), max_length=get_username_max_length(),
@ -123,8 +170,8 @@ class RegisterSerializer(serializers.Serializer):
required=allauth_settings.USERNAME_REQUIRED required=allauth_settings.USERNAME_REQUIRED
) )
email = serializers.EmailField(required=allauth_settings.EMAIL_REQUIRED) email = serializers.EmailField(required=allauth_settings.EMAIL_REQUIRED)
password1 = serializers.CharField(required=True, write_only=True) password1 = serializers.CharField(write_only=True)
password2 = serializers.CharField(required=True, write_only=True) password2 = serializers.CharField(write_only=True)
def validate_username(self, username): def validate_username(self, username):
username = get_adapter().clean_username(username) username = get_adapter().clean_username(username)

View File

@ -17,7 +17,7 @@ urlpatterns = [
# with proper key. # with proper key.
# If you don't want to use API on that step, then just use ConfirmEmailView # If you don't want to use API on that step, then just use ConfirmEmailView
# view from: # view from:
# django-allauth https://github.com/pennersr/django-allauth/blob/master/allauth/account/views.py#L190 # django-allauth https://github.com/pennersr/django-allauth/blob/master/allauth/account/views.py
url(r'^account-confirm-email/(?P<key>[-:\w]+)/$', TemplateView.as_view(), url(r'^account-confirm-email/(?P<key>[-:\w]+)/$', TemplateView.as_view(),
name='account_confirm_email'), name='account_confirm_email'),
] ]

View File

@ -1,39 +1,54 @@
from django.utils.translation import ugettext_lazy as _
from django.conf import settings from django.conf import settings
from django.utils.decorators import method_decorator
from django.utils.translation import ugettext_lazy as _
from django.views.decorators.debug import sensitive_post_parameters
from rest_framework.views import APIView from rest_framework.views import APIView
from rest_framework.response import Response from rest_framework.response import Response
from rest_framework.permissions import AllowAny from rest_framework.permissions import (AllowAny,
from rest_framework.generics import CreateAPIView IsAuthenticated)
from rest_framework.generics import CreateAPIView, ListAPIView, GenericAPIView
from rest_framework.exceptions import NotFound
from rest_framework import status from rest_framework import status
from allauth.account.adapter import get_adapter from allauth.account.adapter import get_adapter
from allauth.account.views import ConfirmEmailView from allauth.account.views import ConfirmEmailView
from allauth.account.utils import complete_signup from allauth.account.utils import complete_signup
from allauth.account import app_settings as allauth_settings from allauth.account import app_settings as allauth_settings
from allauth.socialaccount import signals
from allauth.socialaccount.adapter import get_adapter as get_social_adapter
from allauth.socialaccount.models import SocialAccount
from rest_auth.app_settings import (TokenSerializer, from rest_auth.app_settings import (TokenSerializer,
JWTSerializer, JWTSerializer,
create_token) create_token)
from rest_auth.registration.serializers import (SocialLoginSerializer,
VerifyEmailSerializer)
from rest_auth.views import LoginView
from rest_auth.models import TokenModel from rest_auth.models import TokenModel
from .app_settings import RegisterSerializer from rest_auth.registration.serializers import (VerifyEmailSerializer,
SocialLoginSerializer,
SocialAccountSerializer,
SocialConnectSerializer)
from rest_auth.utils import jwt_encode from rest_auth.utils import jwt_encode
from rest_auth.views import LoginView
from .app_settings import RegisterSerializer, register_permission_classes
sensitive_post_parameters_m = method_decorator(
sensitive_post_parameters('password1', 'password2')
)
class RegisterView(CreateAPIView): class RegisterView(CreateAPIView):
serializer_class = RegisterSerializer serializer_class = RegisterSerializer
permission_classes = (AllowAny, ) permission_classes = register_permission_classes()
token_model = TokenModel token_model = TokenModel
throttle_scope = 'register_view'
@sensitive_post_parameters_m
def dispatch(self, *args, **kwargs):
return super(RegisterView, self).dispatch(*args, **kwargs)
def get_response_data(self, user): def get_response_data(self, user):
if allauth_settings.EMAIL_VERIFICATION == \ if allauth_settings.EMAIL_VERIFICATION == \
allauth_settings.EmailVerificationMethod.MANDATORY: allauth_settings.EmailVerificationMethod.MANDATORY:
return {} return {"detail": _("Verification e-mail sent.")}
if getattr(settings, 'REST_USE_JWT', False): if getattr(settings, 'REST_USE_JWT', False):
data = { data = {
@ -50,7 +65,9 @@ class RegisterView(CreateAPIView):
user = self.perform_create(serializer) user = self.perform_create(serializer)
headers = self.get_success_headers(serializer.data) headers = self.get_success_headers(serializer.data)
return Response(self.get_response_data(user), status=status.HTTP_201_CREATED, headers=headers) return Response(self.get_response_data(user),
status=status.HTTP_201_CREATED,
headers=headers)
def perform_create(self, serializer): def perform_create(self, serializer):
user = serializer.save(self.request) user = serializer.save(self.request)
@ -66,17 +83,19 @@ class RegisterView(CreateAPIView):
class VerifyEmailView(APIView, ConfirmEmailView): class VerifyEmailView(APIView, ConfirmEmailView):
permission_classes = (AllowAny,) permission_classes = (AllowAny,)
allowed_methods = ('POST', 'OPTIONS', 'HEAD') allowed_methods = ('POST', 'OPTIONS', 'HEAD')
def get_serializer(self, *args, **kwargs):
return VerifyEmailSerializer(*args, **kwargs)
def post(self, request, *args, **kwargs): def post(self, request, *args, **kwargs):
serializer = VerifyEmailSerializer(data=request.data) serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True) serializer.is_valid(raise_exception=True)
self.kwargs['key'] = serializer.validated_data['key'] self.kwargs['key'] = serializer.validated_data['key']
confirmation = self.get_object() confirmation = self.get_object()
confirmation.confirm(self.request) confirmation.confirm(self.request)
return Response({'message': _('ok')}, status=status.HTTP_200_OK) return Response({'detail': _('ok')}, status=status.HTTP_200_OK)
class SocialLoginView(LoginView): class SocialLoginView(LoginView):
@ -98,12 +117,70 @@ class SocialLoginView(LoginView):
class FacebookLogin(SocialLoginView): class FacebookLogin(SocialLoginView):
adapter_class = FacebookOAuth2Adapter adapter_class = FacebookOAuth2Adapter
client_class = OAuth2Client client_class = OAuth2Client
callback_url = 'localhost:8000' callback_url = 'localhost:8000'
------------- -------------
""" """
serializer_class = SocialLoginSerializer serializer_class = SocialLoginSerializer
def process_login(self): def process_login(self):
get_adapter(self.request).login(self.request, self.user) get_adapter(self.request).login(self.request, self.user)
class SocialConnectView(LoginView):
"""
class used for social account linking
example usage for facebook with access_token
-------------
from allauth.socialaccount.providers.facebook.views import FacebookOAuth2Adapter
class FacebookConnect(SocialConnectView):
adapter_class = FacebookOAuth2Adapter
-------------
"""
serializer_class = SocialConnectSerializer
permission_classes = (IsAuthenticated,)
def process_login(self):
get_adapter(self.request).login(self.request, self.user)
class SocialAccountListView(ListAPIView):
"""
List SocialAccounts for the currently logged in user
"""
serializer_class = SocialAccountSerializer
permission_classes = (IsAuthenticated,)
def get_queryset(self):
return SocialAccount.objects.filter(user=self.request.user)
class SocialAccountDisconnectView(GenericAPIView):
"""
Disconnect SocialAccount from remote service for
the currently logged in user
"""
serializer_class = SocialConnectSerializer
permission_classes = (IsAuthenticated,)
def get_queryset(self):
return SocialAccount.objects.filter(user=self.request.user)
def post(self, request, *args, **kwargs):
accounts = self.get_queryset()
account = accounts.filter(pk=kwargs['pk']).first()
if not account:
raise NotFound
get_social_adapter(self.request).validate_disconnect(account, accounts)
account.delete()
signals.social_account_removed.send(
sender=SocialAccount,
request=self.request,
socialaccount=account
)
return Response(self.get_serializer(account).data)

View File

@ -6,11 +6,12 @@ from django.utils.http import urlsafe_base64_decode as uid_decoder
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.utils.encoding import force_text from django.utils.encoding import force_text
from .models import TokenModel
from rest_framework import serializers, exceptions from rest_framework import serializers, exceptions
from rest_framework.exceptions import ValidationError from rest_framework.exceptions import ValidationError
from .models import TokenModel
from .utils import import_callable
# Get the UserModel # Get the UserModel
UserModel = get_user_model() UserModel = get_user_model()
@ -20,11 +21,14 @@ class LoginSerializer(serializers.Serializer):
email = serializers.EmailField(required=False, allow_blank=True) email = serializers.EmailField(required=False, allow_blank=True)
password = serializers.CharField(style={'input_type': 'password'}) password = serializers.CharField(style={'input_type': 'password'})
def authenticate(self, **kwargs):
return authenticate(self.context['request'], **kwargs)
def _validate_email(self, email, password): def _validate_email(self, email, password):
user = None user = None
if email and password: if email and password:
user = authenticate(email=email, password=password) user = self.authenticate(email=email, password=password)
else: else:
msg = _('Must include "email" and "password".') msg = _('Must include "email" and "password".')
raise exceptions.ValidationError(msg) raise exceptions.ValidationError(msg)
@ -35,7 +39,7 @@ class LoginSerializer(serializers.Serializer):
user = None user = None
if username and password: if username and password:
user = authenticate(username=username, password=password) user = self.authenticate(username=username, password=password)
else: else:
msg = _('Must include "username" and "password".') msg = _('Must include "username" and "password".')
raise exceptions.ValidationError(msg) raise exceptions.ValidationError(msg)
@ -46,9 +50,9 @@ class LoginSerializer(serializers.Serializer):
user = None user = None
if email and password: if email and password:
user = authenticate(email=email, password=password) user = self.authenticate(email=email, password=password)
elif username and password: elif username and password:
user = authenticate(username=username, password=password) user = self.authenticate(username=username, password=password)
else: else:
msg = _('Must include either "username" or "email" and "password".') msg = _('Must include either "username" or "email" and "password".')
raise exceptions.ValidationError(msg) raise exceptions.ValidationError(msg)
@ -70,7 +74,7 @@ class LoginSerializer(serializers.Serializer):
user = self._validate_email(email, password) user = self._validate_email(email, password)
# Authentication through username # Authentication through username
if app_settings.AUTHENTICATION_METHOD == app_settings.AuthenticationMethod.USERNAME: elif app_settings.AUTHENTICATION_METHOD == app_settings.AuthenticationMethod.USERNAME:
user = self._validate_username(username, password) user = self._validate_username(username, password)
# Authentication through either username or email # Authentication through either username or email
@ -120,13 +124,12 @@ class TokenSerializer(serializers.ModelSerializer):
class UserDetailsSerializer(serializers.ModelSerializer): class UserDetailsSerializer(serializers.ModelSerializer):
""" """
User model w/o password User model w/o password
""" """
class Meta: class Meta:
model = UserModel model = UserModel
fields = ('username', 'email', 'first_name', 'last_name') fields = ('pk', 'username', 'email', 'first_name', 'last_name')
read_only_fields = ('email', ) read_only_fields = ('email', )
@ -135,22 +138,31 @@ class JWTSerializer(serializers.Serializer):
Serializer for JWT authentication. Serializer for JWT authentication.
""" """
token = serializers.CharField() token = serializers.CharField()
user = UserDetailsSerializer() user = serializers.SerializerMethodField()
def get_user(self, obj):
"""
Required to allow using custom USER_DETAILS_SERIALIZER in
JWTSerializer. Defining it here to avoid circular imports
"""
rest_auth_serializers = getattr(settings, 'REST_AUTH_SERIALIZERS', {})
JWTUserDetailsSerializer = import_callable(
rest_auth_serializers.get('USER_DETAILS_SERIALIZER', UserDetailsSerializer)
)
user_data = JWTUserDetailsSerializer(obj['user'], context=self.context).data
return user_data
class PasswordResetSerializer(serializers.Serializer): class PasswordResetSerializer(serializers.Serializer):
""" """
Serializer for requesting a password reset e-mail. Serializer for requesting a password reset e-mail.
""" """
email = serializers.EmailField() email = serializers.EmailField()
password_reset_form_class = PasswordResetForm password_reset_form_class = PasswordResetForm
def get_email_options(self): def get_email_options(self):
""" Override this method to change default e-mail options """Override this method to change default e-mail options"""
"""
return {} return {}
def validate_email(self, value): def validate_email(self, value):
@ -178,12 +190,10 @@ class PasswordResetConfirmSerializer(serializers.Serializer):
""" """
Serializer for requesting a password reset e-mail. Serializer for requesting a password reset e-mail.
""" """
new_password1 = serializers.CharField(max_length=128) new_password1 = serializers.CharField(max_length=128)
new_password2 = serializers.CharField(max_length=128) new_password2 = serializers.CharField(max_length=128)
uid = serializers.CharField()
uid = serializers.CharField(required=True) token = serializers.CharField()
token = serializers.CharField(required=True)
set_password_form_class = SetPasswordForm set_password_form_class = SetPasswordForm
@ -213,11 +223,10 @@ class PasswordResetConfirmSerializer(serializers.Serializer):
return attrs return attrs
def save(self): def save(self):
self.set_password_form.save() return self.set_password_form.save()
class PasswordChangeSerializer(serializers.Serializer): class PasswordChangeSerializer(serializers.Serializer):
old_password = serializers.CharField(max_length=128) old_password = serializers.CharField(max_length=128)
new_password1 = serializers.CharField(max_length=128) new_password1 = serializers.CharField(max_length=128)
new_password2 = serializers.CharField(max_length=128) new_password2 = serializers.CharField(max_length=128)
@ -247,7 +256,8 @@ class PasswordChangeSerializer(serializers.Serializer):
) )
if all(invalid_password_conditions): if all(invalid_password_conditions):
raise serializers.ValidationError('Invalid password') err_msg = _("Your old password was entered incorrectly. Please enter it again.")
raise serializers.ValidationError(err_msg)
return value return value
def validate(self, attrs): def validate(self, attrs):

View File

@ -8,10 +8,12 @@ if 'allauth.socialaccount' in settings.INSTALLED_APPS:
from allauth.socialaccount.models import SocialToken from allauth.socialaccount.models import SocialToken
from allauth.socialaccount.providers.oauth.client import OAuthError from allauth.socialaccount.providers.oauth.client import OAuthError
from rest_auth.registration.serializers import SocialConnectMixin
class TwitterLoginSerializer(serializers.Serializer): class TwitterLoginSerializer(serializers.Serializer):
access_token = serializers.CharField(required=True) access_token = serializers.CharField()
token_secret = serializers.CharField(required=True) token_secret = serializers.CharField()
def _get_request(self): def _get_request(self):
request = self.context.get('request') request = self.context.get('request')
@ -21,15 +23,17 @@ class TwitterLoginSerializer(serializers.Serializer):
def get_social_login(self, adapter, app, token, response): def get_social_login(self, adapter, app, token, response):
""" """
:param adapter: allauth.socialaccount Adapter subclass.
:param adapter: allauth.socialaccount Adapter subclass. Usually OAuthAdapter or Auth2Adapter Usually OAuthAdapter or Auth2Adapter
:param app: `allauth.socialaccount.SocialApp` instance :param app: `allauth.socialaccount.SocialApp` instance
:param token: `allauth.socialaccount.SocialToken` instance :param token: `allauth.socialaccount.SocialToken` instance
:param response: Provider's response for OAuth1. Not used in the :param response: Provider's response for OAuth1. Not used in the
:return: :return: A populated instance of the `allauth.socialaccount.SocialLoginView` instance :returns: A populated instance of the
`allauth.socialaccount.SocialLoginView` instance
""" """
request = self._get_request() request = self._get_request()
social_login = adapter.complete_login(request, app, token, response=response) social_login = adapter.complete_login(request, app, token,
response=response)
social_login.token = token social_login.token = token
return social_login return social_login
@ -39,12 +43,12 @@ class TwitterLoginSerializer(serializers.Serializer):
if not view: if not view:
raise serializers.ValidationError( raise serializers.ValidationError(
'View is not defined, pass it as a context variable' "View is not defined, pass it as a context variable"
) )
adapter_class = getattr(view, 'adapter_class', None) adapter_class = getattr(view, 'adapter_class', None)
if not adapter_class: if not adapter_class:
raise serializers.ValidationError('Define adapter_class in view') raise serializers.ValidationError("Define adapter_class in view")
adapter = adapter_class(request) adapter = adapter_class(request)
app = adapter.get_provider().get_app(request) app = adapter.get_provider().get_app(request)
@ -71,3 +75,7 @@ class TwitterLoginSerializer(serializers.Serializer):
attrs['user'] = login.account.user attrs['user'] = login.account.user
return attrs return attrs
class TwitterConnectSerializer(SocialConnectMixin, TwitterLoginSerializer):
pass

View File

@ -1,11 +1,23 @@
import json import json
from django.conf import settings from django.conf import settings
from django.core.urlresolvers import reverse
from django.test.client import Client, MULTIPART_CONTENT from django.test.client import Client, MULTIPART_CONTENT
from django.utils.encoding import force_text from django.utils.encoding import force_text
from rest_framework import status from rest_framework import status
from rest_framework import permissions
try:
from django.urls import reverse
except ImportError:
from django.core.urlresolvers import reverse
class CustomPermissionClass(permissions.BasePermission):
message = 'You shall not pass!'
def has_permission(self, request, view):
return False
class APIClient(Client): class APIClient(Client):
@ -17,8 +29,7 @@ class APIClient(Client):
return self.generic('OPTIONS', path, data, content_type, **extra) return self.generic('OPTIONS', path, data, content_type, **extra)
class BaseAPITestCase(object): class TestsMixin(object):
""" """
base for API tests: base for API tests:
* easy request calls, f.e.: self.post(url, data), self.get(url) * easy request calls, f.e.: self.post(url, data), self.get(url)
@ -64,29 +75,6 @@ class BaseAPITestCase(object):
def patch(self, *args, **kwargs): def patch(self, *args, **kwargs):
return self.send_request('patch', *args, **kwargs) return self.send_request('patch', *args, **kwargs)
# def put(self, *args, **kwargs):
# return self.send_request('put', *args, **kwargs)
# def delete(self, *args, **kwargs):
# return self.send_request('delete', *args, **kwargs)
# def options(self, *args, **kwargs):
# return self.send_request('options', *args, **kwargs)
# def post_file(self, *args, **kwargs):
# kwargs['content_type'] = MULTIPART_CONTENT
# return self.send_request('post', *args, **kwargs)
# def get_file(self, *args, **kwargs):
# content_type = None
# if 'content_type' in kwargs:
# content_type = kwargs.pop('content_type')
# response = self.send_request('get', *args, **kwargs)
# if content_type:
# self.assertEqual(
# bool(filter(lambda x: content_type in x, response._headers['content-type'])), True)
# return response
def init(self): def init(self):
settings.DEBUG = True settings.DEBUG = True
self.client = APIClient() self.client = APIClient()
@ -97,11 +85,14 @@ class BaseAPITestCase(object):
self.register_url = reverse('rest_register') self.register_url = reverse('rest_register')
self.password_reset_url = reverse('rest_password_reset') self.password_reset_url = reverse('rest_password_reset')
self.user_url = reverse('rest_user_details') self.user_url = reverse('rest_user_details')
self.veirfy_email_url = reverse('rest_verify_email') self.verify_email_url = reverse('rest_verify_email')
self.fb_login_url = reverse('fb_login') self.fb_login_url = reverse('fb_login')
self.tw_login_url = reverse('tw_login') self.tw_login_url = reverse('tw_login')
self.tw_login_no_view_url = reverse('tw_login_no_view') self.tw_login_no_view_url = reverse('tw_login_no_view')
self.tw_login_no_adapter_url = reverse('tw_login_no_adapter') self.tw_login_no_adapter_url = reverse('tw_login_no_adapter')
self.fb_connect_url = reverse('fb_connect')
self.tw_connect_url = reverse('tw_connect')
self.social_account_list_url = reverse('social_account_list')
def _login(self): def _login(self):
payload = { payload = {

View File

@ -1,4 +1,5 @@
django-allauth>=0.19.1 django-allauth>=0.25.0
responses>=0.3.0 responses>=0.3.0
flake8==2.4.0 flake8==2.4.0
djangorestframework-jwt>=1.7.2 djangorestframework-jwt>=1.7.2
djangorestframework>=3.6.4

View File

@ -25,7 +25,7 @@ DATABASES = {
} }
} }
MIDDLEWARE_CLASSES = [ MIDDLEWARE = [
'django.middleware.common.CommonMiddleware', 'django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.csrf.CsrfViewMiddleware', 'django.middleware.csrf.CsrfViewMiddleware',
@ -33,6 +33,9 @@ MIDDLEWARE_CLASSES = [
'django.contrib.messages.middleware.MessageMiddleware' 'django.contrib.messages.middleware.MessageMiddleware'
] ]
# Adding for backwards compatibility for Django 1.8 tests
MIDDLEWARE_CLASSES = MIDDLEWARE
TEMPLATE_CONTEXT_PROCESSORS = [ TEMPLATE_CONTEXT_PROCESSORS = [
'django.contrib.auth.context_processors.auth', 'django.contrib.auth.context_processors.auth',
'django.core.context_processors.debug', 'django.core.context_processors.debug',

View File

@ -1,17 +1,26 @@
from django.core.urlresolvers import reverse
from django.test import TestCase, override_settings from django.test import TestCase, override_settings
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model
from django.core import mail from django.core import mail
from django.conf import settings from django.conf import settings
from django.utils.encoding import force_text from django.utils.encoding import force_text
from rest_framework import status
from allauth.account import app_settings as account_app_settings from allauth.account import app_settings as account_app_settings
from .test_base import BaseAPITestCase from rest_framework import status
from rest_framework.test import APIRequestFactory
from rest_auth.registration.views import RegisterView
from rest_auth.registration.app_settings import register_permission_classes
from .mixins import TestsMixin, CustomPermissionClass
try:
from django.urls import reverse
except ImportError:
from django.core.urlresolvers import reverse
@override_settings(ROOT_URLCONF="tests.urls") @override_settings(ROOT_URLCONF="tests.urls")
class APITestCase1(TestCase, BaseAPITestCase): class APIBasicTests(TestsMixin, TestCase):
""" """
Case #1: Case #1:
- user profile: defined - user profile: defined
@ -398,6 +407,20 @@ class APITestCase1(TestCase, BaseAPITestCase):
self._login() self._login()
self._logout() self._logout()
@override_settings(REST_AUTH_REGISTER_PERMISSION_CLASSES=(CustomPermissionClass,))
def test_registration_with_custom_permission_class(self):
class CustomRegisterView(RegisterView):
permission_classes = register_permission_classes()
authentication_classes = ()
factory = APIRequestFactory()
request = factory.post('/customer/details', self.REGISTRATION_DATA, format='json')
response = CustomRegisterView.as_view()(request)
self.assertEqual(response.data['detail'], CustomPermissionClass.message)
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
@override_settings(REST_USE_JWT=True) @override_settings(REST_USE_JWT=True)
def test_registration_with_jwt(self): def test_registration_with_jwt(self):
user_count = get_user_model().objects.all().count() user_count = get_user_model().objects.all().count()
@ -459,7 +482,7 @@ class APITestCase1(TestCase, BaseAPITestCase):
email_confirmation = new_user.emailaddress_set.get(email=self.EMAIL)\ email_confirmation = new_user.emailaddress_set.get(email=self.EMAIL)\
.emailconfirmation_set.order_by('-created')[0] .emailconfirmation_set.order_by('-created')[0]
self.post( self.post(
self.veirfy_email_url, self.verify_email_url,
data={"key": email_confirmation.key}, data={"key": email_confirmation.key},
status_code=status.HTTP_200_OK status_code=status.HTTP_200_OK
) )

View File

@ -5,17 +5,22 @@ from django.contrib.auth import get_user_model
from django.test.utils import override_settings from django.test.utils import override_settings
from django.contrib.sites.models import Site from django.contrib.sites.models import Site
try:
from django.urls import reverse
except ImportError:
from django.core.urlresolvers import reverse
from allauth.socialaccount.models import SocialApp from allauth.socialaccount.models import SocialApp
from allauth.socialaccount.providers.facebook.provider import GRAPH_API_URL from allauth.socialaccount.providers.facebook.provider import GRAPH_API_URL
import responses import responses
from rest_framework import status from rest_framework import status
from .test_base import BaseAPITestCase from .mixins import TestsMixin
@override_settings(ROOT_URLCONF="tests.urls") @override_settings(ROOT_URLCONF="tests.urls")
class TestSocialAuth(TestCase, BaseAPITestCase): class TestSocialAuth(TestsMixin, TestCase):
USERNAME = 'person' USERNAME = 'person'
PASS = 'person' PASS = 'person'
@ -225,7 +230,7 @@ class TestSocialAuth(TestCase, BaseAPITestCase):
REST_SESSION_LOGIN=False, REST_SESSION_LOGIN=False,
ACCOUNT_EMAIL_CONFIRMATION_HMAC=False ACCOUNT_EMAIL_CONFIRMATION_HMAC=False
) )
def test_edge_case(self): def test_email_clash_with_existing_account(self):
resp_body = { resp_body = {
"id": "123123123123", "id": "123123123123",
"first_name": "John", "first_name": "John",
@ -251,6 +256,8 @@ class TestSocialAuth(TestCase, BaseAPITestCase):
# test empty payload # test empty payload
self.post(self.register_url, data={}, status_code=400) self.post(self.register_url, data={}, status_code=400)
# register user and send email confirmation
self.post( self.post(
self.register_url, self.register_url,
data=self.REGISTRATION_DATA, data=self.REGISTRATION_DATA,
@ -263,7 +270,7 @@ class TestSocialAuth(TestCase, BaseAPITestCase):
email_confirmation = new_user.emailaddress_set.get(email=self.EMAIL)\ email_confirmation = new_user.emailaddress_set.get(email=self.EMAIL)\
.emailconfirmation_set.order_by('-created')[0] .emailconfirmation_set.order_by('-created')[0]
self.post( self.post(
self.veirfy_email_url, self.verify_email_url,
data={"key": email_confirmation.key}, data={"key": email_confirmation.key},
status_code=status.HTTP_200_OK status_code=status.HTTP_200_OK
) )
@ -271,12 +278,11 @@ class TestSocialAuth(TestCase, BaseAPITestCase):
self._login() self._login()
self._logout() self._logout()
# fb log in with already existing email
payload = { payload = {
'access_token': 'abc123' 'access_token': 'abc123'
} }
self.post(self.fb_login_url, data=payload, status_code=400)
self.post(self.fb_login_url, data=payload, status_code=200)
self.assertIn('key', self.response.json.keys())
@responses.activate @responses.activate
@override_settings( @override_settings(
@ -302,3 +308,140 @@ class TestSocialAuth(TestCase, BaseAPITestCase):
self.assertIn('user', self.response.json.keys()) self.assertIn('user', self.response.json.keys())
self.assertEqual(get_user_model().objects.all().count(), users_count + 1) self.assertEqual(get_user_model().objects.all().count(), users_count + 1)
@override_settings(ROOT_URLCONF="tests.urls")
class TestSocialConnectAuth(TestsMixin, TestCase):
USERNAME = 'person'
PASS = 'person'
EMAIL = "person1@world.com"
REGISTRATION_DATA = {
"username": USERNAME,
"password1": PASS,
"password2": PASS,
"email": EMAIL
}
def setUp(self):
self.init()
facebook_social_app = SocialApp.objects.create(
provider='facebook',
name='Facebook',
client_id='123123123',
secret='321321321',
)
twitter_social_app = SocialApp.objects.create(
provider='twitter',
name='Twitter',
client_id='11223344',
secret='55667788',
)
site = Site.objects.get_current()
facebook_social_app.sites.add(site)
twitter_social_app.sites.add(site)
self.graph_api_url = GRAPH_API_URL + '/me'
self.twitter_url = 'https://api.twitter.com/1.1/account/verify_credentials.json'
@responses.activate
def test_social_connect_no_auth(self):
responses.add(
responses.GET,
self.graph_api_url,
body='',
status=200,
content_type='application/json'
)
payload = {
'access_token': 'abc123'
}
self.post(self.fb_connect_url, data=payload, status_code=403)
self.post(self.tw_connect_url, data=payload, status_code=403)
@responses.activate
def test_social_connect(self):
# register user
self.post(
self.register_url,
data=self.REGISTRATION_DATA,
status_code=201
)
# Test Facebook
resp_body = {
"id": "123123123123",
"first_name": "John",
"gender": "male",
"last_name": "Smith",
"link": "https://www.facebook.com/john.smith",
"locale": "en_US",
"name": "John Smith",
"timezone": 2,
"updated_time": "2014-08-13T10:14:38+0000",
"username": "john.smith",
"verified": True
}
responses.add(
responses.GET,
self.graph_api_url,
body=json.dumps(resp_body),
status=200,
content_type='application/json'
)
payload = {
'access_token': 'abc123'
}
self.post(self.fb_connect_url, data=payload, status_code=200)
self.assertIn('key', self.response.json.keys())
# Test Twitter
resp_body = {
"id": "123123123123",
}
responses.add(
responses.GET,
self.twitter_url,
body=json.dumps(resp_body),
status=200,
content_type='application/json'
)
payload = {
'access_token': 'abc123',
'token_secret': '1111222233334444'
}
self.post(self.tw_connect_url, data=payload)
self.assertIn('key', self.response.json.keys())
# Check current social accounts
self.get(self.social_account_list_url)
self.assertEqual(len(self.response.json), 2)
self.assertEqual(self.response.json[0]['provider'], 'facebook')
self.assertEqual(self.response.json[1]['provider'], 'twitter')
facebook_social_account_id = self.response.json[0]['id']
# Try disconnecting accounts
self.incorrect_disconnect_url = reverse(
'social_account_disconnect', args=[999999999]
)
self.post(self.incorrect_disconnect_url, status_code=404)
self.disconnect_url = reverse(
'social_account_disconnect', args=[facebook_social_account_id]
)
self.post(self.disconnect_url, status_code=200)
# Check social accounts after disconnecting
self.get(self.social_account_list_url)
self.assertEqual(len(self.response.json), 1)
self.assertEqual(self.response.json[0]['provider'], 'twitter')

View File

@ -8,8 +8,13 @@ from allauth.socialaccount.providers.twitter.views import TwitterOAuthAdapter
from rest_framework.decorators import api_view from rest_framework.decorators import api_view
from rest_auth.urls import urlpatterns from rest_auth.urls import urlpatterns
from rest_auth.registration.views import SocialLoginView from rest_auth.registration.views import (
from rest_auth.social_serializers import TwitterLoginSerializer SocialLoginView, SocialConnectView, SocialAccountListView,
SocialAccountDisconnectView
)
from rest_auth.social_serializers import (
TwitterLoginSerializer, TwitterConnectSerializer
)
class FacebookLogin(SocialLoginView): class FacebookLogin(SocialLoginView):
@ -21,6 +26,15 @@ class TwitterLogin(SocialLoginView):
serializer_class = TwitterLoginSerializer serializer_class = TwitterLoginSerializer
class FacebookConnect(SocialConnectView):
adapter_class = FacebookOAuth2Adapter
class TwitterConnect(SocialConnectView):
adapter_class = TwitterOAuthAdapter
serializer_class = TwitterConnectSerializer
class TwitterLoginSerializerFoo(TwitterLoginSerializer): class TwitterLoginSerializerFoo(TwitterLoginSerializer):
pass pass
@ -49,5 +63,10 @@ urlpatterns += [
url(r'^social-login/twitter/$', TwitterLogin.as_view(), name='tw_login'), url(r'^social-login/twitter/$', TwitterLogin.as_view(), name='tw_login'),
url(r'^social-login/twitter-no-view/$', twitter_login_view, name='tw_login_no_view'), url(r'^social-login/twitter-no-view/$', twitter_login_view, name='tw_login_no_view'),
url(r'^social-login/twitter-no-adapter/$', TwitterLoginNoAdapter.as_view(), name='tw_login_no_adapter'), url(r'^social-login/twitter-no-adapter/$', TwitterLoginNoAdapter.as_view(), name='tw_login_no_adapter'),
url(r'^social-login/facebook/connect/$', FacebookConnect.as_view(), name='fb_connect'),
url(r'^social-login/twitter/connect/$', TwitterConnect.as_view(), name='tw_connect'),
url(r'^socialaccounts/$', SocialAccountListView.as_view(), name='social_account_list'),
url(r'^socialaccounts/(?P<pk>\d+)/disconnect/$', SocialAccountDisconnectView.as_view(),
name='social_account_disconnect'),
url(r'^accounts/', include('allauth.socialaccount.urls')) url(r'^accounts/', include('allauth.socialaccount.urls'))
] ]

View File

@ -20,7 +20,7 @@ def jwt_encode(user):
try: try:
from rest_framework_jwt.settings import api_settings from rest_framework_jwt.settings import api_settings
except ImportError: except ImportError:
raise ImportError('rest_framework_jwt needs to be installed') raise ImportError("djangorestframework_jwt needs to be installed")
jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER

View File

@ -3,17 +3,17 @@ from django.contrib.auth import (
logout as django_logout logout as django_logout
) )
from django.conf import settings from django.conf import settings
from django.contrib.auth import get_user_model
from django.core.exceptions import ObjectDoesNotExist from django.core.exceptions import ObjectDoesNotExist
from django.utils.decorators import method_decorator
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.views.decorators.debug import sensitive_post_parameters
from rest_framework import status from rest_framework import status
from rest_framework.views import APIView from rest_framework.views import APIView
from rest_framework.response import Response from rest_framework.response import Response
from rest_framework.generics import GenericAPIView from rest_framework.generics import GenericAPIView, RetrieveUpdateAPIView
from rest_framework.permissions import IsAuthenticated, AllowAny from rest_framework.permissions import IsAuthenticated, AllowAny
from rest_framework.generics import RetrieveUpdateAPIView
from allauth.account import app_settings as allauth_settings
from .app_settings import ( from .app_settings import (
TokenSerializer, UserDetailsSerializer, LoginSerializer, TokenSerializer, UserDetailsSerializer, LoginSerializer,
@ -21,12 +21,16 @@ from .app_settings import (
PasswordChangeSerializer, JWTSerializer, create_token PasswordChangeSerializer, JWTSerializer, create_token
) )
from .models import TokenModel from .models import TokenModel
from .utils import jwt_encode from .utils import jwt_encode
sensitive_post_parameters_m = method_decorator(
sensitive_post_parameters(
'password', 'old_password', 'new_password1', 'new_password2'
)
)
class LoginView(GenericAPIView): class LoginView(GenericAPIView):
""" """
Check the credentials and return the REST Token Check the credentials and return the REST Token
if the credentials are valid and authenticated. if the credentials are valid and authenticated.
@ -40,6 +44,10 @@ class LoginView(GenericAPIView):
serializer_class = LoginSerializer serializer_class = LoginSerializer
token_model = TokenModel token_model = TokenModel
@sensitive_post_parameters_m
def dispatch(self, *args, **kwargs):
return super(LoginView, self).dispatch(*args, **kwargs)
def process_login(self): def process_login(self):
django_login(self.request, self.user) django_login(self.request, self.user)
@ -56,7 +64,8 @@ class LoginView(GenericAPIView):
if getattr(settings, 'REST_USE_JWT', False): if getattr(settings, 'REST_USE_JWT', False):
self.token = jwt_encode(self.user) self.token = jwt_encode(self.user)
else: else:
self.token = create_token(self.token_model, self.user, self.serializer) self.token = create_token(self.token_model, self.user,
self.serializer)
if getattr(settings, 'REST_SESSION_LOGIN', True): if getattr(settings, 'REST_SESSION_LOGIN', True):
self.process_login() self.process_login()
@ -69,15 +78,28 @@ class LoginView(GenericAPIView):
'user': self.user, 'user': self.user,
'token': self.token 'token': self.token
} }
serializer = serializer_class(instance=data, context={'request': self.request}) serializer = serializer_class(instance=data,
context={'request': self.request})
else: else:
serializer = serializer_class(instance=self.token, context={'request': self.request}) serializer = serializer_class(instance=self.token,
context={'request': self.request})
return Response(serializer.data, status=status.HTTP_200_OK) response = Response(serializer.data, status=status.HTTP_200_OK)
if getattr(settings, 'REST_USE_JWT', False):
from rest_framework_jwt.settings import api_settings as jwt_settings
if jwt_settings.JWT_AUTH_COOKIE:
from datetime import datetime
expiration = (datetime.utcnow() + jwt_settings.JWT_EXPIRATION_DELTA)
response.set_cookie(jwt_settings.JWT_AUTH_COOKIE,
self.token,
expires=expiration,
httponly=True)
return response
def post(self, request, *args, **kwargs): def post(self, request, *args, **kwargs):
self.request = request self.request = request
self.serializer = self.get_serializer(data=self.request.data) self.serializer = self.get_serializer(data=self.request.data,
context={'request': request})
self.serializer.is_valid(raise_exception=True) self.serializer.is_valid(raise_exception=True)
self.login() self.login()
@ -85,7 +107,6 @@ class LoginView(GenericAPIView):
class LogoutView(APIView): class LogoutView(APIView):
""" """
Calls Django logout method and delete the Token object Calls Django logout method and delete the Token object
assigned to the current User object. assigned to the current User object.
@ -95,17 +116,14 @@ class LogoutView(APIView):
permission_classes = (AllowAny,) permission_classes = (AllowAny,)
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
try: if getattr(settings, 'ACCOUNT_LOGOUT_ON_GET', False):
if allauth_settings.LOGOUT_ON_GET: response = self.logout(request)
response = self.logout(request) else:
else: response = self.http_method_not_allowed(request, *args, **kwargs)
response = self.http_method_not_allowed(request, *args, **kwargs)
except Exception as exc:
response = self.handle_exception(exc)
return self.finalize_response(request, response, *args, **kwargs) return self.finalize_response(request, response, *args, **kwargs)
def post(self, request): def post(self, request, *args, **kwargs):
return self.logout(request) return self.logout(request)
def logout(self, request): def logout(self, request):
@ -113,22 +131,28 @@ class LogoutView(APIView):
request.user.auth_token.delete() request.user.auth_token.delete()
except (AttributeError, ObjectDoesNotExist): except (AttributeError, ObjectDoesNotExist):
pass pass
if getattr(settings, 'REST_SESSION_LOGIN', True):
django_logout(request)
django_logout(request) response = Response({"detail": _("Successfully logged out.")},
status=status.HTTP_200_OK)
return Response({"success": _("Successfully logged out.")}, if getattr(settings, 'REST_USE_JWT', False):
status=status.HTTP_200_OK) from rest_framework_jwt.settings import api_settings as jwt_settings
if jwt_settings.JWT_AUTH_COOKIE:
response.delete_cookie(jwt_settings.JWT_AUTH_COOKIE)
return response
class UserDetailsView(RetrieveUpdateAPIView): class UserDetailsView(RetrieveUpdateAPIView):
""" """
Returns User's details in JSON format. Reads and updates UserModel fields
Accepts GET, PUT, PATCH methods.
Accepts the following GET parameters: token Default accepted fields: username, first_name, last_name
Accepts the following POST parameters: Default display fields: pk, username, email, first_name, last_name
Required: token Read-only fields: pk, email
Optional: email, first_name, last_name and UserProfile fields
Returns the updated UserProfile and/or User object. Returns UserModel fields.
""" """
serializer_class = UserDetailsSerializer serializer_class = UserDetailsSerializer
permission_classes = (IsAuthenticated,) permission_classes = (IsAuthenticated,)
@ -136,16 +160,22 @@ class UserDetailsView(RetrieveUpdateAPIView):
def get_object(self): def get_object(self):
return self.request.user return self.request.user
def get_queryset(self):
"""
Adding this method since it is sometimes called when using
django-rest-swagger
https://github.com/Tivix/django-rest-auth/issues/275
"""
return get_user_model().objects.none()
class PasswordResetView(GenericAPIView): class PasswordResetView(GenericAPIView):
""" """
Calls Django Auth PasswordResetForm save method. Calls Django Auth PasswordResetForm save method.
Accepts the following POST parameters: email Accepts the following POST parameters: email
Returns the success/fail message. Returns the success/fail message.
""" """
serializer_class = PasswordResetSerializer serializer_class = PasswordResetSerializer
permission_classes = (AllowAny,) permission_classes = (AllowAny,)
@ -157,28 +187,34 @@ class PasswordResetView(GenericAPIView):
serializer.save() serializer.save()
# Return the success message with OK HTTP status # Return the success message with OK HTTP status
return Response( return Response(
{"success": _("Password reset e-mail has been sent.")}, {"detail": _("Password reset e-mail has been sent.")},
status=status.HTTP_200_OK status=status.HTTP_200_OK
) )
class PasswordResetConfirmView(GenericAPIView): class PasswordResetConfirmView(GenericAPIView):
""" """
Password reset e-mail link is confirmed, therefore this resets the user's password. Password reset e-mail link is confirmed, therefore
this resets the user's password.
Accepts the following POST parameters: new_password1, new_password2 Accepts the following POST parameters: token, uid,
Accepts the following Django URL arguments: token, uid new_password1, new_password2
Returns the success/fail message. Returns the success/fail message.
""" """
serializer_class = PasswordResetConfirmSerializer serializer_class = PasswordResetConfirmSerializer
permission_classes = (AllowAny,) permission_classes = (AllowAny,)
def post(self, request): @sensitive_post_parameters_m
def dispatch(self, *args, **kwargs):
return super(PasswordResetConfirmView, self).dispatch(*args, **kwargs)
def post(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data) serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True) serializer.is_valid(raise_exception=True)
serializer.save() serializer.save()
return Response({"success": _("Password has been reset with the new password.")}) return Response(
{"detail": _("Password has been reset with the new password.")}
)
class PasswordChangeView(GenericAPIView): class PasswordChangeView(GenericAPIView):
@ -188,12 +224,15 @@ class PasswordChangeView(GenericAPIView):
Accepts the following POST parameters: new_password1, new_password2 Accepts the following POST parameters: new_password1, new_password2
Returns the success/fail message. Returns the success/fail message.
""" """
serializer_class = PasswordChangeSerializer serializer_class = PasswordChangeSerializer
permission_classes = (IsAuthenticated,) permission_classes = (IsAuthenticated,)
def post(self, request): @sensitive_post_parameters_m
def dispatch(self, *args, **kwargs):
return super(PasswordChangeView, self).dispatch(*args, **kwargs)
def post(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data) serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True) serializer.is_valid(raise_exception=True)
serializer.save() serializer.save()
return Response({"success": _("New password has been saved.")}) return Response({"detail": _("New password has been saved.")})

View File

@ -1,8 +1,21 @@
# .coveragerc to control coverage.py [bdist_wheel]
[run] universal = 1
[metadata]
license_file = LICENSE
[flake8]
max-line-length = 120
exclude = docs/*,demo/*
ignore = F403
[coverage:run]
omit=*site-packages*,*distutils*,*migrations* omit=*site-packages*,*distutils*,*migrations*
[report] [coverage:report]
# Regexes for lines to exclude from consideration # Regexes for lines to exclude from consideration
exclude_lines = exclude_lines =
# Have to re-enable the standard pragma # Have to re-enable the standard pragma
@ -22,5 +35,5 @@ exclude_lines =
ignore_errors = True ignore_errors = True
[html] [coverage:html]
directory = coverage_html directory = coverage_html

View File

@ -1,14 +1,8 @@
#!/usr/bin/env python #!/usr/bin/env python
try:
from setuptools import setup, find_packages
except ImportError:
from ez_setup import use_setuptools
use_setuptools()
from setuptools import setup, find_packages
import os import os
from setuptools import setup, find_packages
here = os.path.dirname(os.path.abspath(__file__)) here = os.path.dirname(os.path.abspath(__file__))
f = open(os.path.join(here, 'README.rst')) f = open(os.path.join(here, 'README.rst'))
@ -18,7 +12,7 @@ f.close()
setup( setup(
name='django-rest-auth', name='django-rest-auth',
version='0.8.0', version='0.9.5',
author='Sumit Chachra', author='Sumit Chachra',
author_email='chachra@tivix.com', author_email='chachra@tivix.com',
url='http://github.com/Tivix/django-rest-auth', url='http://github.com/Tivix/django-rest-auth',
@ -29,7 +23,7 @@ setup(
zip_safe=False, zip_safe=False,
install_requires=[ install_requires=[
'Django>=1.8.0', 'Django>=1.8.0',
'djangorestframework>=3.1.0', 'djangorestframework>=3.1.3',
'six>=1.9.0', 'six>=1.9.0',
], ],
extras_require={ extras_require={
@ -38,10 +32,10 @@ setup(
tests_require=[ tests_require=[
'responses>=0.5.0', 'responses>=0.5.0',
'django-allauth>=0.25.0', 'django-allauth>=0.25.0',
'djangorestframework-jwt>=1.9.0',
], ],
test_suite='runtests.runtests', test_suite='runtests.runtests',
include_package_data=True, include_package_data=True,
# cmdclass={},
classifiers=[ classifiers=[
'Framework :: Django', 'Framework :: Django',
'Intended Audience :: Developers', 'Intended Audience :: Developers',