Initial package (WIP)

This commit is contained in:
Aurélien Delobelle 2017-08-03 12:40:52 +02:00
parent 5bc1446dd3
commit 916b08374a
36 changed files with 5463 additions and 0 deletions

3
allauth_ens/__init__.py Normal file
View file

@ -0,0 +1,3 @@
__version__ = '0.0.1.dev0'
default_app_config = 'allauth_ens.apps.ENSAllauthAppConfig'

7
allauth_ens/apps.py Normal file
View file

@ -0,0 +1,7 @@
from django.apps import AppConfig
from django.utils.translation import ugettext_lazy as _
class ENSAllauthAppConfig(AppConfig):
name = 'allauth_ens'
verbose_name = _("ENS Authentication")

View file

View file

View file

@ -0,0 +1,42 @@
# -*- coding: utf-8 -*-
from allauth.account.models import EmailAddress
from allauth.socialaccount.providers.base import ProviderAccount
from allauth_cas.providers import CASProvider
class ClipperAccount(ProviderAccount):
pass
class ClipperProvider(CASProvider):
id = 'clipper'
name = 'Clipper'
account_class = ClipperAccount
def extract_email(self, data):
username, _, _ = data
return '{}@clipper.ens.fr'.format(username)
def extract_common_fields(self, data):
common = super(ClipperProvider, self).extract_common_fields(data)
common['email'] = self.extract_email(data)
return common
def extract_email_addresses(self, data):
email = self.extract_email(data)
return [
EmailAddress(
email=email,
verified=True,
primary=True,
)
]
def extract_extra_data(self, data):
extra = super(ClipperProvider, self).extract_extra_data(data)
extra['email'] = self.extract_email(data)
return extra
provider_classes = [ClipperProvider]

View file

@ -0,0 +1,33 @@
from allauth_cas.test.testcases import CASViewTestCase
class ClipperViewsTests(CASViewTestCase):
def test_login_view(self):
r = self.client.get('/accounts/clipper/login/')
expected = (
"https://cas.eleves.ens.fr/login?service=http%3A%2F%2Ftestserver"
"%2Faccounts%2Fclipper%2Flogin%2Fcallback%2F"
)
self.assertRedirects(
r, expected,
fetch_redirect_response=False,
)
def test_callback_view(self):
self.patch_cas_response(valid_ticket='__all__')
r = self.client.get('/accounts/clipper/login/callback/', {
'ticket': '123456',
})
self.assertLoginSuccess(r)
def test_logout_view(self):
r = self.client.get('/accounts/clipper/logout/')
expected = (
"https://cas.eleves.ens.fr/logout?service=http%3A%2F%2Ftestserver"
"%2F"
)
self.assertRedirects(
r, expected,
fetch_redirect_response=False,
)

View file

@ -0,0 +1,6 @@
# -*- coding: utf-8 -*-
from allauth_cas.urls import default_urlpatterns
from .provider import ClipperProvider
urlpatterns = default_urlpatterns(ClipperProvider)

View file

@ -0,0 +1,15 @@
# -*- coding: utf-8 -*-
from allauth_cas import views
from .provider import ClipperProvider
class ClipperCASAdapter(views.CASAdapter):
provider_id = ClipperProvider.id
url = 'https://cas.eleves.ens.fr'
version = 3
login = views.CASLoginView.adapter_view(ClipperCASAdapter)
callback = views.CASCallbackView.adapter_view(ClipperCASAdapter)
logout = views.CASLogoutView.adapter_view(ClipperCASAdapter)

358
allauth_ens/scss/_base.scss Normal file
View file

