Eww, hard to sum up…
- Update django-allauth-cas to the last version. - Add docs (README, example/README). - Add tests for Clipper provider. - Add tests to check templates do not contain syntax error. - Add the last missing templates to override all allauth's displayable templates. - Improve stylesheets.
This commit is contained in:
parent
4cdbb049df
commit
fe21f9c6af
58 changed files with 1304 additions and 4566 deletions
5
CHANGELOG.rst
Normal file
5
CHANGELOG.rst
Normal file
|
@ -0,0 +1,5 @@
|
|||
******************
|
||||
1.0.0 (unreleased)
|
||||
******************
|
||||
|
||||
- First official release.
|
1
Gemfile
1
Gemfile
|
@ -2,4 +2,3 @@
|
|||
source "https://rubygems.org"
|
||||
|
||||
gem 'compass'
|
||||
gem 'font-awesome-sass', :git => "https://github.com/TruePath/font-awesome-sass.git", :branch => "patch-1"
|
||||
|
|
13
Gemfile.lock
13
Gemfile.lock
|
@ -1,11 +1,3 @@
|
|||
GIT
|
||||
remote: https://github.com/TruePath/font-awesome-sass.git
|
||||
revision: b3974fe0632d09a7744c4a3b42f4ccf8dc9f919e
|
||||
branch: patch-1
|
||||
specs:
|
||||
font-awesome-sass (4.7.0)
|
||||
sass (>= 3.2)
|
||||
|
||||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
|
@ -23,7 +15,7 @@ GEM
|
|||
compass-import-once (1.0.5)
|
||||
sass (>= 3.2, < 3.5)
|
||||
ffi (1.9.18)
|
||||
multi_json (1.12.1)
|
||||
multi_json (1.12.2)
|
||||
rb-fsevent (0.10.2)
|
||||
rb-inotify (0.9.10)
|
||||
ffi (>= 0.5.0, < 2)
|
||||
|
@ -34,7 +26,6 @@ PLATFORMS
|
|||
|
||||
DEPENDENCIES
|
||||
compass
|
||||
font-awesome-sass!
|
||||
|
||||
BUNDLED WITH
|
||||
1.15.3
|
||||
1.16.1
|
||||
|
|
259
README.rst
259
README.rst
|
@ -1,8 +1,259 @@
|
|||
==================
|
||||
##################
|
||||
django-allauth-ens
|
||||
==================
|
||||
##################
|
||||
|
||||
Providers for django-allauth_ allowing using the ENS' auth-systems.
|
||||
This package is meant to ease the management of authentication of django-apps
|
||||
at the ENS.
|
||||
|
||||
On top of django-allauth_, which provides easy ways to configure the
|
||||
authentication of django-apps, this package provides:
|
||||
|
||||
* social authentication using Clipper (*cas.eleves*);
|
||||
|
||||
* ready-to-use templates in replacement of allauth' ones;
|
||||
|
||||
* helpers to use *allauth*'s login and logout views instead of those
|
||||
provided by third-parties (Django admin, wagtail, *etc*).
|
||||
|
||||
|
||||
.. _django-allauth: https://www.intenct.nl/projects/django-allauth/
|
||||
**Contents**
|
||||
|
||||
.. contents:: :local:
|
||||
|
||||
|
||||
************
|
||||
Installation
|
||||
************
|
||||
|
||||
First, `install django-allauth`_.
|
||||
|
||||
Then, install *django-allauth-ens*:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ pip install django-allauth-ens
|
||||
|
||||
And edit your settings file:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
INSTALLED_APPS = [
|
||||
# …
|
||||
|
||||
# Above allauth to replace its templates.
|
||||
'allauth_ens',
|
||||
|
||||
# Added when you installed allauth.
|
||||
'allauth',
|
||||
'allauth.account',
|
||||
'allauth.socialaccount',
|
||||
|
||||
# Required to use CAS-based providers (e.g. Clipper).
|
||||
'allauth_cas',
|
||||
|
||||
# …
|
||||
]
|
||||
|
||||
|
||||
*************
|
||||
Configuration
|
||||
*************
|
||||
|
||||
See also the `allauth configuration`_ and `advanced usage`_ docs pages.
|
||||
|
||||
``ACCOUNT_HOME_URL``
|
||||
*Optional* — A view name or an url path.
|
||||
|
||||
Used as a link from the templates of ``allauth_ens`` to return to your
|
||||
application.
|
||||
|
||||
**Examples:** ``'home'``, ``'/home/'``
|
||||
|
||||
``ACCOUNT_DETAILS_URL``
|
||||
*Optional* — A view name or an url path.
|
||||
|
||||
Used as a link from the templates of ``allauth_ens`` for a logged in user to
|
||||
access their profile in your app.
|
||||
|
||||
**Examples:** ``'my-account'``, ``'/my-account/'``
|
||||
|
||||
*****
|
||||
Views
|
||||
*****
|
||||
|
||||
Capture other login and logout views
|
||||
====================================
|
||||
|
||||
You can use the ``capture_login`` and ``capture_logout`` views to replace the
|
||||
login and logout views of other applications. They redirect to their similar
|
||||
*allauth*'s view and forward the query string, so that if a GET parameter
|
||||
``next`` is given along the initial request, user is redirected to this url on
|
||||
successful login and logout.
|
||||
|
||||
This requires to add urls before the include of the app' urls.
|
||||
|
||||
For example, to replace the Django admin login and logout views with allauth's
|
||||
ones:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from allauth_ens.views import capture_login, capture_logout
|
||||
|
||||
urlpatterns = [
|
||||
# …
|
||||
|
||||
# Add it before include of admin urls.
|
||||
url(r'^admin/login/$', capture_login),
|
||||
url(r'^admin/logout/$', capture_logout),
|
||||
|
||||
url(r'^admin/$', include(admin.site.urls)),
|
||||
|
||||
# …
|
||||
]
|
||||
|
||||
|
||||
*********
|
||||
Templates
|
||||
*********
|
||||
|
||||
The templates provided by *allauth* only contains the bare minimum. Hopefully,
|
||||
this package includes ready-to-use templates. They are automatically used if
|
||||
you put ``'allauth_ens'`` before ``'allauth'`` in your ``INSTALLED_APPS``,
|
||||
|
||||
|
||||
*********
|
||||
Providers
|
||||
*********
|
||||
|
||||
*Google, Facebook¸ but also Clipper…*
|
||||
|
||||
To interact with an external authentication service, you must add the
|
||||
corresponding provider application to your ``INSTALLED_APPS``.
|
||||
|
||||
*allauth* already includes `several providers`_ (see also `their python path`_).
|
||||
In addition to that, this package adds the following providers:
|
||||
|
||||
Clipper
|
||||
=======
|
||||
|
||||
It uses the CAS server `<https://cas.eleves.ens.fr/>`_.
|
||||
|
||||
Installation
|
||||
Add ``'allauth_ens.providers.clipper'`` to the ``INSTALLED_APPS``.
|
||||
|
||||
Configuration
|
||||
Available settings and their default value:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
SOCIALACCOUNT_PROVIDERS = {
|
||||
# …
|
||||
|
||||
'clipper': {
|
||||
|
||||
# These settings control whether a message containing a link to
|
||||
# disconnect from the CAS server is added when users log out.
|
||||
'MESSAGE_SUGGEST_LOGOUT_ON_LOGOUT': True,
|
||||
'MESSAGE_SUGGEST_LOGOUT_ON_LOGOUT_LEVEL': messages.INFO,
|
||||
|
||||
},
|
||||
}
|
||||
|
||||
Auto-signup
|
||||
Poulated data
|
||||
- username: ``<clipper>``
|
||||
- email (primary and verified): ``<clipper>@clipper.ens.fr``
|
||||
|
||||
|
||||
*********
|
||||
Demo Site
|
||||
*********
|
||||
|
||||
See ``example/README``.
|
||||
|
||||
|
||||
***********
|
||||
Development
|
||||
***********
|
||||
|
||||
First, you need to clone the repository.
|
||||
|
||||
Stylesheets
|
||||
===========
|
||||
|
||||
This project uses `compass`_ to compile SCSS files to CSS.
|
||||
|
||||
Using bundler
|
||||
-------------
|
||||
|
||||
Requirements
|
||||
* Ensure Ruby is installed (``$ ruby -v``) or `install Ruby`_
|
||||
* Ensure bundler is installed (``$ bundle -v``) or install bundler
|
||||
(``$ gem install bundler``)
|
||||
* Install dependencies: ``$ bundle install``
|
||||
|
||||
Compile
|
||||
* Watch changes and recompile: ``$ bundle exec compass watch``
|
||||
|
||||
Tests
|
||||
=====
|
||||
|
||||
Local environment
|
||||
-----------------
|
||||
|
||||
``$ ./runtests.py``
|
||||
|
||||
All
|
||||
---
|
||||
|
||||
Requirements
|
||||
* tox, install with ``$ pip install tox``
|
||||
* ``python{2.7,3.4,3.5,3.6}`` must be available on your system path
|
||||
|
||||
Run
|
||||
* all (django/python with combined coverage + flake8 + isort): ``$ tox``
|
||||
|
||||
|
||||
******
|
||||
Howtos
|
||||
******
|
||||
|
||||
Assuming you use the following settings (when needed):
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
ACCOUNT_ADAPTER = 'shared.allauth_adapter.AccountAdapter'
|
||||
SOCIALACCOUNT_ADAPTER = 'shared.allauth_adapter.SocialAccountAdapter'
|
||||
|
||||
Signup disabled, except for clipper provider (auto-signup)
|
||||
==========================================================
|
||||
|
||||
In ``shared/allauth_adapter.py``:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
class AccountAdapter(DefaultAccountAdapter):
|
||||
def is_open_for_signup(self, request):
|
||||
return False
|
||||
|
||||
class SocialAccountAdapter(DefaultSocialAccountAdapter):
|
||||
def is_open_for_signup(self, request, sociallogin):
|
||||
# sociallogin.account is a SocialAccount instance.
|
||||
# See https://github.com/pennersr/django-allauth/blob/master/allauth/socialaccount/models.py
|
||||
|
||||
if sociallogin.account.provider == 'clipper':
|
||||
return True
|
||||
|
||||
# It returns AccountAdapter.is_open_for_signup().
|
||||
# See https://github.com/pennersr/django-allauth/blob/master/allauth/socialaccount/adapter.py
|
||||
return super().is_open_for_signup(request, sociallogin)
|
||||
|
||||
|
||||
.. _django-allauth: https://django-allauth.readthedocs.io/en/latest/overview.html
|
||||
.. _install django-allauth: https://django-allauth.readthedocs.io/en/latest/installation.html
|
||||
.. _several providers: https://django-allauth.readthedocs.io/en/latest/providers.html
|
||||
.. _allauth configuration: https://django-allauth.readthedocs.io/en/latest/configuration.html
|
||||
.. _advanced usage: https://django-allauth.readthedocs.io/en/latest/advanced.html
|
||||
.. _their python path: https://django-allauth.readthedocs.io/en/latest/installation.html
|
||||
.. _compass: https://compass-style.org/
|
||||
.. _install Ruby: https://www.ruby-lang.org/en/documentation/installation/
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
__version__ = '0.0.1.dev1'
|
||||
|
||||
default_app_config = 'allauth_ens.apps.ENSAllauthAppConfig'
|
||||
default_app_config = 'allauth_ens.apps.ENSAllauthConfig'
|
||||
|
|
|
@ -2,6 +2,6 @@ from django.apps import AppConfig
|
|||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
|
||||
class ENSAllauthAppConfig(AppConfig):
|
||||
class ENSAllauthConfig(AppConfig):
|
||||
name = 'allauth_ens'
|
||||
verbose_name = _("ENS Authentication")
|
||||
|
|
|
@ -15,8 +15,8 @@ class ClipperProvider(CASProvider):
|
|||
account_class = ClipperAccount
|
||||
|
||||
def extract_email(self, data):
|
||||
username, _, _ = data
|
||||
return '{}@clipper.ens.fr'.format(username)
|
||||
uid, extra = data
|
||||
return '{}@clipper.ens.fr'.format(uid.strip().lower())
|
||||
|
||||
def extract_common_fields(self, data):
|
||||
common = super(ClipperProvider, self).extract_common_fields(data)
|
||||
|
@ -24,20 +24,23 @@ class ClipperProvider(CASProvider):
|
|||
return common
|
||||
|
||||
def extract_email_addresses(self, data):
|
||||
email = self.extract_email(data)
|
||||
return [
|
||||
EmailAddress(
|
||||
email=email,
|
||||
verified=True,
|
||||
primary=True,
|
||||
)
|
||||
email=self.extract_email(data),
|
||||
verified=True, primary=True,
|
||||
),
|
||||
]
|
||||
|
||||
def extract_extra_data(self, data):
|
||||
extra = super(ClipperProvider, self).extract_extra_data(data)
|
||||
extra['username'] = data[0]
|
||||
extra['email'] = self.extract_email(data)
|
||||
return extra
|
||||
extra_data = super(ClipperProvider, self).extract_extra_data(data)
|
||||
extra_data['email'] = self.extract_email(data)
|
||||
return extra_data
|
||||
|
||||
def message_suggest_caslogout_on_logout(self, request):
|
||||
return (
|
||||
self.get_settings()
|
||||
.get('MESSAGE_SUGGEST_CASLOGOUT_ON_LOGOUT', True)
|
||||
)
|
||||
|
||||
|
||||
provider_classes = [ClipperProvider]
|
||||
|
|
|
@ -1,4 +1,21 @@
|
|||
from allauth_cas.test.testcases import CASViewTestCase
|
||||
from django.contrib.auth import get_user_model
|
||||
|
||||
from allauth_cas.test.testcases import CASTestCase, CASViewTestCase
|
||||
|
||||
User = get_user_model()
|
||||
|
||||
|
||||
class ClipperProviderTests(CASTestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.u = User.objects.create_user('user', 'user@mail.net', 'user')
|
||||
|
||||
def test_auto_signup(self):
|
||||
self.client_cas_login(
|
||||
self.client, provider_id='clipper', username='clipper_uid')
|
||||
|
||||
u = User.objects.get(username='clipper_uid')
|
||||
self.assertEqual(u.email, 'clipper_uid@clipper.ens.fr')
|
||||
|
||||
|
||||
class ClipperViewsTests(CASViewTestCase):
|
||||
|
@ -15,6 +32,10 @@ class ClipperViewsTests(CASViewTestCase):
|
|||
)
|
||||
|
||||
def test_callback_view(self):
|
||||
# Required to initialize a SocialLogin.
|
||||
r = self.client.get('/accounts/clipper/login/')
|
||||
|
||||
# Tests.
|
||||
self.patch_cas_response(valid_ticket='__all__')
|
||||
r = self.client.get('/accounts/clipper/login/callback/', {
|
||||
'ticket': '123456',
|
||||
|
|
|
@ -27,16 +27,14 @@ b {
|
|||
* Layout structure *
|
||||
********************/
|
||||
|
||||
$main-max-width: 700px;
|
||||
|
||||
$divider-size: 2px;
|
||||
$main-max-width: 500px;
|
||||
|
||||
.wrapper {
|
||||
max-width: $main-max-width;
|
||||
margin: 0 auto;
|
||||
|
||||
background: $white;
|
||||
box-shadow: 0 0 10px $gray-lighter;
|
||||
box-shadow: 0 0 5px rgba(0,0,0,.1);
|
||||
|
||||
}
|
||||
|
||||
|
@ -65,49 +63,24 @@ $divider-size: 2px;
|
|||
padding: 15px;
|
||||
}
|
||||
|
||||
@media (min-width: 576px) {
|
||||
@media (min-width: 500px) {
|
||||
& > section {
|
||||
flex: 1 1 auto;
|
||||
width: 350px - $divider-size / 2;
|
||||
width: 250px;
|
||||
}
|
||||
}
|
||||
|
||||
/* Divider */
|
||||
|
||||
& > .divider {
|
||||
display: none;
|
||||
|
||||
&::before {
|
||||
display: block;
|
||||
content: " ";
|
||||
background: $gray-lighter;
|
||||
|
||||
height: $divider-size;
|
||||
width: $divider-size;
|
||||
}
|
||||
|
||||
@media (max-width: 575px) {
|
||||
& {
|
||||
flex: 100%;
|
||||
padding: 0 15px;
|
||||
}
|
||||
|
||||
&::before { width: 100%; }
|
||||
}
|
||||
|
||||
@media (min-width: 576px) {
|
||||
& {
|
||||
align-self: stretch;
|
||||
padding: 15px 0;
|
||||
}
|
||||
|
||||
&::before { height: 100%; }
|
||||
@media (min-width: 120px) {
|
||||
& > section {
|
||||
flex: 1 1 auto;
|
||||
width: 350px;
|
||||
}
|
||||
}
|
||||
|
||||
& > section + .divider {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
#providers {
|
||||
width:150px;
|
||||
}
|
||||
|
||||
|
||||
|
@ -132,23 +105,6 @@ header {
|
|||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
|
||||
.history-back {
|
||||
@include transition;
|
||||
|
||||
width: 55px;
|
||||
cursor: pointer;
|
||||
|
||||
background: transparent;
|
||||
|
||||
color: $white;
|
||||
font-size: $header-history-icon-size;
|
||||
|
||||
@include hover-focus {
|
||||
background: lighten($header-bg, 5%);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
a {
|
||||
color: $white !important;
|
||||
|
||||
|
@ -159,42 +115,41 @@ header {
|
|||
}
|
||||
|
||||
.right {
|
||||
border-left: 1px solid lighten($header-bg, 15%);
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
align-items: stretch;
|
||||
justify-content: space-around;
|
||||
|
||||
flex: 0 0 auto;
|
||||
border-left: 1px solid lighten($header-bg, 15%);
|
||||
|
||||
font-size: 14px;
|
||||
|
||||
text-align: center;
|
||||
|
||||
& > * {
|
||||
flex: 0 0 auto;
|
||||
line-height: 28px;
|
||||
|
||||
& > * {
|
||||
display: block;
|
||||
padding: 5px 10px;
|
||||
}
|
||||
}
|
||||
|
||||
& > * > * {
|
||||
display: inline-block;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
padding: 0 15px;
|
||||
}
|
||||
|
||||
& #connect-status {
|
||||
#connect-status {
|
||||
font-weight: normal;
|
||||
font-size: 12px;
|
||||
|
||||
.fa {
|
||||
margin-right: 10px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
h1 {
|
||||
flex: 1 0 auto;
|
||||
flex: 1 1 auto;
|
||||
|
||||
padding: 15px 35px;
|
||||
line-height: 25px;
|
||||
padding: 15px 25px;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -252,128 +207,92 @@ section {
|
|||
|
||||
/* Methods list */
|
||||
|
||||
$space-between: 15px;
|
||||
|
||||
.method-list {
|
||||
display: flex;
|
||||
flex-flow: row wrap;
|
||||
justify-content: space-between;
|
||||
margin: - $space-between / 2;
|
||||
}
|
||||
|
||||
.method-wrapper {
|
||||
flex: 1 50%;
|
||||
padding: $space-between / 2;
|
||||
& > .method-wrapper {
|
||||
flex: 1 100%;
|
||||
padding: 2px 0;
|
||||
|
||||
a {
|
||||
@include btn;
|
||||
@include btn-primary-hov;
|
||||
display: block;
|
||||
a {
|
||||
@include btn;
|
||||
|
||||
border-radius: 0;
|
||||
border-left: 5px solid $brand-primary;
|
||||
|
||||
background: $gray-lighter;
|
||||
color: $black;
|
||||
font-size: 16px;
|
||||
text-align: left;
|
||||
|
||||
@include hover-focus {
|
||||
background: lighten($brand-primary, 50%);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Connected accounts list */
|
||||
|
||||
.provider-list {
|
||||
.connections-providers-list {
|
||||
|
||||
& > li {
|
||||
& > * {
|
||||
|
||||
&:not(:first-child) {
|
||||
margin-top: 5px;
|
||||
& + * {
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
& > .heading {
|
||||
@include clearfix;
|
||||
|
||||
height: 45px;
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
|
||||
background-color: $gray-lighter;
|
||||
border-left: 5px solid $brand-primary;
|
||||
background: $gray-lighter;
|
||||
|
||||
& > * {
|
||||
float: left;
|
||||
height: 100%;
|
||||
}
|
||||
.connect {
|
||||
@include btn;
|
||||
@include btn-primary;
|
||||
@include btn-sm;
|
||||
|
||||
& > .connect, & > .brand-icon {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
& > .connect a {
|
||||
@include transition;
|
||||
|
||||
display: inline-block;
|
||||
|
||||
background-color: $brand-success;
|
||||
color: $white;
|
||||
|
||||
height: 100%;
|
||||
line-height: 100%;
|
||||
width: 45px;
|
||||
|
||||
padding: 12px;
|
||||
|
||||
font-size: 20px;
|
||||
text-align: center;
|
||||
|
||||
@include hover-focus {
|
||||
background-color: darken($brand-success, 5%);
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
|
||||
& > .brand-icon {
|
||||
padding: 10px;
|
||||
width: 45px;
|
||||
color: $brand-primary;
|
||||
}
|
||||
|
||||
& > .name {
|
||||
padding: 10px;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
& > .connected-list {
|
||||
|
||||
padding: 0 15px;
|
||||
|
||||
& > li {
|
||||
@include clearfix;
|
||||
|
||||
height: 30px;
|
||||
|
||||
& > * {
|
||||
float: left;
|
||||
display: block;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
& > .connected-delete [type=submit] {
|
||||
background-color: $red;
|
||||
color: $white;
|
||||
min-height: 30px;
|
||||
width: 30px;
|
||||
|
||||
@include hover-focus {
|
||||
background-color: darken($red, 5%);
|
||||
}
|
||||
}
|
||||
|
||||
& > .connected-label {
|
||||
padding: 7px 15px;
|
||||
width: calc(100% - 30px);
|
||||
border-bottom: 1px solid $red;
|
||||
|
||||
font-size: 12px;
|
||||
|
||||
.fa {
|
||||
margin-right: 5px;
|
||||
}
|
||||
}
|
||||
float: right;
|
||||
width: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.connections-list {
|
||||
border-left: 5px solid $gray-lightest;
|
||||
|
||||
& > * {
|
||||
padding: 10px;
|
||||
font-size: 14px;
|
||||
|
||||
& + * {
|
||||
border-top: 1px dotted $gray-lighter;
|
||||
}
|
||||
|
||||
& > .fa {
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.delete {
|
||||
float: right;
|
||||
margin-top: -2px;
|
||||
|
||||
& [type=submit] {
|
||||
@include btn;
|
||||
@include btn-danger;
|
||||
@include btn-sm;
|
||||
opacity: .8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
form {
|
||||
display: inline-block;
|
||||
}
|
||||
|
@ -412,7 +331,7 @@ $space-between: 15px;
|
|||
}
|
||||
|
||||
& > .primary {
|
||||
color: darken($brand-primary, 15%);
|
||||
color: $brand-primary;
|
||||
}
|
||||
|
||||
& > .verified {
|
||||
|
@ -424,19 +343,6 @@ $space-between: 15px;
|
|||
}
|
||||
}
|
||||
|
||||
.actions {
|
||||
@include clearfix;
|
||||
|
||||
margin-bottom: 10px;
|
||||
|
||||
& > * {
|
||||
float: right;
|
||||
margin-right: 10px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -557,9 +463,9 @@ $label-top: $label-height + $input-wrapper-padding + $input-padding;
|
|||
}
|
||||
}
|
||||
|
||||
@include input-special('has-value', $green);
|
||||
@include input-special('error', $red);
|
||||
@include input-special('focused', $blue);
|
||||
@include input-special('has-value', $brand-success);
|
||||
@include input-special('error', $brand-danger);
|
||||
@include input-special('focused', $brand-primary);
|
||||
|
||||
.infos-spacer {
|
||||
float: right;
|
||||
|
@ -577,16 +483,47 @@ $label-top: $label-height + $input-wrapper-padding + $input-padding;
|
|||
|
||||
}
|
||||
|
||||
.widget-checkbox {
|
||||
display: inline-flex;
|
||||
|
||||
& > input[type="checkbox"] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
& > button {
|
||||
@include transition;
|
||||
flex: 0 1 auto;
|
||||
display: inline-block;
|
||||
padding: 5px 10px;
|
||||
background: white;
|
||||
color: $gray-light;
|
||||
}
|
||||
|
||||
& > button.choice-yes {
|
||||
border-top-left-radius: 3px;
|
||||
border-bottom-left-radius: 3px;
|
||||
}
|
||||
|
||||
& > button.choice-no {
|
||||
border-top-right-radius: 3px;
|
||||
border-bottom-right-radius: 3px;
|
||||
}
|
||||
|
||||
& > button.focus {
|
||||
background: $brand-primary;
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
|
||||
[type=submit]:not(.link) {
|
||||
@include btn;
|
||||
@include btn-success-hov;
|
||||
float: right;
|
||||
@include btn-success;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
[type=submit].link {
|
||||
@include link;
|
||||
background: transparent;
|
||||
padding: 0;
|
||||
|
||||
@include hover-focus {
|
||||
cursor: pointer;
|
||||
|
@ -595,13 +532,15 @@ $label-top: $label-height + $input-wrapper-padding + $input-padding;
|
|||
|
||||
.form-inline {
|
||||
display: flex;
|
||||
flex-flow: row nowrap;
|
||||
align-items: center;
|
||||
|
||||
.input-list {
|
||||
& > .input-wrapper {
|
||||
flex: 1 0 auto;
|
||||
}
|
||||
|
||||
[type=submit] {
|
||||
margin-top: -5px;
|
||||
margin-left: 8px;
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
|
@ -611,6 +550,5 @@ $label-top: $label-height + $input-wrapper-padding + $input-padding;
|
|||
display: block;
|
||||
}
|
||||
|
||||
.btn-primary-hov {
|
||||
@include btn-primary-hov;
|
||||
}
|
||||
.btn-primary { @include btn-primary; }
|
||||
.btn-success { @include btn-success; }
|
||||
|
|
|
@ -30,8 +30,8 @@
|
|||
}
|
||||
}
|
||||
|
||||
@mixin transition($time: .3s) {
|
||||
transition: background $time, color $time;
|
||||
@mixin transition($time: .15s) {
|
||||
transition: background $time, color $time, border-color $time;
|
||||
}
|
||||
|
||||
@mixin link {
|
||||
|
@ -50,13 +50,15 @@
|
|||
@mixin btn {
|
||||
@include transition;
|
||||
|
||||
//width: 100%;
|
||||
display: block;
|
||||
width: 100%;
|
||||
min-height: 30px;
|
||||
line-height: initial;
|
||||
|
||||
border: 0;
|
||||
padding: 10px 15px;
|
||||
border-radius: 3px;
|
||||
padding: 7px 15px;
|
||||
|
||||
font-family: "Roboto Slab";
|
||||
font-size: 18px;
|
||||
|
||||
text-align: center;
|
||||
|
@ -67,23 +69,38 @@
|
|||
}
|
||||
}
|
||||
|
||||
@mixin btn-primary-hov {
|
||||
color: $black;
|
||||
@mixin btn-primary {
|
||||
background: $brand-primary;
|
||||
color: $white;
|
||||
|
||||
@include hover-focus {
|
||||
background: darken($brand-primary, 15%);
|
||||
background: darken($brand-primary, 5%);
|
||||
color: $white;
|
||||
}
|
||||
}
|
||||
|
||||
@mixin btn-success-hov {
|
||||
background-color: $brand-success;
|
||||
@mixin btn-success {
|
||||
background: $brand-success;
|
||||
color: $white;
|
||||
//background: $gray-lighter;
|
||||
//color: $black;
|
||||
|
||||
@include hover-focus {
|
||||
background: darken($brand-success, 15%);
|
||||
color: $white;
|
||||
}
|
||||
}
|
||||
|
||||
@mixin btn-danger {
|
||||
background: $brand-danger;
|
||||
color: $white;
|
||||
|
||||
@include hover-focus {
|
||||
background: darken($brand-danger, 15%);
|
||||
color: $white;
|
||||
}
|
||||
}
|
||||
|
||||
@mixin btn-sm {
|
||||
min-height: auto;
|
||||
padding: 4px 7px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ a, input, button {
|
|||
}
|
||||
|
||||
input, button {
|
||||
padding: 0;
|
||||
border: 0;
|
||||
border-radius: 0;
|
||||
box-shadow: none;
|
||||
|
|
|
@ -17,10 +17,10 @@ $gray-light: #636c72 !default;
|
|||
$gray-lighter: #eceeef !default;
|
||||
$gray-lightest: #f7f7f9 !default;
|
||||
|
||||
$brand-primary: $blue !default;
|
||||
$brand-success: $green !default;
|
||||
$brand-primary: darken($blue, 10%) !default;
|
||||
$brand-success: darken($green, 10%) !default;
|
||||
$brand-info: $teal !default;
|
||||
$brand-warning: $orange !default;
|
||||
$brand-warning: darken($orange, 10%) !default;
|
||||
$brand-danger: $red !default;
|
||||
$brand-inverse: $gray-dark !default;
|
||||
|
||||
|
|
|
@ -1,16 +1,6 @@
|
|||
/* Welcome to Compass.
|
||||
* In this file you should write your main styles. (or centralize your imports)
|
||||
* Import this file using the following HTML or equivalent:
|
||||
* <link href="/stylesheets/screen.css" media="screen, projection" rel="stylesheet" type="text/css" /> */
|
||||
|
||||
// @import "vendor/normalize";
|
||||
// @import "reset";
|
||||
@import "compass/reset";
|
||||
@import "reset";
|
||||
|
||||
@import "font-awesome-compass";
|
||||
@import "font-awesome";
|
||||
|
||||
@import "variables";
|
||||
@import "mixins";
|
||||
|
||||
|
|
|
@ -40,18 +40,41 @@ Input.prototype = {
|
|||
}
|
||||
};
|
||||
|
||||
Object.assign(Input.prototype, {
|
||||
$.extend(Input.prototype, {
|
||||
update_focus: toggleWrapperClass('input-focused', Input.prototype.has_focus),
|
||||
update_error: toggleWrapperClass('input-error', Input.prototype.has_error),
|
||||
update_error: function () {
|
||||
let has_error = this.has_error();
|
||||
toggleWrapperClass('input-error').bind(this)(has_error);
|
||||
if (!has_error) {
|
||||
this.wrapper.find('.messages .error-desc').hide();
|
||||
}
|
||||
},
|
||||
update_has_value: toggleWrapperClass('input-has-value', Input.prototype.has_value),
|
||||
});
|
||||
|
||||
|
||||
$( function() {
|
||||
$(function () {
|
||||
let fields = $('input.field');
|
||||
fields.map( function() { return new Input(this); });
|
||||
});
|
||||
|
||||
$(function () {
|
||||
let choice_yes = $('.choice-yes');
|
||||
let choice_no = $('.choice-no');
|
||||
|
||||
choice_yes.click(function () {
|
||||
$(this).siblings('input').prop('checked', true);
|
||||
$(this).addClass('focus');
|
||||
$(this).siblings('.choice-no').removeClass('focus');
|
||||
});
|
||||
|
||||
choice_no.click(function () {
|
||||
$(this).siblings('input').prop('checked', true);
|
||||
$(this).addClass('focus');
|
||||
$(this).siblings('.choice-yes').removeClass('focus');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
/**
|
||||
* Keyboard shortcuts
|
||||
|
|
File diff suppressed because it is too large
Load diff
18
allauth_ens/templates/account/account_inactive.html
Normal file
18
allauth_ens/templates/account/account_inactive.html
Normal file
|
@ -0,0 +1,18 @@
|
|||
{% extends "allauth_ens/base.html" %}
|
||||
|
||||
{% load i18n %}
|
||||
|
||||
{% block header-title %}{% trans "Account Inactive" %}{% endblock %}
|
||||
{% block title %}{% trans "Account Inactive" %}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<section>
|
||||
<p>
|
||||
{% blocktrans %}
|
||||
This account is inactive.
|
||||
{% endblocktrans %}
|
||||
</p>
|
||||
</section>
|
||||
|
||||
{% endblock %}
|
|
@ -1,29 +0,0 @@
|
|||
{% load widget_tweaks %}
|
||||
|
||||
{% csrf_token %}
|
||||
<ul class="input-list">
|
||||
{% for field in form %}
|
||||
{% with field|field_type as type %}
|
||||
<li class="input-wrapper {% if type == "booleanfield" %}input-skip{% endif %}">
|
||||
{% if type == "booleanfield" %}
|
||||
<label for="{{ field.id_for_label }}">
|
||||
{{ field.label }}
|
||||
{% render_field field class+="field" %}
|
||||
</label>
|
||||
{% else %}
|
||||
<label for="{{ field.id_for_label }}">{{ field.label }}</label>
|
||||
{% render_field field class+="field" autocomplete="off" autocapitalize="none" placeholder="" %}
|
||||
{% endif %}
|
||||
<div class="infos-spacer"></div>
|
||||
<ul class="messages">
|
||||
{% if field.help_text %}
|
||||
<li>{{ field.help_text|safe }}</li>
|
||||
{% endif %}
|
||||
{% for error in field.errors %}
|
||||
<li>{{ error }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</li>
|
||||
{% endwith %}
|
||||
{% endfor %}
|
||||
</ul>
|
|
@ -1,4 +1,4 @@
|
|||
{% extends "account/base.html" %}
|
||||
{% extends "allauth_ens/base.html" %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block title %}{% trans "E-mail Addresses" %}{% endblock %}
|
||||
|
@ -97,7 +97,7 @@
|
|||
{% endif %}
|
||||
|
||||
<form action="{% url "account_email" %}" method="post" class="form-inline">
|
||||
{% include "account/block-form.html" with form=form %}
|
||||
{% include "allauth_ens/block-form.html" with form=form %}
|
||||
<button type="submit" class="link" name="action_add">{% trans "Add E-mail" %}</button>
|
||||
</form>
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
{% extends "account/base.html" %}
|
||||
{% extends "allauth_ens/base.html" %}
|
||||
{% load i18n %}
|
||||
{% load account %}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
{% extends "account/base.html" %}
|
||||
{% extends "allauth_ens/base.html" %}
|
||||
{% load i18n %}
|
||||
{% load account socialaccount allauth_ens %}
|
||||
|
||||
|
@ -7,25 +7,26 @@
|
|||
|
||||
{% block messages-extra %}
|
||||
{% if form.errors or user.is_authenticated %}
|
||||
<div class="messages-container">
|
||||
<ul class="messages-list">
|
||||
{% if form.errors %}
|
||||
<li class="message error">
|
||||
{% blocktrans %}
|
||||
Authentication failed. Please check your credentials and try again.
|
||||
{% endblocktrans %}
|
||||
</li>
|
||||
{% endif %}
|
||||
{% if user.is_authenticated %}
|
||||
<li class="message warning">
|
||||
{% blocktrans %}
|
||||
You are unauthorized to view this page. Please sign in with an account
|
||||
with the required permissions.
|
||||
{% endblocktrans %}
|
||||
</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</div>
|
||||
<div class="messages-container">
|
||||
<ul class="messages-list">
|
||||
{% if form.errors %}
|
||||
<li class="message error">
|
||||
{% blocktrans %}
|
||||
Authentication failed. Please check your credentials and try again.
|
||||
{% endblocktrans %}
|
||||
</li>
|
||||
{% endif %}
|
||||
{% if user.is_authenticated %}
|
||||
<li class="message warning">
|
||||
{% user_display user as user_str %}
|
||||
{% blocktrans %}
|
||||
Your are authenticated as {{ user_str }}, but are not authorized to access
|
||||
this page. Would you like to login to a different account ?
|
||||
{% endblocktrans %}
|
||||
</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
|
@ -34,31 +35,32 @@
|
|||
{% get_providers as socialaccount_providers %}
|
||||
|
||||
{% if socialaccount_providers %}
|
||||
<section>
|
||||
<p>
|
||||
{% blocktrans %}
|
||||
Please sign in with one of your existing third party accounts, or with the
|
||||
form opposite.
|
||||
{% endblocktrans %}
|
||||
</p>
|
||||
<section id="providers">
|
||||
<ul class="method-list">
|
||||
{% include "socialaccount/snippets/provider_list.html" with process="login" %}
|
||||
</ul>
|
||||
{% include "socialaccount/snippets/login_extra.html" %}
|
||||
</section>
|
||||
|
||||
{% include "socialaccount/snippets/login_extra.html" %}
|
||||
|
||||
<div class="divider"></div>
|
||||
|
||||
{% endif %}
|
||||
|
||||
<section>
|
||||
<section id="main">
|
||||
<p>
|
||||
{% blocktrans %}
|
||||
Please sign in with one of your existing third party accounts, or with the form below.
|
||||
{% endblocktrans %}
|
||||
</p>
|
||||
<ul class="actions">
|
||||
<li><a href="{{ signup_url }}">{% trans "Sign Up" %}</a></li>
|
||||
<li><a href="{% url "account_reset_password" %}">{% trans "Forgot Password?" %}</a>
|
||||
{% is_open_for_signup as open_signup %}
|
||||
{% if open_signup %}
|
||||
<li><a href="{{ signup_url }}">{% trans "Sign Up" %}</a></li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
<form action="{% url "account_login" %}" method="post">
|
||||
{% include "account/block-form.html" with form=form %}
|
||||
{% include "allauth_ens/block-form.html" with form=form %}
|
||||
<input type="submit" value="{% trans "Sign In" %}">
|
||||
{% if redirect_field_value %}
|
||||
<input type="hidden" name="{{ redirect_field_name }}" value="{{ redirect_field_value }}">
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
{% extends "account/base.html" %}
|
||||
{% extends "allauth_ens/base.html" %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block title %}{% trans "Sign Out" %}{% endblock %}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
{% extends "account/base.html" %}
|
||||
{% extends "allauth_ens/base.html" %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block title %}{% trans "Change Password" %}{% endblock %}
|
||||
|
@ -6,7 +6,7 @@
|
|||
|
||||
{% block messages-extra %}
|
||||
|
||||
{% include "account/block-messages-form-errors.html" with form_errors=form.non_field_errors %}
|
||||
{% include "allauth_ens/block-messages-form-errors.html" with form_errors=form.non_field_errors %}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
|
@ -14,7 +14,7 @@
|
|||
|
||||
<section>
|
||||
<form action="{% url "account_change_password" %}" method="post">
|
||||
{% include "account/block-form.html" with form=form submit_value=submit_value %}
|
||||
{% include "allauth_ens/block-form.html" with form=form submit_value=submit_value %}
|
||||
<input type="submit" value="{% trans "Change Password" %}">
|
||||
</form>
|
||||
</section>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
{% extends "account/base.html" %}
|
||||
{% extends "allauth_ens/base.html" %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block title %}{% trans "Password Reset" %}{% endblock %}
|
||||
|
@ -14,7 +14,7 @@
|
|||
{% endblocktrans %}
|
||||
</p>
|
||||
<form action="{% url "account_reset_password" %}" method="post">
|
||||
{% include "account/block-form.html" with form=form %}
|
||||
{% include "allauth_ens/block-form.html" with form=form %}
|
||||
<input type="submit" value="{% trans "Reset Password" %}">
|
||||
</form>
|
||||
</section>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
{% extends "account/base.html" %}
|
||||
{% extends "allauth_ens/base.html" %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block title %}{% trans "Password Reset" %}{% endblock %}
|
||||
|
|
28
allauth_ens/templates/account/password_reset_from_key.html
Normal file
28
allauth_ens/templates/account/password_reset_from_key.html
Normal file
|
@ -0,0 +1,28 @@
|
|||
{% extends "allauth_ens/base.html" %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block title %}{% trans "Change Password" %}{% endblock %}
|
||||
{% block header-title %}{% trans "Change Password" %}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<section>
|
||||
{% if token_fail %}
|
||||
<p>
|
||||
{% url 'account_reset_password' as passwd_reset_url %}
|
||||
{% blocktrans %}
|
||||
The password reset link was invalid, possibly because it has already been used.
|
||||
Please request a <a href="{{ passwd_reset_url }}">new password reset</a>.
|
||||
{% endblocktrans %}
|
||||
</p>
|
||||
{% elif form %}
|
||||
<form action="" method="post">
|
||||
{% include "allauth_ens/block-form.html" with form=form %}
|
||||
<input type="submit" value="{% trans "Reset Password" %}">
|
||||
</form>
|
||||
{% else %}
|
||||
<p>{% trans "Your password is now changed." %}</p>
|
||||
{% endif %}
|
||||
</section>
|
||||
|
||||
{% endblock %}
|
|
@ -1,4 +1,4 @@
|
|||
{% extends "account/base.html" %}
|
||||
{% extends "allauth_ens/base.html" %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block title %}{% trans "Change Password" %}{% endblock %}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
{% extends "account/base.html" %}
|
||||
{% extends "allauth_ens/base.html" %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block title %}{% trans "Set Password" %}{% endblock %}
|
||||
|
@ -6,7 +6,7 @@
|
|||
|
||||
{% block messages-extra %}
|
||||
|
||||
{% include "account/block-messages-form-errors.html" with form_errors=form.non_field_errors %}
|
||||
{% include "allauth_ens/block-messages-form-errors.html" with form_errors=form.non_field_errors %}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
|
@ -19,9 +19,8 @@
|
|||
third parties.
|
||||
{% endblocktrans %}
|
||||
</p>
|
||||
<hr>
|
||||
<form action="{% url "account_set_password" %}" method="post">
|
||||
{% include "account/block-form.html" with form=form %}
|
||||
{% include "allauth_ens/block-form.html" with form=form %}
|
||||
<input type="submit" value="{% trans "Set Password" %}">
|
||||
</form>
|
||||
</section>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
{% extends "account/base.html" %}
|
||||
{% extends "allauth_ens/base.html" %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block title %}{% trans "Signup" %}{% endblock %}
|
||||
|
@ -13,7 +13,7 @@
|
|||
</li>
|
||||
</ul>
|
||||
<form action="{% url "account_signup" %}" method="post">
|
||||
{% include "account/block-form.html" with form=form %}
|
||||
{% include "allauth_ens/block-form.html" with form=form %}
|
||||
<input type="submit" value="{% trans "Sign Up" %}">
|
||||
{% if redirect_field_value %}
|
||||
<input type="hidden" name="{{ redirect_field_name }}" value="{{ redirect_field_value }}">
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
{% extends "account/base.html" %}
|
||||
{% extends "allauth_ens/base.html" %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block title %}{% trans "Sign Up Closed" %}{% endblock %}
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
<meta charset="utf-8">
|
||||
|
||||
<title>{% block title %}{% endblock %}{% if request.site.name %} - {{ request.site.name }}{% endif %}</title>
|
||||
<title>{% block title %}{% endblock %}{% if request.site.name %} · {{ request.site.name }}{% endif %}</title>
|
||||
|
||||
{# Responsive UI #}
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
|
@ -17,6 +17,10 @@
|
|||
{# CSS #}
|
||||
<link rel="stylesheet"
|
||||
href="https://fonts.googleapis.com/css?family=Roboto:400,700|Roboto+Slab:400">
|
||||
<link rel="stylesheet"
|
||||
href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css"
|
||||
integrity="sha384-wvfXpqpZZVQGK6TAh5PVlGOfQNHSoD2xbE+QkPxCAFlNEevoEH3Sl0sibVcOQVnN"
|
||||
crossorigin="anonymous">
|
||||
<link rel="stylesheet"
|
||||
href="{% static "allauth_ens/screen.css" %}">
|
||||
|
||||
|
@ -44,10 +48,10 @@
|
|||
{% get_home_url as home_url %}
|
||||
{% if home_url %}
|
||||
<a href="{{ home_url }}">
|
||||
{{ request.site.name|default:"Voir le site" }}
|
||||
{{ request.site.name|default:"View site" }}
|
||||
</a>
|
||||
{% else %}
|
||||
<span>{{ request.site.name }}</span>
|
||||
<span>{{ request.site.name|default:"View site" }}</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
|
@ -66,16 +70,16 @@
|
|||
</span>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<span>
|
||||
<i class="fa fa-user"></i>
|
||||
<a href="{% url "account_login" %}">
|
||||
<i class="fa fa-sign-in"></i>
|
||||
{% trans "Not Connected" %}
|
||||
</span>
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
{% include "account/block-messages.html" %}
|
||||
{% include "allauth_ens/block-messages.html" %}
|
||||
|
||||
{% block messages-extra %}{% endblock %}
|
||||
|
33
allauth_ens/templates/allauth_ens/block-form.html
Normal file
33
allauth_ens/templates/allauth_ens/block-form.html
Normal file
|
@ -0,0 +1,33 @@
|
|||
{% load widget_tweaks %}
|
||||
|
||||
{% csrf_token %}
|
||||
|
||||
{% for field in form %}
|
||||
{% with widget=field|widget_type %}
|
||||
{% if widget == "checkboxinput" %}
|
||||
<div li class="input-wrapper input-skip {% if field.errors %}input-error{% endif %}">
|
||||
<label for="{{ field.id_for_label }}">
|
||||
{{ field.label }}
|
||||
<div class="widget-checkbox">
|
||||
{% render_field field class+="field" %}
|
||||
<button type="button" class="choice-yes">Oui</button>
|
||||
<button type="button" class="choice-no focus">Non</button>
|
||||
</div>
|
||||
</label>
|
||||
{% else %}
|
||||
<div class="input-wrapper{% if field.errors %} input-error{% endif %}">
|
||||
<label for="{{ field.id_for_label }}">{{ field.label }}</label>
|
||||
{% render_field field class+="field" size="" autocomplete="off" autocapitalize="none" placeholder="" %}
|
||||
{% endif %}
|
||||
<div class="infos-spacer"></div>
|
||||
<ul class="messages">
|
||||
{% if field.help_text %}
|
||||
<li>{{ field.help_text|safe }}</li>
|
||||
{% endif %}
|
||||
{% for error in field.errors %}
|
||||
<li class="error-desc">{{ error }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
{% endwith %}
|
||||
{% endfor %}
|
|
@ -1,4 +1,4 @@
|
|||
{% extends "account/block-messages-base.html" %}
|
||||
{% extends "allauth_ens/block-messages-base.html" %}
|
||||
|
||||
{% block messages-container %}
|
||||
{% if form_errors %}{{ block.super }}{% endif %}
|
|
@ -1,4 +1,4 @@
|
|||
{% extends "account/block-messages-base.html" %}
|
||||
{% extends "allauth_ens/block-messages-base.html" %}
|
||||
|
||||
{% block messages-container %}
|
||||
{% if messages %}{{ block.super }}{% endif %}
|
|
@ -0,0 +1,17 @@
|
|||
{% extends "allauth_ens/base.html" %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block title %}{% trans "Login Failure" %}{% endblock %}
|
||||
{% block header-title %}{% trans "Login Failure" %}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<section>
|
||||
<p>
|
||||
{% blocktrans %}
|
||||
An error occured while attempting to login via your social network account.
|
||||
{% endblocktrans %}
|
||||
</p>
|
||||
</section>
|
||||
|
||||
{% endblock %}
|
|
@ -1,4 +1,4 @@
|
|||
{% extends "account/base.html" %}
|
||||
{% extends "allauth_ens/base.html" %}
|
||||
{% load i18n %}
|
||||
{% load socialaccount allauth_ens_social %}
|
||||
|
||||
|
@ -19,48 +19,45 @@
|
|||
{% endblocktrans %}
|
||||
{% endif %}
|
||||
</p>
|
||||
<ul class="provider-list">
|
||||
<ul class="connections-providers-list">
|
||||
{% get_accounts_by_providers user as accounts_by_providers %}
|
||||
|
||||
{% for provider, accounts in accounts_by_providers.items %}
|
||||
|
||||
<li class="provider">
|
||||
<ul class="heading">
|
||||
<li class="connect">
|
||||
<a href="{% provider_login_url provider.id process="connect" scope=scope auth_params=auth_params %}">
|
||||
<i class="fa fa-plus"></i>
|
||||
</a>
|
||||
</li>
|
||||
<li class="name">
|
||||
{{ provider.name }}
|
||||
</li>
|
||||
</ul>
|
||||
<li>
|
||||
<div class="heading">
|
||||
<a class="connect" href="{% provider_login_url provider.id process="connect" scope=scope auth_params=auth_params %}">
|
||||
<i class="fa fa-plus"></i>
|
||||
</a>
|
||||
{{ provider.name }}
|
||||
</div>
|
||||
|
||||
{% if accounts %}
|
||||
|
||||
<ul class="connected-list">
|
||||
<ul class="connections-list">
|
||||
{% for account in accounts %}
|
||||
|
||||
<li>
|
||||
<span class="connected-delete">
|
||||
<div class="delete">
|
||||
<form action="{% url "socialaccount_connections" %}" method="post">
|
||||
{% csrf_token %}
|
||||
<input type="hidden" name="account" value="{{ account.id }}">
|
||||
<button type="submit" class="link"><i class="fa fa-remove"></i></button>
|
||||
<button type="submit" class="link">
|
||||
<i class="fa fa-remove"></i>
|
||||
</button>
|
||||
</form>
|
||||
</span>
|
||||
<span class="connected-label">
|
||||
<i class="fa fa-user"></i>
|
||||
{% with account.get_profile_url as profile_url %}
|
||||
{% trans "Connected Account - No ID" as fallback_label %}
|
||||
{% firstof account.extra_data.name account.extra_data.username fallback_label as account_label %}
|
||||
{% if profile_url %}
|
||||
<a href="{{ profile_url }}" target="blank">{{ account_label }}</a>
|
||||
{% else %}
|
||||
</div>
|
||||
<i class="fa fa-user"></i>
|
||||
{% with profile_urlaccount.get_profile_url as profile_url %}
|
||||
{% firstof account.extra_data.name account.extra_data.username account.uid as account_label %}
|
||||
{% if profile_url %}
|
||||
<a href="{{ get_profile_url }}" target="blank">
|
||||
{{ account_label }}
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
</span>
|
||||
</a>
|
||||
{% else %}
|
||||
{{ account_label }}
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
</li>
|
||||
|
||||
{% endfor %}
|
||||
|
|
19
allauth_ens/templates/socialaccount/login_cancelled.html
Normal file
19
allauth_ens/templates/socialaccount/login_cancelled.html
Normal file
|
@ -0,0 +1,19 @@
|
|||
{% extends "allauth_ens/base.html" %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block title %}{% trans "Login Cancelled" %}{% endblock %}
|
||||
{% block header-title %}{% trans "Login Cancelled" %}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<section>
|
||||
<p>
|
||||
{% url "account_login" as login_url %}
|
||||
|
||||
{% blocktrans %}
|
||||
You decided to cancel logging into our site using one of your existing accounts. If this was a mistake, please proceed to <a href="{{login_url}}">sign in</a>.{% endblocktrans %}
|
||||
{% endblocktrans %}
|
||||
</p>
|
||||
</section>
|
||||
|
||||
{% endblock %}
|
26
allauth_ens/templates/socialaccount/signup.html
Normal file
26
allauth_ens/templates/socialaccount/signup.html
Normal file
|
@ -0,0 +1,26 @@
|
|||
{% extends "allauth_ens/base.html" %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block title %}{% trans "Signup" %}{% endblock %}
|
||||
{% block header-title %}{% trans "Signup" %}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<section>
|
||||
<p>
|
||||
{% blocktrans with provider_name=account.get_provider.name %}
|
||||
You are about to use your {{ provider_name }} account to login.
|
||||
As a final step, please complete the following form:
|
||||
{% endblocktrans %}
|
||||
</p>
|
||||
|
||||
<form action="{% url "socialaccount_signup" %}" method="post">
|
||||
{% include "allauth_ens/block-form.html" with form=form %}
|
||||
<input type="submit" value="{% trans "Sign Up" %}">
|
||||
{% if redirect_field_value %}
|
||||
<input type="hidden" name="{{ redirect_field_name }}" value="{{ redirect_field_value }}">
|
||||
{% endif %}
|
||||
</form>
|
||||
</section>
|
||||
|
||||
{% endblock %}
|
|
@ -3,6 +3,7 @@ from django import template
|
|||
from django.conf import settings
|
||||
from django.shortcuts import resolve_url
|
||||
|
||||
from allauth.account.adapter import get_adapter
|
||||
|
||||
register = template.Library()
|
||||
|
||||
|
@ -26,3 +27,9 @@ def get_profile_url():
|
|||
if profile_url is None:
|
||||
return None
|
||||
return resolve_url(profile_url)
|
||||
|
||||
|
||||
@simple_tag(takes_context=True)
|
||||
def is_open_for_signup(context):
|
||||
request = context['request']
|
||||
return get_adapter(request).is_open_for_signup(request)
|
||||
|
|
|
@ -6,7 +6,6 @@ from django import template
|
|||
from allauth import app_settings as allauth_settings
|
||||
from allauth.socialaccount.templatetags import socialaccount as tt_social
|
||||
|
||||
|
||||
register = template.Library()
|
||||
|
||||
if django.VERSION >= (1, 9):
|
||||
|
|
137
allauth_ens/tests.py
Normal file
137
allauth_ens/tests.py
Normal file
|
@ -0,0 +1,137 @@
|
|||
import re
|
||||
|
||||
import django
|
||||
from django.contrib.auth import HASH_SESSION_KEY, get_user_model
|
||||
from django.contrib.sites.models import Site
|
||||
from django.core import mail
|
||||
from django.test import TestCase, override_settings
|
||||
|
||||
if django.VERSION >= (1, 10):
|
||||
from django.urls import reverse
|
||||
else:
|
||||
from django.core.urlresolvers import reverse
|
||||
|
||||
User = get_user_model()
|
||||
|
||||
|
||||
def prevent_logout_pwd_change(client, user):
|
||||
"""
|
||||
Updating a user's password logs out all sessions for the user.
|
||||
By calling this function this behavior will be prevented.
|
||||
|
||||
See this link, and the source code of `update_session_auth_hash`:
|
||||
https://docs.djangoproject.com/en/dev/topics/auth/default/#session-invalidation-on-password-change
|
||||
"""
|
||||
if hasattr(user, 'get_session_auth_hash'):
|
||||
session = client.session
|
||||
session[HASH_SESSION_KEY] = user.get_session_auth_hash()
|
||||
session.save()
|
||||
|
||||
|
||||
class ViewsTests(TestCase):
|
||||
"""
|
||||
Checks (barely) that templates do not contain errors.
|
||||
"""
|
||||
def setUp(self):
|
||||
self.u = User.objects.create_user('user', 'user@mail.net', 'user')
|
||||
|
||||
Site.objects.filter(pk=1).update(domain='testserver')
|
||||
|
||||
def _login(self, client=None):
|
||||
if client is None:
|
||||
client = self.client
|
||||
client.login(username='user', password='user')
|
||||
|
||||
def _get_confirm_email_link(self, email_msg):
|
||||
m = re.search(
|
||||
r'http://testserver(/accounts/confirm-email/.*/)',
|
||||
email_msg.body,
|
||||
)
|
||||
return m.group(1)
|
||||
|
||||
def _get_reset_password_link(self, email_msg):
|
||||
m = re.search(
|
||||
r'http://testserver(/accounts/password/reset/key/.*/)',
|
||||
email_msg.body,
|
||||
)
|
||||
return m.group(1)
|
||||
|
||||
def test_account_signup(self):
|
||||
r = self.client.get(reverse('account_signup'))
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
@override_settings(
|
||||
ACCOUNT_ADAPTER='tests.adapter.ClosedSignupAccountAdapter',
|
||||
)
|
||||
def test_account_closed_signup(self):
|
||||
r = self.client.get(reverse('account_signup'))
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
def test_account_login(self):
|
||||
r = self.client.get(reverse('account_login'))
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
def test_account_logout(self):
|
||||
self._login()
|
||||
r = self.client.get(reverse('account_logout'))
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
def test_account_change_password(self):
|
||||
self._login()
|
||||
r = self.client.get(reverse('account_change_password'))
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
def test_account_set_password(self):
|
||||
self._login()
|
||||
self.u.set_unusable_password()
|
||||
self.u.save()
|
||||
prevent_logout_pwd_change(self.client, self.u)
|
||||
|
||||
r = self.client.get(reverse('account_set_password'))
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
def test_account_inactive(self):
|
||||
r = self.client.get(reverse('account_inactive'))
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
def test_account_email(self):
|
||||
self._login()
|
||||
r = self.client.get(reverse('account_email'))
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
def test_account_email_verification_sent(self):
|
||||
self._login()
|
||||
r = self.client.get(reverse('account_email_verification_sent'))
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
def test_account_confirm_email(self):
|
||||
self._login()
|
||||
self.client.post(reverse('account_email'), {
|
||||
'action_add': '',
|
||||
'email': 'test@mail.net',
|
||||
})
|
||||
confirm_url = self._get_confirm_email_link(mail.outbox[0])
|
||||
|
||||
r = self.client.get(confirm_url)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
def test_account_reset_password(self):
|
||||
r = self.client.get(reverse('account_reset_password'))
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
def test_account_reset_password_done(self):
|
||||
r = self.client.get(reverse('account_reset_password_done'))
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
def test_account_reset_password_from_key(self):
|
||||
self.client.post(reverse('account_reset_password'), {
|
||||
'email': 'user@mail.net',
|
||||
})
|
||||
reset_url = self._get_reset_password_link(mail.outbox[0])
|
||||
|
||||
r = self.client.get(reset_url, follow=True)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
def test_account_reset_password_from_key_done(self):
|
||||
r = self.client.get(reverse('account_reset_password_from_key_done'))
|
||||
self.assertEqual(r.status_code, 200)
|
|
@ -1,10 +1,16 @@
|
|||
from django.core.urlresolvers import reverse_lazy
|
||||
import django
|
||||
from django.views.generic import RedirectView
|
||||
|
||||
if django.VERSION >= (1, 10):
|
||||
from django.urls import reverse_lazy
|
||||
else:
|
||||
from django.core.urlresolvers import reverse_lazy
|
||||
|
||||
|
||||
class CaptureLogin(RedirectView):
|
||||
url = reverse_lazy('account_login')
|
||||
query_string = True
|
||||
permanent = False
|
||||
|
||||
|
||||
capture_login = CaptureLogin.as_view()
|
||||
|
@ -13,6 +19,7 @@ capture_login = CaptureLogin.as_view()
|
|||
class CaptureLogout(RedirectView):
|
||||
url = reverse_lazy('account_logout')
|
||||
query_string = True
|
||||
permanent = False
|
||||
|
||||
|
||||
capture_logout = CaptureLogout.as_view()
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
require 'compass/import-once/activate'
|
||||
# Require any additional compass plugins here.
|
||||
require 'font-awesome-sass'
|
||||
|
||||
# Set this to the root of your project when deployed:
|
||||
http_path = '/'
|
||||
|
|
54
example/README.rst
Normal file
54
example/README.rst
Normal file
|
@ -0,0 +1,54 @@
|
|||
*****
|
||||
Setup
|
||||
*****
|
||||
|
||||
Clone the repository and go to the directory containing this file.
|
||||
|
||||
If it is the first time you start the example website, run these commands::
|
||||
|
||||
# Create a virtual env.
|
||||
$ virtualenv -p python3 venv
|
||||
$ . venv/bin/activate
|
||||
|
||||
# Install dependencies (django-allauth-ens is installed from local copy).
|
||||
$ pip install -r requirements.txt
|
||||
|
||||
# Initialize the database (sqlite).
|
||||
$ ./manage.py migrate
|
||||
|
||||
Start the server with::
|
||||
|
||||
$ ./manage.py runserver
|
||||
|
||||
Then, open your browser at `<http://localhost:8000/>`_.
|
||||
|
||||
|
||||
*****
|
||||
Usage
|
||||
*****
|
||||
|
||||
Pre-existing users
|
||||
==================
|
||||
|
||||
You can try to login using one of the existing users:
|
||||
|
||||
* a "normal" user (username: 'user', password: 'user')
|
||||
|
||||
* a superuser (username: 'root', password: 'root')
|
||||
|
||||
Auth Providers
|
||||
==============
|
||||
|
||||
Facebook and Google are activated but they won't work unless you provide valid
|
||||
API credentials in the Django Admin at
|
||||
`<http://localhost:8060/admin/socialaccount/socialapp/>`_.
|
||||
|
||||
Clipper is available (which requires valid credentials). For auto-signup, the
|
||||
new user is populated with the clipper identifier as username (plus a suffix if
|
||||
not available) and ``<clipper id>@clipper.ens.fr`` as email.
|
||||
|
||||
Adapters
|
||||
========
|
||||
|
||||
``ACCOUNT_ADAPTER`` and ``SOCIALACCOUNT_ADAPTER`` can be customized in
|
||||
``adapter.py``.
|
11
example/adapter.py
Normal file
11
example/adapter.py
Normal file
|
@ -0,0 +1,11 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from allauth.account.adapter import DefaultAccountAdapter
|
||||
from allauth.socialaccount.adapter import DefaultSocialAccountAdapter
|
||||
|
||||
|
||||
class AccountAdapter(DefaultAccountAdapter):
|
||||
pass
|
||||
|
||||
|
||||
class SocialAccountAdapter(DefaultSocialAccountAdapter):
|
||||
pass
|
|
@ -1,27 +0,0 @@
|
|||
from django.contrib import admin
|
||||
from django.contrib.auth.admin import UserAdmin
|
||||
from django.contrib.auth.models import AbstractUser
|
||||
from django.utils.translation import ugettext as _
|
||||
|
||||
from .models import User
|
||||
|
||||
|
||||
class ExtendedUserAdmin(UserAdmin):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
base_fields = [field.name for field in AbstractUser._meta.fields]
|
||||
all_fields = [field.name for field in self.model._meta.fields]
|
||||
|
||||
extra_fields = [
|
||||
f for f in all_fields
|
||||
if f not in base_fields and f != self.model._meta.pk.name
|
||||
]
|
||||
|
||||
self.fieldsets += (
|
||||
(_('Champs additionnels'), {'fields': extra_fields}),
|
||||
)
|
||||
|
||||
|
||||
admin.site.register(User, ExtendedUserAdmin)
|
|
@ -1,34 +1,42 @@
|
|||
from django.apps import AppConfig
|
||||
from django.db.models.signals import post_migrate
|
||||
from django.utils.module_loading import import_string
|
||||
|
||||
from allauth.socialaccount.providers import registry
|
||||
|
||||
|
||||
def prepare_site(sender, **kwargs):
|
||||
def setup_site(sender, **kwargs):
|
||||
from django.contrib.sites.models import Site
|
||||
Site.objects.filter(id=1).update(name="Demo Site", domain="localhost")
|
||||
|
||||
|
||||
def prepare_superuser(sender, **kwargs):
|
||||
def setup_users(sender, **kwargs):
|
||||
from django.contrib.auth import get_user_model
|
||||
User = get_user_model()
|
||||
root, created = User.objects.get_or_create(
|
||||
username='root',
|
||||
defaults={
|
||||
'is_staff': True,
|
||||
'is_superuser': True,
|
||||
},
|
||||
)
|
||||
if created:
|
||||
|
||||
root, r_created = User.objects.get_or_create(username='root', defaults={
|
||||
'email': 'root@mail.net',
|
||||
'is_staff': True,
|
||||
'is_superuser': True,
|
||||
})
|
||||
if r_created:
|
||||
root.set_password('root')
|
||||
root.save()
|
||||
print('Superuser created - Credentials: root:root')
|
||||
|
||||
user, u_created = User.objects.get_or_create(username='user', defaults={
|
||||
'email': 'user@mail.net',
|
||||
})
|
||||
if u_created:
|
||||
user.set_password('user')
|
||||
user.save()
|
||||
print('User created - Credentials: user:user')
|
||||
|
||||
|
||||
def setup_dummy_social(sender, **kwargs):
|
||||
from django.contrib.sites.models import Site
|
||||
from django.utils.module_loading import import_string
|
||||
|
||||
from allauth.socialaccount.models import SocialApp
|
||||
from allauth.socialaccount.providers import registry
|
||||
|
||||
need_credentials = [
|
||||
'allauth.socialaccount.providers.oauth.provider.OAuthProvider',
|
||||
|
@ -68,6 +76,6 @@ class BasicAppConfig(AppConfig):
|
|||
name = 'app'
|
||||
|
||||
def ready(self):
|
||||
post_migrate.connect(prepare_site, sender=self)
|
||||
post_migrate.connect(prepare_superuser, sender=self)
|
||||
post_migrate.connect(setup_site, sender=self)
|
||||
post_migrate.connect(setup_dummy_social, sender=self)
|
||||
post_migrate.connect(setup_users, sender=self)
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
[
|
||||
{
|
||||
"model": "testapp.user",
|
||||
"model": "auth.user",
|
||||
"pk": 1,
|
||||
"fields": {
|
||||
"password": "pbkdf2_sha256$36000$RNuQMJ1hqN0P$GFFyxtTONjkh4IUMifNYrsXs4/SnX5uMnGtRNR2WrFo=",
|
||||
"password": "pbkdf2_sha256$100000$WDs2nLZ0eIl1$oNqrYphOf0AVRQ8aPIA3g7xM2gI8/c8NJkp2geVT7mc=",
|
||||
"last_login": null,
|
||||
"is_superuser": false,
|
||||
"username": "user",
|
||||
|
@ -13,19 +13,15 @@
|
|||
"is_staff": false,
|
||||
"is_active": true,
|
||||
"date_joined": "2017-07-03T10:10:18.675Z",
|
||||
"departement": "",
|
||||
"occupation": "1A",
|
||||
"phone": "",
|
||||
"promo": 2016,
|
||||
"groups": [],
|
||||
"user_permissions": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "testapp.user",
|
||||
"model": "auth.user",
|
||||
"pk": 2,
|
||||
"fields": {
|
||||
"password": "pbkdf2_sha256$36000$NFfbdDHHuq0A$auDXrWn6xr+FnsAOW8uq0aa8m2kyUPtgY/QgThMDKF0=",
|
||||
"password": "pbkdf2_sha256$100000$EjBzWe7Ce5Bc$abqTFywweKuMaRux2MMUwcLchcwxmXGduN320oYaV28=",
|
||||
"last_login": null,
|
||||
"is_superuser": true,
|
||||
"username": "root",
|
||||
|
@ -35,12 +31,16 @@
|
|||
"is_staff": true,
|
||||
"is_active": true,
|
||||
"date_joined": "2017-07-03T10:10:36.413Z",
|
||||
"departement": "",
|
||||
"occupation": "1A",
|
||||
"phone": "",
|
||||
"promo": 2016,
|
||||
"groups": [],
|
||||
"user_permissions": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "sites.Site",
|
||||
"pk": 1,
|
||||
"fields": {
|
||||
"name": "Example Site",
|
||||
"domain": "localhost"
|
||||
}
|
||||
}
|
||||
]
|
|
@ -1,46 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.3 on 2017-07-27 15:06
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import django.contrib.auth.models
|
||||
import django.contrib.auth.validators
|
||||
from django.db import migrations, models
|
||||
import django.utils.timezone
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
('auth', '0008_alter_user_username_max_length'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='User',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('password', models.CharField(max_length=128, verbose_name='password')),
|
||||
('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')),
|
||||
('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')),
|
||||
('username', models.CharField(error_messages={'unique': 'A user with that username already exists.'}, help_text='Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.', max_length=150, unique=True, validators=[django.contrib.auth.validators.UnicodeUsernameValidator()], verbose_name='username')),
|
||||
('first_name', models.CharField(blank=True, max_length=30, verbose_name='first name')),
|
||||
('last_name', models.CharField(blank=True, max_length=30, verbose_name='last name')),
|
||||
('email', models.EmailField(blank=True, max_length=254, verbose_name='email address')),
|
||||
('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')),
|
||||
('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')),
|
||||
('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')),
|
||||
('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.Group', verbose_name='groups')),
|
||||
('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.Permission', verbose_name='user permissions')),
|
||||
],
|
||||
options={
|
||||
'verbose_name_plural': 'users',
|
||||
'verbose_name': 'user',
|
||||
'abstract': False,
|
||||
},
|
||||
managers=[
|
||||
('objects', django.contrib.auth.models.UserManager()),
|
||||
],
|
||||
),
|
||||
]
|
|
@ -1,11 +0,0 @@
|
|||
from django.contrib.auth.models import AbstractUser, UserManager
|
||||
|
||||
# from authens.models import ENSUserMixin
|
||||
|
||||
"""
|
||||
class User(ENSUserMixin, AbstractUser):
|
||||
objects = UserManager()
|
||||
"""
|
||||
|
||||
class User(AbstractUser):
|
||||
objects = UserManager()
|
|
@ -1,38 +0,0 @@
|
|||
[
|
||||
{
|
||||
"model": "auth.user",
|
||||
"pk": 1,
|
||||
"fields": {
|
||||
"password": "pbkdf2_sha256$36000$xjRTvXipQpaq$z0kj/h2b4yZp8DNOjhu2TUxSOWHWYX+S+0rvsaWx7TU=",
|
||||
"last_login": null,
|
||||
"is_superuser": false,
|
||||
"username": "user",
|
||||
"first_name": "",
|
||||
"last_name": "",
|
||||
"email": "",
|
||||
"is_staff": false,
|
||||
"is_active": true,
|
||||
"date_joined": "2017-07-01T07:11:08.549Z",
|
||||
"groups": [],
|
||||
"user_permissions": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "auth.user",
|
||||
"pk": 3,
|
||||
"fields": {
|
||||
"password": "pbkdf2_sha256$36000$7IcQUVbp8OM1$7mKhCjAPFLkcEUfu9djXxn/scOw2uvlWLFrMtGfhd0U=",
|
||||
"last_login": null,
|
||||
"is_superuser": true,
|
||||
"username": "root",
|
||||
"first_name": "",
|
||||
"last_name": "",
|
||||
"email": "",
|
||||
"is_staff": true,
|
||||
"is_active": true,
|
||||
"date_joined": "2017-07-01T07:11:20.745Z",
|
||||
"groups": [],
|
||||
"user_permissions": []
|
||||
}
|
||||
}
|
||||
]
|
|
@ -9,34 +9,26 @@ SECRET_KEY = 'iamaplop'
|
|||
|
||||
DEBUG = True
|
||||
|
||||
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
|
||||
|
||||
SITE_ID = 1
|
||||
|
||||
INSTALLED_APPS = [
|
||||
'django.contrib.admin',
|
||||
'django.contrib.auth',
|
||||
'django.contrib.contenttypes',
|
||||
'django.contrib.sessions',
|
||||
'django.contrib.messages',
|
||||
'django.contrib.sessions',
|
||||
'django.contrib.sites',
|
||||
'django.contrib.staticfiles',
|
||||
|
||||
'debug_toolbar',
|
||||
'widget_tweaks',
|
||||
|
||||
# This one must be before 'allauth' to replace its templates.
|
||||
'allauth_ens',
|
||||
|
||||
'allauth',
|
||||
'allauth.account',
|
||||
'allauth.socialaccount',
|
||||
|
||||
'allauth_cas',
|
||||
|
||||
'allauth.socialaccount.providers.facebook',
|
||||
'allauth.socialaccount.providers.google',
|
||||
|
||||
'allauth_ens.providers.clipper',
|
||||
|
||||
'app',
|
||||
|
@ -59,6 +51,12 @@ else:
|
|||
|
||||
ROOT_URLCONF = 'urls'
|
||||
|
||||
SITE_ID = 1
|
||||
|
||||
WSGI_APPLICATION = 'wsgi.application'
|
||||
|
||||
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
|
||||
|
||||
TEMPLATES = [
|
||||
{
|
||||
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
||||
|
@ -75,8 +73,6 @@ TEMPLATES = [
|
|||
},
|
||||
]
|
||||
|
||||
WSGI_APPLICATION = 'wsgi.application'
|
||||
|
||||
DATABASES = {
|
||||
'default': {
|
||||
'ENGINE': 'django.db.backends.sqlite3',
|
||||
|
@ -86,16 +82,28 @@ DATABASES = {
|
|||
|
||||
AUTH_PASSWORD_VALIDATORS = [
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
|
||||
'NAME': (
|
||||
'django.contrib.auth.password_validation'
|
||||
'.UserAttributeSimilarityValidator',
|
||||
),
|
||||
},
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
|
||||
'NAME': (
|
||||
'django.contrib.auth.password_validation'
|
||||
'.MinimumLengthValidator'
|
||||
),
|
||||
},
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
|
||||
'NAME': (
|
||||
'django.contrib.auth.password_validation'
|
||||
'.CommonPasswordValidator'
|
||||
),
|
||||
},
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
|
||||
'NAME': (
|
||||
'django.contrib.auth.password_validation'
|
||||
'.NumericPasswordValidator'
|
||||
),
|
||||
},
|
||||
]
|
||||
|
||||
|
@ -115,7 +123,10 @@ DEBUG_TOOLBAR_CONFIG = {
|
|||
'SHOW_TOOLBAR_CALLBACK': lambda r: True,
|
||||
}
|
||||
|
||||
AUTH_USER_MODEL = 'app.User'
|
||||
AUTHENTICATION_BACKENDS = [
|
||||
'django.contrib.auth.backends.ModelBackend',
|
||||
'allauth.account.auth_backends.AuthenticationBackend',
|
||||
]
|
||||
|
||||
LOGIN_URL = '/account/login/'
|
||||
LOGIN_REDIRECT_URL = 'user-view'
|
||||
|
@ -125,4 +136,13 @@ SOCIALACCOUNT_QUERY_EMAIL = True
|
|||
|
||||
# allauth settings
|
||||
|
||||
ACCOUNT_ADAPTER = 'adapter.AccountAdapter'
|
||||
ACCOUNT_AUTHENTICATED_LOGIN_REDIRECTS = False
|
||||
ACCOUNT_AUTHENTICATION_METHOD = 'username_email'
|
||||
|
||||
SOCIALACCOUNT_ADAPTER = 'adapter.SocialAccountAdapter'
|
||||
|
||||
# allauth_ens settings
|
||||
|
||||
ACCOUNT_HOME_URL = 'home'
|
||||
ACCOUNT_DETAILS_URL = '/my-account/'
|
||||
|
|
|
@ -4,13 +4,14 @@ from django.contrib.auth.decorators import login_required, permission_required
|
|||
from django.views.generic import RedirectView
|
||||
|
||||
import debug_toolbar
|
||||
from allauth_ens.views import capture_login, capture_logout
|
||||
|
||||
from app import views
|
||||
|
||||
urlpatterns = [
|
||||
# Catch admin login/logout views.
|
||||
# url(r'^admin/login/', authens_views.CaptureLogin.as_view()),
|
||||
# url(r'^admin/logout/', authens_views.CaptureLogout.as_view()),
|
||||
url(r'^admin/login/', capture_login),
|
||||
url(r'^admin/logout/', capture_logout),
|
||||
|
||||
# Admin urls include comes after.
|
||||
url(r'^admin/', admin.site.urls),
|
||||
|
@ -28,7 +29,8 @@ urlpatterns = [
|
|||
|
||||
|
||||
# (Redirect from /)
|
||||
url(r'^$', RedirectView.as_view(url='/view/')),
|
||||
url(r'^$', RedirectView.as_view(url='/view/'),
|
||||
name='home'),
|
||||
]
|
||||
|
||||
urlpatterns += [url(r'^__debug__/', include(debug_toolbar.urls))]
|
||||
|
|
2
setup.py
2
setup.py
|
@ -45,7 +45,7 @@ setup(
|
|||
include_package_data=True,
|
||||
install_requires=[
|
||||
'django-allauth',
|
||||
'django-allauth-cas',
|
||||
'django-allauth-cas>=1.0.0b2,<1.1',
|
||||
'django-widget-tweaks',
|
||||
],
|
||||
)
|
||||
|
|
6
tests/adapter.py
Normal file
6
tests/adapter.py
Normal file
|
@ -0,0 +1,6 @@
|
|||
from allauth.account.adapter import DefaultAccountAdapter
|
||||
|
||||
|
||||
class ClosedSignupAccountAdapter(DefaultAccountAdapter):
|
||||
def is_open_for_signup(self, request):
|
||||
return False
|
|
@ -12,10 +12,12 @@ INSTALLED_APPS = [
|
|||
'django.contrib.sites',
|
||||
'django.contrib.staticfiles',
|
||||
|
||||
'widget_tweaks',
|
||||
|
||||
'allauth_ens',
|
||||
'allauth',
|
||||
'allauth.account',
|
||||
'allauth.socialaccount',
|
||||
|
||||
'allauth_cas',
|
||||
|
||||
'allauth_ens.providers.clipper',
|
||||
|
@ -36,6 +38,7 @@ _MIDDLEWARES = [
|
|||
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||
'django.middleware.csrf.CsrfViewMiddleware',
|
||||
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
||||
'django.contrib.sites.middleware.CurrentSiteMiddleware',
|
||||
'django.contrib.messages.middleware.MessageMiddleware',
|
||||
]
|
||||
|
||||
|
@ -61,3 +64,7 @@ TEMPLATES = [
|
|||
]
|
||||
|
||||
ROOT_URLCONF = 'tests.urls'
|
||||
|
||||
SITE_ID = 1
|
||||
|
||||
STATIC_URL = '/static/'
|
||||
|
|
6
tox.ini
6
tox.ini
|
@ -1,7 +1,8 @@
|
|||
[tox]
|
||||
envlist =
|
||||
py{27,34,35}-django{18,19,110}
|
||||
py{27,34,35,36}-django111,
|
||||
django{18,19,110}-py{27,34,35},
|
||||
django111-py{27,34,35,36},
|
||||
django20-py{34,35,36},
|
||||
cov_combine,
|
||||
flake8,
|
||||
isort
|
||||
|
@ -12,6 +13,7 @@ deps =
|
|||
django19: django>=1.9,<1.10
|
||||
django110: django>=1.10,<1.11
|
||||
django111: django>=1.11,<2.0
|
||||
django20: django>=2.0,<2.1
|
||||
coverage
|
||||
mock ; python_version < "3.0"
|
||||
usedevelop= True
|
||||
|
|
Loading…
Reference in a new issue