add user settings for Sources
This commit is contained in:
parent
e98e5e4e3e
commit
ae3c092238
|
@ -186,6 +186,12 @@ class Source(PolicyModel):
|
||||||
"""Return additional Info, such as a callback URL. Show in the administration interface."""
|
"""Return additional Info, such as a callback URL. Show in the administration interface."""
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def has_user_settings(self):
|
||||||
|
"""Entrypoint to integrate with User settings. Can either return False if no
|
||||||
|
user settings are available, or a tuple or string, string, string where the first string
|
||||||
|
is the name the item has, the second string is the icon and the third is the view-name."""
|
||||||
|
return False
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
<li class="dropdown">
|
<li class="dropdown">
|
||||||
<button class="btn btn-link dropdown-toggle nav-item-iconic" id="dropdownMenu1" data-toggle="dropdown"
|
<button class="btn btn-link dropdown-toggle nav-item-iconic" id="dropdownMenu1" data-toggle="dropdown"
|
||||||
aria-haspopup="true" aria-expanded="true">
|
aria-haspopup="true" aria-expanded="true">
|
||||||
<span title="Help" class="fa pficon-help dropdown-title"></span>
|
<span title="Help" class="fa pficon-help"></span>
|
||||||
</button>
|
</button>
|
||||||
<ul class="dropdown-menu" aria-labelledby="dropdownMenu1">
|
<ul class="dropdown-menu" aria-labelledby="dropdownMenu1">
|
||||||
{% comment %} <li><a href="#0">Help</a></li> {% endcomment %}
|
{% comment %} <li><a href="#0">Help</a></li> {% endcomment %}
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
{% load is_active %}
|
{% load is_active %}
|
||||||
|
{% load static %}
|
||||||
{% load passbook_user_settings %}
|
{% load passbook_user_settings %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
@ -24,6 +25,15 @@
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
<li class="nav-divider"></li>
|
||||||
|
{% user_sources as us %}
|
||||||
|
{% for name, icon, link in us %}
|
||||||
|
<li class="{% if link == request.get_full_path %} active {% endif %}">
|
||||||
|
<a href="{{ link }}">
|
||||||
|
<img src="{% static icon %}" alt=""> {{ name }}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
from django import template
|
from django import template
|
||||||
|
|
||||||
from passbook.core.models import Factor
|
from passbook.core.models import Factor, Source
|
||||||
from passbook.core.policies import PolicyEngine
|
from passbook.core.policies import PolicyEngine
|
||||||
|
|
||||||
register = template.Library()
|
register = template.Library()
|
||||||
|
@ -20,3 +20,17 @@ def user_factors(context):
|
||||||
if policy_engine.passing and _link:
|
if policy_engine.passing and _link:
|
||||||
matching_factors.append(_link)
|
matching_factors.append(_link)
|
||||||
return matching_factors
|
return matching_factors
|
||||||
|
|
||||||
|
@register.simple_tag(takes_context=True)
|
||||||
|
def user_sources(context):
|
||||||
|
"""Return a list of all sources which are enabled for the user"""
|
||||||
|
user = context.get('request').user
|
||||||
|
_all_sources = Source.objects.filter(enabled=True).select_subclasses()
|
||||||
|
matching_sources = []
|
||||||
|
for factor in _all_sources:
|
||||||
|
_link = factor.has_user_settings()
|
||||||
|
policy_engine = PolicyEngine(factor.policies.all())
|
||||||
|
policy_engine.for_user(user).with_request(context.get('request')).build()
|
||||||
|
if policy_engine.passing and _link:
|
||||||
|
matching_sources.append(_link)
|
||||||
|
return matching_sources
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
"""OAuth Client models"""
|
"""OAuth Client models"""
|
||||||
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.urls import reverse_lazy
|
from django.urls import reverse, reverse_lazy
|
||||||
from django.utils.translation import gettext as _
|
from django.utils.translation import gettext as _
|
||||||
|
|
||||||
from passbook.core.models import Source, UserSourceConnection
|
from passbook.core.models import Source, UserSourceConnection
|
||||||
|
@ -38,6 +38,16 @@ class OAuthSource(Source):
|
||||||
return "Callback URL: '%s'" % reverse_lazy('passbook_oauth_client:oauth-client-callback',
|
return "Callback URL: '%s'" % reverse_lazy('passbook_oauth_client:oauth-client-callback',
|
||||||
kwargs={'source_slug': self.slug})
|
kwargs={'source_slug': self.slug})
|
||||||
|
|
||||||
|
def has_user_settings(self):
|
||||||
|
"""Entrypoint to integrate with User settings. Can either return False if no
|
||||||
|
user settings are available, or a tuple or string, string, string where the first string
|
||||||
|
is the name the item has, the second string is the icon and the third is the view-name."""
|
||||||
|
icon = 'img/%s.svg' % self.get_login_button[1]
|
||||||
|
view_name = 'passbook_oauth_client:oauth-client-user'
|
||||||
|
return self.name, icon, reverse((view_name), kwargs={
|
||||||
|
'source_slug': self.slug
|
||||||
|
})
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
|
||||||
verbose_name = _('Generic OAuth Source')
|
verbose_name = _('Generic OAuth Source')
|
||||||
|
|
|
@ -1,6 +0,0 @@
|
||||||
{% load passbook_oauth_client %}
|
|
||||||
|
|
||||||
{% any_provider as enabled %}
|
|
||||||
{% if enabled %}
|
|
||||||
<div class="btn-group btn-primary btn-block">
|
|
||||||
{% endif %}
|
|
|
@ -1,6 +0,0 @@
|
||||||
{% load passbook_oauth_client %}
|
|
||||||
|
|
||||||
{% provider_exists 'facebook' as facebook_enabled %}
|
|
||||||
{% if facebook_enabled %}
|
|
||||||
<a href="{% url 'passbook_oauth_client:oauth-client-login' provider='facebook' %}" class="btn" style="background-color:#4267b2;color:white;margin-top:10px;width:100%;"><i class="fa fa-facebook-official" aria-hidden="true"></i></a>
|
|
||||||
{% endif %}
|
|
|
@ -1,6 +0,0 @@
|
||||||
{% load passbook_oauth_client %}
|
|
||||||
|
|
||||||
{% provider_exists 'twitter' as twitter_enabled %}
|
|
||||||
{% if twitter_enabled %}
|
|
||||||
<a href="{% url 'passbook_oauth_client:oauth-client-login' provider='twitter' %}" class="btn" style="background-color:#55ACEE;color:white;margin-top:10px;width:100%;"><i class="fa fa-twitter" aria-hidden="true"></i></a>
|
|
||||||
{% endif %}
|
|
|
@ -1,7 +0,0 @@
|
||||||
{% load passbook_oauth_client %}
|
|
||||||
{% load static %}
|
|
||||||
|
|
||||||
{% provider_exists 'google' as google_enabled %}
|
|
||||||
{% if google_enabled %}
|
|
||||||
<a href="{% url 'passbook_oauth_client:oauth-client-login' provider='google' %}" class="btn" style="background-color:white;color:black;margin-top:10px;width:100%;"><img src="{% static 'img/google.svg' %}" style="height:12px"></a>
|
|
||||||
{% endif %}
|
|
|
@ -1,6 +0,0 @@
|
||||||
{% load passbook_oauth_client %}
|
|
||||||
|
|
||||||
{% provider_exists 'github' as github_enabled %}
|
|
||||||
{% if github_enabled %}
|
|
||||||
<a href="{% url 'passbook_oauth_client:oauth-client-login' provider='github' %}" class="btn" style="background-color:#444444;color:white;margin-top:10px;width:100%;"><i class="fa fa-github" aria-hidden="true"></i></a>
|
|
||||||
{% endif %}
|
|
|
@ -1,7 +0,0 @@
|
||||||
{% load passbook_oauth_client %}
|
|
||||||
{% load static %}
|
|
||||||
|
|
||||||
{% provider_exists 'discord' as discord_enabled %}
|
|
||||||
{% if discord_enabled %}
|
|
||||||
<a href="{% url 'passbook_oauth_client:oauth-client-login' provider='discord' %}" class="btn" style="background-color:#2C2F33;color:white;margin-top:10px;width:100%;"><img src="{% static 'img/discord.svg' %}" style="height:12px"></a>
|
|
||||||
{% endif %}
|
|
|
@ -1,7 +0,0 @@
|
||||||
{% load passbook_oauth_client %}
|
|
||||||
{% load static %}
|
|
||||||
|
|
||||||
{% provider_exists 'reddit' as reddit_enabled %}
|
|
||||||
{% if reddit_enabled %}
|
|
||||||
<a href="{% url 'passbook_oauth_client:oauth-client-login' provider='reddit' %}" class="btn" style="background-color:#ff4500;color:white;margin-top:10px;width:100%;"><img src="{% static 'img/reddit.svg' %}" style="height:20px;margin-top:-5px;"></a>
|
|
||||||
{% endif %}
|
|
|
@ -1,6 +0,0 @@
|
||||||
{% load passbook_oauth_client %}
|
|
||||||
|
|
||||||
{% any_provider as enabled %}
|
|
||||||
{% if enabled %}
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
|
@ -1,54 +0,0 @@
|
||||||
{% extends "user/base.html" %}
|
|
||||||
|
|
||||||
{% load utils %}
|
|
||||||
{% load i18n %}
|
|
||||||
|
|
||||||
{% block title %}
|
|
||||||
{% title "Overview" %}
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
<h1><clr-icon shape="connect" size="48"></clr-icon>{% trans "OAuth2" %}</h1>
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-md-12">
|
|
||||||
<div class="card">
|
|
||||||
<div class="card-header">
|
|
||||||
{% trans "Connected Accounts" %}
|
|
||||||
</div>
|
|
||||||
<div class="card-footer">
|
|
||||||
{% if provider_state %}
|
|
||||||
<table class="table">
|
|
||||||
<thead>
|
|
||||||
<th>
|
|
||||||
<th>{% trans 'Provider' %}</th>
|
|
||||||
<th>{% trans 'Status' %}</th>
|
|
||||||
<th>{% trans 'Action' %}</th>
|
|
||||||
<th>{% trans 'ID' %}</th>
|
|
||||||
</th>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{% for data in provider_state %}
|
|
||||||
<tr>
|
|
||||||
<td></td>
|
|
||||||
<td>{% trans data.provider.ui_name %}</td>
|
|
||||||
<td>{{ data.state|yesno:"Connected,Not Connected" }}</td>
|
|
||||||
<td>
|
|
||||||
{% if data.state == False %}
|
|
||||||
<a href="{% url 'passbook_oauth_client:oauth-client-login' provider=data.provider.name %}">Connect</a>
|
|
||||||
{% else %}
|
|
||||||
<a href="{% url 'passbook_oauth_client:oauth-client-disconnect' provider=data.provider.name %}">Disconnect</a>
|
|
||||||
{% endif %}
|
|
||||||
</td>
|
|
||||||
<td>{{ data.aas.first.identifier }}</td>
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
{% else %}
|
|
||||||
<p>{% trans "No Providers configured!" %}</p>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
{% extends "user/base.html" %}
|
||||||
|
|
||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
{% block page %}
|
||||||
|
<h1>{{ source.name }}</h1>
|
||||||
|
{% if connections.exists %}
|
||||||
|
<p>{% trans 'Connected.' %}</p>
|
||||||
|
<a class="btn btn-danger" href="{% url 'passbook_oauth_client:oauth-client-disconnect' source_slug=source.slug %}">
|
||||||
|
{% trans 'Disconnect' %}
|
||||||
|
</a>
|
||||||
|
{% else %}
|
||||||
|
<p>Not connected.</p>
|
||||||
|
<a class="btn btn-primary" href="{% url 'passbook_oauth_client:oauth-client-login' source_slug=source.slug %}">
|
||||||
|
{% trans 'Connect' %}
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
{% endblock %}
|
|
@ -3,7 +3,7 @@
|
||||||
from django.urls import path
|
from django.urls import path
|
||||||
|
|
||||||
from passbook.oauth_client.source_types.manager import RequestKind
|
from passbook.oauth_client.source_types.manager import RequestKind
|
||||||
from passbook.oauth_client.views import core, dispatcher
|
from passbook.oauth_client.views import core, dispatcher, user
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path('login/<slug:source_slug>/', dispatcher.DispatcherView.as_view(
|
path('login/<slug:source_slug>/', dispatcher.DispatcherView.as_view(
|
||||||
|
@ -12,4 +12,6 @@ urlpatterns = [
|
||||||
kind=RequestKind.callback), name='oauth-client-callback'),
|
kind=RequestKind.callback), name='oauth-client-callback'),
|
||||||
path('disconnect/<slug:source_slug>/', core.DisconnectView.as_view(),
|
path('disconnect/<slug:source_slug>/', core.DisconnectView.as_view(),
|
||||||
name='oauth-client-disconnect'),
|
name='oauth-client-disconnect'),
|
||||||
|
path('user/<slug:source_slug>/', user.UserSettingsView.as_view(),
|
||||||
|
name='oauth-client-user'),
|
||||||
]
|
]
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
"""passbook oauth_client user views"""
|
||||||
|
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||||
|
from django.shortcuts import get_object_or_404
|
||||||
|
from django.views.generic import TemplateView
|
||||||
|
|
||||||
|
from passbook.oauth_client.models import OAuthSource, UserOAuthSourceConnection
|
||||||
|
|
||||||
|
|
||||||
|
class UserSettingsView(LoginRequiredMixin, TemplateView):
|
||||||
|
"""Show user current connection state"""
|
||||||
|
|
||||||
|
template_name = 'oauth_client/user.html'
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
source = get_object_or_404(OAuthSource, slug=self.kwargs.get('source_slug'))
|
||||||
|
connections = UserOAuthSourceConnection.objects.filter(user=self.request.user,
|
||||||
|
source=source)
|
||||||
|
kwargs['source'] = source
|
||||||
|
kwargs['connections'] = connections
|
||||||
|
return super().get_context_data(**kwargs)
|
Reference in New Issue