@ -0,0 +1,358 @@
body {
font-family: Roboto, Verdana;
font-family: $font-family-base;
line-height: 1.4;
background: $gray-lightest;
color: $gray;
@media (min-width: 576px) {
display: flex;
align-items: center;
justify-content: center;
}
}
a {
@include link;
}
b {
font-weight: bold;
}
/********************
* Layout structure *
********************/
$main-max-width: 700px;
$divider-size: 2px;
.wrapper {
max-width: $main-max-width;
margin: 0 auto;
background: $white;
box-shadow: 0 0 10px $gray-lighter;
}
@media (min-height: 400px) and (min-width: 576px) {
html, body {
height: 100%;
}
}
@media (min-height: 500px) and (min-width: 576px) {
.wrapper {
position: relative;
top: -5%;
}
}
.content-wrapper {
display: flex;
flex-flow: row wrap;
align-items: center;
/* Blocks */
& > section {
flex: 1 100%;
padding: 15px;
}
@media (min-width: 576px) {
& > section {
flex: 1 1 auto;
width: 350px - $divider-size / 2;
}
}
/* 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%; }
}
}
& > section + .divider {
display: block;
}
}
/**********
* Header *
**********/
$header-bg: darken($red, 10%);
$header-history-icon-size: 20px;
header {
@include clearfix;
display: flex;
align-items: stretch;
min-height: 60px;
background: $header-bg;
color: $white;
font-size: 20px;
font-weight: bold;
button {
width: 60px;
cursor: pointer;
background: transparent;
@include hover-focus {
background: lighten($header-bg, 5%);
}
img {
height: $header-history-icon-size;
width: auto;
vertical-align: bottom;
}
}
h1 {
padding: 15px 35px 15px 15px;
line-height: 30px;
}
}
/************
* Messages *
************/
.messages-container {
padding: 0 15px;
&::after {
display: block;
content: "";
background-color: $gray-lighter;
height: 2px;
}
}
.messages-list {
padding: 15px 0;
}
.message {
& + .message {
margin-top: 10px;
}
&.warning { color: darken($orange, 15%); }
&.error { color: $red; }
}
/***********
* Content *
***********/
section {
p {
margin-bottom: 15px;
}
}
/* 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;
a {
@include btn;
@include btn-primary-hov;
display: block;
}
}
/* Connected accounts list */
.provider-list {
& > li {
height: 40px;
padding: 10px;
& > .heading > * {
float: left;
}
}
form {
display: inline-block;
}
}
/*********
* Forms *
*********/
$input-space-after: 10px;
$input-wrapper-padding: 0;
$input-border-color: rgba(0,0,0,0.12);
$input-border-width: 1px;
$input-border-width-lg: 2px;
$input-padding: 2px;
$input-font-size: 16px;
$input-height: 30px;
$label-small-scale: 0.75;
$input-height-inner: $input-height - 2 * $input-padding;
$label-height: $input-height-inner;
$label-small-top: $label-height * (1 - $label-small-scale);
$label-top: $label-height + $input-wrapper-padding + $input-padding;
.input-wrapper {
@include clearfix;
position: relative;
display: block;
margin: ($label-small-scale * $label-height) 0;
padding: $input-wrapper-padding;
label {
@include ellipsis;
position: absolute;
bottom: 100%;
left: 0;
padding-left: $input-wrapper-padding;
width: 100%;
max-width: 100%;
height: $label-height;
line-height: $label-height;
pointer-events: none;
color: rgba(0,0,0,0.38);
font-size: $input-font-size;
transform: translate3d(0,$label-height + $input-padding,0) scale(1);
transition: transform .4s cubic-bezier(.25,.8,.25,1);
transform-origin: left top;
}
input.field {
height: $input-height;
width: 100%;
padding: $input-padding $input-padding ($input-padding - $input-border-width);
background-color: $white;
line-height: $input-height-inner;
border-bottom: $input-border-width solid $input-border-color;
font-size: $input-font-size;
}
@mixin input-special($type, $color: $input-border-color) {
&.input-#{$type} input.field {
padding-bottom: $input-padding - $input-border-width-lg;
border-width: $input-border-width-lg;
border-color: $color;
}
}
&.input-focused label,
&.input-has-value label {
transform: translate3d(0,$label-small-top,0) scale($label-small-scale);
}
@include input-special('has-value', $green);
@include input-special('error', $red);
@include input-special('focused', $blue);
.infos-spacer {
float: right;
min-height: $input-space-after;
min-width: 1px;
}
}
[type=submit]:not(.link) {
@include btn;
@include btn-success-hov;
}
[type=submit].link {
@include link;
background: transparent;
padding: 0;
@include hover-focus {
cursor: pointer;
}
}
.btn {
@include btn;
display: block;
}
.btn-primary-hov {
@include btn-primary-hov;
}

View file

