Commit b17f9027 authored by Olga Brani's avatar Olga Brani
Browse files

Bug fixes

Style improvents
Authorisation methods page
parent b655c9c1
...@@ -458,8 +458,6 @@ form.quotas-form legend span.info span { width:395px; } ...@@ -458,8 +458,6 @@ form.quotas-form legend span.info span { width:395px; }
.stats .green .img-wrap { background-position: -263px 7px; } .stats .green .img-wrap { background-position: -263px 7px; }
.projects .editable form textarea { width:70%; height:50px; max-width:70%; width:270px; height:120px;} .projects .editable form textarea { width:70%; height:50px; max-width:70%; width:270px; height:120px;}
/* temp style to hide extra menu for groups */
.navigation ul+ul { display:none; }
table .msg-wrap { position:relative; } table .msg-wrap { position:relative; }
table .msg-wrap .dialog { position:absolute; border:1px dashed #ccc; padding:15px; width:200px; bottom:30px; left:0; background:#fff; display:none; } table .msg-wrap .dialog { position:absolute; border:1px dashed #ccc; padding:15px; width:200px; bottom:30px; left:0; background:#fff; display:none; }
...@@ -487,8 +485,17 @@ form.quotas-form span.error-msg:hover em { background-position:-58px -3px; } ...@@ -487,8 +485,17 @@ form.quotas-form span.error-msg:hover em { background-position:-58px -3px; }
.content .how-it-works a.submit:focus { border-color: #B3B3B3} .content .how-it-works a.submit:focus { border-color: #B3B3B3}
.content .how-it-works a.submit:focus:hover { border-color: #55B577} .content .how-it-works a.submit:focus:hover { border-color: #55B577}
.auth_methods { margin:3em 0; } .auth_methods ul { margin:1em 0; padding:0; list-style:none outside none; }
.auth_methods .wrap { } .auth_methods ul li { margin:0 0 1em 0; padding:0; list-style:none outside none; font-size:1.154em; }
.auth_methods h2 { font-size:1.154em; } .auth_methods ul li>a { padding-right:20px; background:url(../images/arrow-down_green.png) no-repeat center right; color:#55B577 }
.auth_methods table { width:100%; color:#222; margin:1em 0; } .auth_methods ul li>a.up { background-image:url(../images/arrow-up_green.png); }
.auth_methods table th { font-weight:normal; color:#3582AC } .auth_methods ul li .wrap { font-size:0.867em; margin-top:1em; display:none; }
\ No newline at end of file .auth_methods ul li .actions a { margin-right:20px; }
.auth_methods ul li a.red { color:#F24E53; }
.auth_methods ul.notassigned { margin-top:3em; }
.auth_methods ul.notassigned li>a { background:transparent; color: #F89A1C}
.auth_methods .dialog-wrap { display:inline; position:relative; }
.auth_methods .dialog { background:#fff; border:1px dashed #ccc; position:absolute; bottom:30px; left:0; padding:15px; width:220px; display:none;}
.auth_methods .dialog .submit { min-width:30px; padding:5px 22px; }
.content input:-webkit-autofill { background: transparent; }
...@@ -288,6 +288,34 @@ $(document).ready(function() { ...@@ -288,6 +288,34 @@ $(document).ready(function() {
$('.hidden-submit .form-row.submit').show(500); $('.hidden-submit .form-row.submit').show(500);
}); });
$('.auth_methods').find('li>a').click(function(e){
e.preventDefault();
$(this).siblings('.wrap').toggle('slow');
$(this).toggleClass('up');
});
$('.auth_methods a.red').click(function(e){
e.preventDefault();
$(this).siblings('.dialog').show();
})
$('.auth_methods .dialog .no').click( function(e){
e.preventDefault();
console.log($(this));
$(this).parents('.dialog').hide();
})
setTimeout(function() {
if ($('input#id_username').val()){
$('input#id_username').siblings('label').css('opacity','0');
};
if ($('input#id_password').val()){
$('input#id_password').siblings('label').css('opacity','0');
}
}, 100);
}); });
$(window).resize(function() { $(window).resize(function() {
......
{% extends "im/account_base.html" %} {% extends "im/account_base.html" %}
{% block page.body %} {% block page.body %}
<div class="full bottom-bordered clearfix"> <div class="full clearfix">
<div class="lt-div"> <div class="lt-div">
<p>Invite someone else</p> <p>Invite someone else</p>
</div> </div>
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
</div> </div>
<div class="full {% block innerpage.class %}{% endblock %}"> <div class="full full-dotted">
<h2>You have <em>{{ inviter.invitations }}</em> invitation{{ inviter.invitations|pluralize }} left.</h2> <h2>You have <em>{{ inviter.invitations }}</em> invitation{{ inviter.invitations|pluralize }} left.</h2>
{% if sent|length %} {% if sent|length %}
......
...@@ -13,58 +13,64 @@ ...@@ -13,58 +13,64 @@
<input type="hidden" name="auth" value="{{ user.auth_token }}"> <input type="hidden" name="auth" value="{{ user.auth_token }}">
<input type="submit" class="submit altcol" value="UPDATE" /> <input type="submit" class="submit altcol" value="UPDATE" />
</div> </div>
</form>
<div class="auth_methods"> <div class="full-dotted">
<br /><br /> <div class="auth_methods">
<div class="assigned"> <h2>ENABLED AUTHENTICATION METHODS</h2>
<h4>Authentication methods</h4> <ul>
<p>You can login to your account using the following methods</p> {% for provider in user_providers %}
<ul class="auth_providers"> <li>
{% for provider in user_providers %} <a href="#">{{ provider.settings.title }}</a>
<li> <div class="wrap">
<h2> <p>{{ provider.details_display }}</p>
{{ provider.settings.title }} <div class="actions">
<span class="actions" style="margin-left: 40px">
{% for name, url in provider.settings.extra_actions %} {% for name, url in provider.settings.extra_actions %}
<a href="{{ url }}" title="{{ name }}">{{ name }}</a> <a href="{{ url }}" title="{{ name }}">{{ name }}</a>
{% endfor %} {% endfor %}
{% if provider.can_remove %} {% if provider.can_remove %}
<a href="{% url remove_auth_provider provider.pk %}" title="disble">Remove</a> <div class="dialog-wrap">
{% endif %} <a href="#" title="disable" class="red">
</span> Disable x</a>
</h2> <div class="dialog">Are you sure you want to disable this method?
<p>{{ provider.details_display }}</p> <a href="{% url remove_auth_provider provider.pk %}" class="yes submit">Yes</a>&nbsp;&nbsp;&nbsp;<a href="#" class="no submit">No</a>
<br /> </div>
</li> </div>
{% empty %}
<li>No available authentication methods</li> {% endif %}
{% endfor %} </div>
</ul> </div>
</div> </li>
<div class="notassigned"> {% empty %}
<p>You can add the following authentication methods to your account </p> <li>No available authentication methods</li>
<ul class="auth_providers"> {% endfor %}
{% for provider in user_available_providers %}
<li> </ul>
<h2><a href="{{ provider.add_url }}">{{ provider.title }}</a></h2> <ul class="notassigned">
<p>{{ provider.add_description }}</p> <li>
<br /> <a href="#">+ Add new authentication method</a>
</li>
{% empty %} <div class="wrap">
No available providers. {% for provider in user_available_providers %}
{% endfor %} <p><a href="{{ provider.add_url }}">{{ provider.title }}</a> ( {{ provider.add_description }})</p>
</ul> {% empty %}
</div> No available providers
{% endfor %}
</div>
</li>
</ul>
</div> </div>
</div>
</form> <div class="full-dotted">
<ul class="options">
<div class="two-cols-links"> <li><a href="https://okeanos.grnet.gr/home/" class="blue">Back to ~okeanos ></a></li>
<p><a href="{% url password_change %}">Change Password</a></p> <li><a href="https://cyclades.okeanos.grnet.gr/ui/" class="blue">Take me to cyclades ></a></li>
<p> <li><a href="https://pithos.okeanos.grnet.gr/ui/" class="blue">Take me to pithos+ ></a></li>
<a href="https://okeanos.grnet.gr/home/">Back to ~okeanos</a> </ul>
<a href="https://cyclades.okeanos.grnet.gr/ui/">Take me to cyclades</a>
<a href="https://pithos.okeanos.grnet.gr/ui/">Take me to pithos+</a>
</p>
</div> </div>
{% endblock body %} {% endblock body %}
{% extends "im/account_base.html" %}
{% block body %}
<form action={%url edit_profile %} method="post" class="withlabels hidden-submit">{% csrf_token %}
{% with profile_form as form %}
{% include "im/form_render.html" %}
{% endwith %}
<div class="form-row submit">
<input type="hidden" name="next" value="{{ next }}">
<input type="hidden" name="auth" value="{{ user.auth_token }}">
<input type="submit" class="submit altcol" value="UPDATE" />
</div>
<div class="auth_methods">
<br /><br />
<div class="assigned">
<h2><a href="#">Available authentication methods</a></h2>
<p>You can login to your account using the following methods</p>
<ul class="auth_providers">
{% for provider in user_providers %}
<li>
<h2>
{{ provider.settings.title }}
<span class="actions" style="margin-left: 40px">
{% for name, url in provider.settings.extra_actions %}
<a href="{{ url }}" title="{{ name }}">{{ name }}</a>
{% endfor %}
{% if provider.can_remove %}
<a href="{% url remove_auth_provider provider.pk %}" title="disble">Remove</a>
{% endif %}
</span>
</h2>
<p>{{ provider.details_display }}</p>
<br />
</li>
{% empty %}
<li>No available authentication methods</li>
{% endfor %}
</ul>
</div>
<div class="notassigned">
<p>You can add the following authentication methods to your account </p>
<ul class="auth_providers">
{% for provider in user_available_providers %}
<li>
<h2><a href="{{ provider.add_url }}">{{ provider.title }}</a></h2>
<p>{{ provider.add_description }}</p>
<br />
</li>
{% empty %}
No available providers.
{% endfor %}
</ul>
</div>
</div>
</form>
<div class="two-cols-links">
<p><a href="{% url password_change %}">Change Password</a></p>
<p>
<a href="https://okeanos.grnet.gr/home/">Back to ~okeanos</a>
<a href="https://cyclades.okeanos.grnet.gr/ui/">Take me to cyclades</a>
<a href="https://pithos.okeanos.grnet.gr/ui/">Take me to pithos+</a>
</p>
</div>
{% endblock body %}
...@@ -57,6 +57,7 @@ from django.views.generic.create_update import (delete_object, ...@@ -57,6 +57,7 @@ from django.views.generic.create_update import (delete_object,
get_model_and_form_class) get_model_and_form_class)
from django.views.generic.list_detail import object_list from django.views.generic.list_detail import object_list
from django.core.xheaders import populate_xheaders from django.core.xheaders import populate_xheaders
from django.core.exceptions import ValidationError, PermissionDenied
from django.template.loader import render_to_string from django.template.loader import render_to_string
from django.views.decorators.http import require_http_methods from django.views.decorators.http import require_http_methods
...@@ -64,7 +65,7 @@ from astakos.im.activation_backends import get_backend, SimpleBackend ...@@ -64,7 +65,7 @@ from astakos.im.activation_backends import get_backend, SimpleBackend
from astakos.im.models import (AstakosUser, ApprovalTerms, AstakosGroup, from astakos.im.models import (AstakosUser, ApprovalTerms, AstakosGroup,
EmailChange, GroupKind, Membership, EmailChange, GroupKind, Membership,
RESOURCE_SEPARATOR) RESOURCE_SEPARATOR, AstakosUserAuthProvider)
from astakos.im.util import get_context, prepare_response, get_query, restrict_next from astakos.im.util import get_context, prepare_response, get_query, restrict_next
from astakos.im.forms import (LoginForm, InvitationForm, ProfileForm, from astakos.im.forms import (LoginForm, InvitationForm, ProfileForm,
FeedbackForm, SignApprovalTermsForm, FeedbackForm, SignApprovalTermsForm,
...@@ -87,6 +88,8 @@ from astakos.im.tasks import request_billing ...@@ -87,6 +88,8 @@ from astakos.im.tasks import request_billing
from astakos.im.api.callpoint import AstakosCallpoint from astakos.im.api.callpoint import AstakosCallpoint
import astakos.im.messages as astakos_messages import astakos.im.messages as astakos_messages
from astakos.im import settings
from astakos.im import auth_providers
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
...@@ -109,6 +112,26 @@ def render_response(template, tab=None, status=200, context_instance=None, **kwa ...@@ -109,6 +112,26 @@ def render_response(template, tab=None, status=200, context_instance=None, **kwa
response = HttpResponse(html, status=status) response = HttpResponse(html, status=status)
return response return response
def requires_auth_provider(provider_id, **perms):
"""
"""
def decorator(func, *args, **kwargs):
@wraps(func)
def wrapper(request, *args, **kwargs):
provider = auth_providers.get_provider(provider_id)
if not provider or not provider.is_active():
raise PermissionDenied
if provider:
for pkey, value in perms.iteritems():
attr = 'is_available_for_%s' % pkey.lower()
if getattr(provider, attr)() != value:
raise PermissionDenied
return func(request, *args)
return wrapper
return decorator
def requires_anonymous(func): def requires_anonymous(func):
""" """
...@@ -169,7 +192,7 @@ def index(request, login_template_name='im/login.html', profile_template_name='i ...@@ -169,7 +192,7 @@ def index(request, login_template_name='im/login.html', profile_template_name='i
template_name = login_template_name template_name = login_template_name
if request.user.is_authenticated(): if request.user.is_authenticated():
return HttpResponseRedirect(reverse('astakos.im.views.edit_profile')) return HttpResponseRedirect(reverse('astakos.im.views.edit_profile'))
return render_response( return render_response(
template_name, template_name,
login_form = LoginForm(request=request), login_form = LoginForm(request=request),
...@@ -319,11 +342,19 @@ def edit_profile(request, template_name='im/profile.html', extra_context=None): ...@@ -319,11 +342,19 @@ def edit_profile(request, template_name='im/profile.html', extra_context=None):
except ValueError, ve: except ValueError, ve:
messages.success(request, ve) messages.success(request, ve)
elif request.method == "GET": elif request.method == "GET":
if not request.user.is_verified: request.user.is_verified = True
request.user.is_verified = True request.user.save()
request.user.save()
# existing providers
user_providers = request.user.get_active_auth_providers()
# providers that user can add
user_available_providers = request.user.get_available_auth_providers()
return render_response(template_name, return render_response(template_name,
profile_form = form, profile_form = form,
user_providers = user_providers,
user_available_providers = user_available_providers,
context_instance = get_context(request, context_instance = get_context(request,
extra_context)) extra_context))
...@@ -370,6 +401,9 @@ def signup(request, template_name='im/signup.html', on_success='im/signup_comple ...@@ -370,6 +401,9 @@ def signup(request, template_name='im/signup.html', on_success='im/signup_comple
return HttpResponseRedirect(reverse('edit_profile')) return HttpResponseRedirect(reverse('edit_profile'))
provider = get_query(request).get('provider', 'local') provider = get_query(request).get('provider', 'local')
if not auth_providers.get_provider(provider).is_available_for_create():
raise PermissionDenied
id = get_query(request).get('id') id = get_query(request).get('id')
try: try:
instance = AstakosUser.objects.get(id=id) if id else None instance = AstakosUser.objects.get(id=id) if id else None
...@@ -390,7 +424,9 @@ def signup(request, template_name='im/signup.html', on_success='im/signup_comple ...@@ -390,7 +424,9 @@ def signup(request, template_name='im/signup.html', on_success='im/signup_comple
result = backend.handle_activation(user) result = backend.handle_activation(user)
status = messages.SUCCESS status = messages.SUCCESS
message = result.message message = result.message
user.save()
form.store_user(user, request)
if 'additional_email' in form.cleaned_data: if 'additional_email' in form.cleaned_data:
additional_email = form.cleaned_data['additional_email'] additional_email = form.cleaned_data['additional_email']
if additional_email != user.email: if additional_email != user.email:
...@@ -406,6 +442,7 @@ def signup(request, template_name='im/signup.html', on_success='im/signup_comple ...@@ -406,6 +442,7 @@ def signup(request, template_name='im/signup.html', on_success='im/signup_comple
transaction.commit() transaction.commit()
return response return response
messages.add_message(request, status, message) messages.add_message(request, status, message)
transaction.commit()
return render_response( return render_response(
on_success, on_success,
context_instance=get_context( context_instance=get_context(
...@@ -655,6 +692,10 @@ def change_email(request, activation_key=None, ...@@ -655,6 +692,10 @@ def change_email(request, activation_key=None,
def send_activation(request, user_id, template_name='im/login.html', extra_context=None): def send_activation(request, user_id, template_name='im/login.html', extra_context=None):
if settings.MODERATION_ENABLED:
raise PermissionDenied
extra_context = extra_context or {} extra_context = extra_context or {}
try: try:
u = AstakosUser.objects.get(id=user_id) u = AstakosUser.objects.get(id=user_id)
...@@ -677,107 +718,107 @@ def send_activation(request, user_id, template_name='im/login.html', extra_conte ...@@ -677,107 +718,107 @@ def send_activation(request, user_id, template_name='im/login.html', extra_conte
) )
class ResourcePresentation(): class ResourcePresentation():
def __init__(self, data): def __init__(self, data):
self.data = data self.data = data
def update_from_result(self, result): def update_from_result(self, result):
if result.is_success: if result.is_success:
for r in result.data: for r in result.data:
rname = '%s%s%s' % (r.get('service'), RESOURCE_SEPARATOR, r.get('name')) rname = '%s%s%s' % (r.get('service'), RESOURCE_SEPARATOR, r.get('name'))
if not rname in self.data['resources']: if not rname in self.data['resources']:
self.data['resources'][rname] = {} self.data['resources'][rname] = {}
self.data['resources'][rname].update(r) self.data['resources'][rname].update(r)
self.data['resources'][rname]['id'] = rname self.data['resources'][rname]['id'] = rname
group = r.get('group') group = r.get('group')
if not group in self.data['groups']: if not group in self.data['groups']:
self.data['groups'][group] = {} self.data['groups'][group] = {}
self.data['groups'][r.get('group')].update({'name': r.get('group')}) self.data['groups'][r.get('group')].update({'name': r.get('group')})
def test(self, quota_dict): def test(self, quota_dict):
for k, v in quota_dict.iteritems(): for k, v in quota_dict.iteritems():
rname = k rname = k
value = v value = v
if not rname in self.data['resources']: if not rname in self.data['resources']:
self.data['resources'][rname] = {} self.data['resources'][rname] = {}
self.data['resources'][rname]['value'] = value self.data['resources'][rname]['value'] = value
def update_from_result_report(self, result): def update_from_result_report(self, result):
if result.is_success: if result.is_success:
for r in result.data: for r in result.data:
rname = r.get('name') rname = r.get('name')
if not rname in self.data['resources']: if not rname in self.data['resources']:
self.data['resources'][rname] = {} self.data['resources'][rname] = {}
self.data['resources'][rname].update(r) self.data['resources'][rname].update(r)
self.data['resources'][rname]['id'] = rname self.data['resources'][rname]['id'] = rname
group = r.get('group') group = r.get('group')
if not group in self.data['groups']: if not group in self.data['groups']:
self.data['groups'][group] = {} self.data['groups'][group] = {}
self.data['groups'][r.get('group')].update({'name': r.get('group')}) self.data['groups'][r.get('group')].update({'name': r.get('group')})
def get_group_resources(self, group): def get_group_resources(self, group):
return dict(filter(lambda t: t[1].get('group') == group, self.data['resources'].iteritems())) return dict(filter(lambda t: t[1].get('group') == group, self.data['resources'].iteritems()))
def get_groups_resources(self): def get_groups_resources(self):
for g in self.data['groups']: for g in self.data['groups']:
yield g, self.get_group_resources(g) yield g, self.get_group_resources(g)
def get_quota(self, group_quotas): def get_quota(self, group_quotas):
for r, v in group_quotas.iteritems(): for r, v in group_quotas.iteritems():
rname = str(r) rname = str(r)
quota = self.data['resources'].get(rname) quota = self.data['resources'].get(rname)
quota['value'] = v quota['value'] = v
yield quota yield quota
def get_policies(self, policies_data): def get_policies(self, policies_data):
for policy in policies_data: for policy in policies_data:
rname = '%s%s%s' % (policy.get('service'), RESOURCE_SEPARATOR, policy.get('resource')) rname = '%s%s%s' % (policy.get('service'), RESOURCE_SEPARATOR, policy.get('resource'))
policy.update(self.data['resources'].get(rname)) policy.update(self.data['resources'].get(rname))
yield policy yield policy
def __repr__(self):