@ -0,0 +1,86 @@
@mixin hover {
&:hover { @content }
}
@mixin hover-focus {
@if $enable-hover-media-query {
&:focus { @content }
@include hover { @content }
} @else {
&:focus,
&:hover {
@content
}
}
}
@mixin clearfix() {
&::after {
display: block;
content: "";
clear: both;
}
}
@mixin ellipsis($text-overflow: ellipsis) {
& {
overflow: hidden;
text-overflow: $text-overflow;
white-space: nowrap;
}
}
@mixin link {
color: $link-color;
font-size: inherit;
text-decoration: $link-decoration;
@include hover-focus {
color: $link-hover-color;
text-decoration: $link-hover-decoration;
}
}
@mixin btn {
width: 100%;
min-height: 40px;
border: 0;
padding: 15px 10px;
font-family: "Roboto Slab";
font-size: 18px;
text-align:center;
transition: background .3s;
@include hover-focus {
text-decoration: none;
cursor: pointer;
}
}
@mixin btn-primary-hov {
// background: $gray-lighter;
color: $black;
// border: 1px dashed $gray;
// border-top: 2px solid transparent;
// border-bottom: 2px solid darken($brand-primary, 15%);
@include hover-focus {
background: darken($brand-primary, 15%);
color: $white;
// border: 1px solid darken($brand-primary, 15%);
}
}
@mixin btn-success-hov {
background: $gray-lighter;
color: $black;
@include hover-focus {
background: darken($brand-success, 15%);
color: $white;
}
}

View file

@ -0,0 +1,24 @@
html {
box-sizing: border-box;
}
*,
*::before,
*::after {
box-sizing: inherit;
}
a, input, button {
outline: none;
}
input, button {
border: 0;
border-radius: 0;
box-shadow: none;
font-family: inherit;
}
input:-webkit-autofill {
-webkit-box-shadow: 0 0 0 30px white inset;
}

View file

@ -0,0 +1,67 @@
// Colors
$white: #fff !default;
$black: #000 !default;
$red: #d9534f !default;
$orange: #f0ad4e !default;
$yellow: #ffd500 !default;
$green: #5cb85c !default;
$blue: #0275d8 !default;
$teal: #5bc0de !default;
$pink: #ff5b77 !default;
$purple: #613d7c !default;
$gray-dark: #292b2c !default;
$gray: #464a4c !default;
$gray-light: #636c72 !default;
$gray-lighter: #eceeef !default;
$gray-lightest: #f7f7f9 !default;
$brand-primary: $blue !default;
$brand-success: $green !default;
$brand-info: $teal !default;
$brand-warning: $orange !default;
$brand-danger: $red !default;
$brand-inverse: $gray-dark !default;
// Links
$link-color: $brand-primary !default;
$link-decoration: none !default;
$link-hover-color: darken($link-color, 15%) !default;
$link-hover-decoration: underline !default;
// Body
$body-bg: $white !default;
$body-color: $gray-dark !default;
// Fonts
$font-family-sans-serif: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif !default;
$font-family-monospace: Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace !default;
$font-family-base: $font-family-sans-serif !default;
$font-size-base: 1rem !default;
$font-weight-normal: normal !default;
$font-weight-bold: bold !default;
$font-weight-base: $font-weight-normal !default;
$line-height-base: 1.5 !default;
$text-muted: $gray-light !default;
$dt-font-weight: $font-weight-bold !default;
// Tables
$table-cell-padding: .75rem !default;
// Options
$enable-hover-media-query: false !default;

5
allauth_ens/scss/ie.scss Normal file
View file

@ -0,0 +1,5 @@
/* Welcome to Compass. Use this file to write IE specific override styles.
* Import this file using the following HTML or equivalent:
* <!--[if IE]>
* <link href="/stylesheets/ie.css" media="screen, projection" rel="stylesheet" type="text/css" />
* <![endif]--> */

View file

@ -0,0 +1,3 @@
/* Welcome to Compass. Use this file to define print styles.
* Import this file using the following HTML or equivalent:
* <link href="/stylesheets/print.css" media="print" rel="stylesheet" type="text/css" /> */

View file

@ -0,0 +1,17 @@
/* 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";
@import "base";

View file

@ -0,0 +1,105 @@
/*************************
* Input fields handlers *
*************************/
function toggleWrapperClass(class_name, callable) {
let func = function(bool) {
if (bool === undefined)
bool = callable.apply(this);
this.wrapper.toggleClass(class_name, bool);
};
return func;
}
let Input = function(field) {
this.dom_field = field;
this.field = $(field);
this.wrapper = $(field).closest('.input-wrapper');
// initialization
this.update_focus();
this.update_has_value();
// register event handlers
this.field.focus( () => this.on_focus() );
this.field.blur( () => this.on_blur() );
this.field.on('change', () => this.on_change() );
};
Input.prototype = {
has_value: function() { return this.field.val() ? true : false; },
has_focus: function() { return this.field.is(':focus'); },
has_error: function() { return !this.has_value() && this.field.prop('required'); },
on_focus: function() { this.update_focus(true); },
on_blur: function() { this.update_focus(false); },
on_change: function() {
this.update_has_value();
this.update_error();
}
};
Object.assign(Input.prototype, {
update_focus: toggleWrapperClass('input-focused', Input.prototype.has_focus),
update_error: toggleWrapperClass('input-error', Input.prototype.has_error),
update_has_value: toggleWrapperClass('input-has-value', Input.prototype.has_value),
});
$( function() {
let fields = $('input.field');
fields.map( function() { return new Input(this); });
});
/**
* History
*/
$( function() {
$('.history-back').click( () => history.back() );
});
/**
* Keyboard shortcuts
*
* - A method can be selected by pressing Ctrl+Alt+(first letter of method name)
* (or second if first is already used...)
*/
function prepareShorcuts() {
let shorcuts = {};
$('.method-wrapper a').each( function() {
let name = $(this).text();
for (let i=0; i < name.length; i++) {
let key = name[i].toLowerCase();
if (key !== '' && shorcuts[key] === undefined) {
shorcuts[key] = this;
break;
}
}
});
window.methodsShorcuts = shorcuts;
}
$( function() {
// Register shorcuts
prepareShorcuts();
// Shorcuts handler
$(document).keydown( function(e) {
if (e.ctrlKey && e.altKey) {
let methodLink = window.methodsShorcuts[e.key];
if (methodLink !== undefined)
methodLink.click();
}
});
});

View file

@ -0,0 +1,5 @@
/* Welcome to Compass. Use this file to write IE specific override styles.
* Import this file using the following HTML or equivalent:
* <!--[if IE]>
* <link href="/stylesheets/ie.css" media="screen, projection" rel="stylesheet" type="text/css" />
* <![endif]--> */

Binary file not shown.

After

Width:  |  Height:  |  Size: 381 B

View file

@ -0,0 +1,59 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
viewBox="0 -256 1792 1792"
id="svg3013"
version="1.1"
inkscape:version="0.48.3.1 r9886"
width="100%"
height="100%"
sodipodi:docname="chevron_left_font_awesome.svg">
<metadata
id="metadata3023">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs3021" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="640"
inkscape:window-height="480"
id="namedview3019"
showgrid="false"
inkscape:zoom="0.13169643"
inkscape:cx="896"
inkscape:cy="896"
inkscape:window-x="0"
inkscape:window-y="25"
inkscape:window-maximized="0"
inkscape:current-layer="svg3013" />
<g
transform="matrix(1,0,0,-1,387.25424,1338.5763)"
id="g3015">
<path
d="M 742,-37 90,614 Q 53,651 53,704.5 53,758 90,795 l 652,651 q 37,37 90.5,37 53.5,0 90.5,-37 l 75,-75 q 37,-37 37,-90.5 0,-53.5 -37,-90.5 L 512,704 998,219 q 37,-38 37,-91 0,-53 -37,-90 L 923,-37 Q 886,-74 832.5,-74 779,-74 742,-37 z"
id="path3017"
inkscape:connector-curvature="0"
style="fill:currentColor" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

View file

@ -0,0 +1,3 @@
/* Welcome to Compass. Use this file to define print styles.
* Import this file using the following HTML or equivalent:
* <link href="/stylesheets/print.css" media="print" rel="stylesheet" type="text/css" /> */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,9 @@
{% extends "account/base.html" %}
{% load i18n %}
{% block title %}{% trans "Connexion" %} - {% project_name %}{% endblock %}
{% block header-title %}{% trans "Connexion à" %} {% project_name %}{% endblock %}
{% block content %}
<section>{% include "account/block-form.html" %}</section>
{% endblock %}

View file

@ -0,0 +1,11 @@
{% extends "authens/base.html" %}
{% load authens i18n %}
{% block title %}{% trans "Déconnexion" %} - {% project_name %}{% endblock %}
{% block header-title %}{% trans "Déconnexion de" %} {% project_name %}{% endblock %}
{% block content %}
<section>
{% trans "Vous êtes déjà déconnecté-e." %}
</section>
{% endblock %}

View file

@ -0,0 +1,55 @@
{% load static %}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>{% block title %}{% endblock %}</title>
{# Responsive UI #}
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
{# CSS #}
<link rel="stylesheet"
href="https://fonts.googleapis.com/css?family=Roboto:400,700|Roboto+Slab:400">
<link rel="stylesheet"
href="{% static "allauth_ens/screen.css" %}">
{# JS #}
<script type="text/javascript"
src="https://code.jquery.com/jquery-3.2.1.slim.min.js"
integrity="sha256-k2WSCIexGzOj3Euiig+TlR8gA0EmPjuc79OEeY5L45g="
crossorigin="anonymous"></script>
<script type="text/javascript"
src="{% static "allauth_ens/authens.js" %}"></script>
</head>
<body>
<div class="wrapper">
<header>
<button type="button" class="history-back">
<img src="{% static "allauth_ens/images/64px-Chevron_left_font_awesome.svg.png" %}">
</button>
<h1>{% block header-title %}{% endblock %}</h1>
</header>
{% include "account/block-messages.html" %}
{% block messages-extra %}{% endblock %}
<div class="content-wrapper">
{% block content %}{% endblock %}
</div>
</div>
</body>
</html>

View file

@ -0,0 +1,20 @@
{% load i18n %}
{% load widget_tweaks %}
<form action="{% url "account_login" %}" method="post">
{% csrf_token %}
<ul class="input-list">
{% for field in form %}
<li class="input-wrapper">
<label for="{{ field.id_for_label }}">{{ field.label }}</label>
{% render_field field class+="field" autocomplete="off" autocapitalize="none" placeholder="" %}
<div class="infos-spacer"></div>
{% if field.help_text %}
<p class="help">{{ field.help_text|safe }}</p>
{% endif %}
</li>
{% endfor %}
</ul>
<input type="submit" value="{% trans "Sign In" %}">
<input type="hidden" name="{{ redirect_field_name }}" value="{{ redirect_field_value }}">
</form>

View file

@ -0,0 +1,11 @@
{% if messages %}
<div class="messages-container">
<ul class="messages-list">
{% for message in messages %}
<li class="message {{ message.level_tag }}">
{{ message }}
</li>
{% endfor %}
</ul>
</div>
{% endif %}

View file

@ -0,0 +1,63 @@
{% extends "account/base.html" %}
{% load i18n %}
{% load account socialaccount %}
{% block title %}{% trans "Sign In" %} - {{ site.name }}{% endblock %}
{% block header-title %}
{% blocktrans with site.name as site_name %}
Sign in {{ site_name }}
{% endblocktrans %}
{% endblock %}
{% 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>
{% endif %}
{% endblock %}
{% block content %}
{% 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>
<ul class="method-list">
{% include "socialaccount/snippets/provider_list.html" with process="login" %}
</ul>
</section>
{% include "socialaccount/snippets/login_extra.html" %}
<div class="divider"></div>
{% endif %}
<section>
{% include "account/block-form.html" with form=form %}
</section>
{% endblock %}

View file

@ -0,0 +1,28 @@
{% extends "account/base.html" %}
{% load i18n %}
{% block title %}{% trans "Sign Out" %} - {{ site.name }}{% endblock %}
{% block header-title %}
{% blocktrans with site.name as site_name %}
Sign out {{ site_name }}
{% endblocktrans %}
{% endblock %}
{% block content %}
<section>
<p>
{% blocktrans %}
Are you sure you want to sign out?
{% endblocktrans %}
</p>
<form action="{% url "account_logout" %}" method="post">
{% csrf_token %}
{% if redirect_field_value %}
<input type="hidden" name="{{ redirect_field_name }}" value="{{ redirect_field_value }}">
{% endif %}
<input type="submit" value="{% trans "Sign Out" %}">
</form>
</section>
{% endblock %}

View file

@ -0,0 +1,32 @@
{% extends "account/base.html" %}
{% load i18n %}
{% block title %}
{% trans "Account Preferences" %} - {{ request.site.name }}
{% endblock %}
{% block header-title %}
{% blocktrans with request.site.name as site_name %}
Account Preferences - {{ site_name }}
{% endblocktrans %}
{% endblock %}
{% block content %}
<section>
<ul class="method-list">
<li class="method-wrapper">
<a href="{% url "account_change_password" %}">{% trans "Change password" %}</a>
</li>
<li class="method-wrapper">
<a href="{% url "account_email" %}">{% trans "Manage emails" %}</a>
</li>
<li class="method-wrapper">
<a href="{% url "socialaccount_connections" %}">{% trans "Check account connections" %}</a>
</li>
</ul>
</section>
{% endblock %}

View file

@ -0,0 +1,73 @@
{% extends "account/base.html" %}
{% load i18n %}
{% load socialaccount %}
{% load allauth_ens_social %}
{% block title %}{% trans "Account Connections" %} - {{ request.site.name }}{% endblock %}
{% block header-title %}
{% trans "Account Connections" %} - {{ request.site.name }}
{% endblock %}
{% block content %}
<section>
<p>
{% if form.accounts %}
{% blocktrans %}
You can sign in to your account using any of the following third party accounts:
{% endblocktrans %}
{% else %}
{% blocktrans %}
You currently have no third party accounts connected to this account.
{% endblocktrans %}
{% endif %}
</p>
<ul class="provider-list">
{% get_providers_with_accounts user as providers_with_accounts %}
{% for provider in providers_with_accounts %}
<li class="provider">
<ul class="heading">
<li>
<a class="connect"
href="{% provider_login_url provider.provider.id process="connect" scope=scope auth_params=auth_params %}">
<i class="fa fa-plus"></i>
</a>
</li>
<li>
<b>{{ provider.provider.name }}</b>
</li>
</ul>
{% if provider.accounts %}
<ul class="connected-account-list">
{% for base_account in provider.accounts %}
<li>
<span>
<small style="font-size: 14px">
{% firstof base_account.extra_data.name base_account.email %}
</small>
</span>
<span>
{% with base_account.get_provider_account as account %}
<form action="{% url "socialaccount_connections" %}" method="post">
{% csrf_token %}
<input type="hidden" name="account" value="{{ base_account.id }}">
<input type="submit" class="link" value="{% trans "Remove" %}">
</form>
{% endwith %}
</span>
</li>
{% endfor %}
</ul>
{% endif %}
{% endfor %}
</ul>
</section>
{% endblock %}

View file

@ -0,0 +1,26 @@
{% load socialaccount %}
{% if not socialaccount_providers %}
{% get_providers as socialaccount_providers %}
{% endif %}
{% for provider in socialaccount_providers %}
{% if provider.id == "openid" %}
{% for brand in provider.get_brands %}
<li class="method-wrapper">
<a title="{{ brand.name }}"
href="{% provider_login_url provider.id openid=brand.openid_url process=process %}"
>
{{ brand.name }}
</a>
</li>
{% endfor %}
{% endif %}
<li class="method-wrapper">
<a title="{{ provider.name }}"
href="{% provider_login_url provider.id process=process scope=scope auth_params=auth_parms %}"
>
{{ provider.name }}
</a>
</li>
{% endfor %}

View file

@ -0,0 +1,28 @@
import django
from django import template
from allauth.socialaccount.templatetags import socialaccount as tt_social
register = template.Library()
if django.VERSION >= (1, 9):
simple_tag = register.simple_tag
else:
simple_tag = register.assignment_tag
@simple_tag
def get_providers_with_accounts(user):
providers = tt_social.get_providers()
accounts = tt_social.get_social_accounts(user)
providers_with_accounts = [
{
'provider': provider,
'accounts': accounts.get(provider.id, []),
}
for provider in providers
]
return providers_with_accounts

8
allauth_ens/urls.py Normal file
View file

@ -0,0 +1,8 @@
from django.conf.urls import include, url
from . import views
urlpatterns = [
url(r'^settings/$', views.account_settings,
name="account_settings"),
url(r'^', include('allauth.urls')),
]

11
allauth_ens/views.py Normal file
View file

@ -0,0 +1,11 @@
from django.contrib.auth.decorators import login_required
from django.utils.decorators import method_decorator
from django.views.generic import TemplateView
@method_decorator(login_required, name="dispatch")
class SettingsAccount(TemplateView):
template_name = 'account/settings.html'
account_settings = SettingsAccount.as_view()