mirror of
https://gitlab.com/allianceauth/allianceauth.git
synced 2025-07-16 07:50:16 +02:00
Fix registration.
Fix state assignment. Fix character ownership transfer. Disable non-staff passwords. Fix dashboard groups panel placement. Fix corpstats viewmodel retrieval.
This commit is contained in:
parent
ab10f062f7
commit
963cecb365
@ -4,5 +4,5 @@ from __future__ import absolute_import, unicode_literals
|
||||
# Django starts so that shared_task will use this app.
|
||||
from .celeryapp import app as celery_app # noqa
|
||||
|
||||
__version__ = '1.15.0'
|
||||
__version__ = '1.16-dev'
|
||||
NAME = 'Alliance Auth v%s' % __version__
|
||||
|
@ -225,6 +225,7 @@ SITE_NAME = 'Alliance Auth'
|
||||
#################
|
||||
# EMAIL SETTINGS
|
||||
#################
|
||||
# DEFAULT_FROM_EMAIL - no-reply email address
|
||||
# DOMAIN - The Alliance Auth domain (or subdomain) address, starting with http://
|
||||
# EMAIL_HOST - SMTP Server URL
|
||||
# EMAIL_PORT - SMTP Server PORT
|
||||
@ -232,6 +233,7 @@ SITE_NAME = 'Alliance Auth'
|
||||
# EMAIL_HOST_PASSWORD - Email Password
|
||||
# EMAIL_USE_TLS - Set to use TLS encryption
|
||||
#################
|
||||
DEFAULT_FROM_EMAIL = 'no-reply@example.com'
|
||||
DOMAIN = 'https://example.com'
|
||||
EMAIL_HOST = 'smtp.gmail.com'
|
||||
EMAIL_PORT = 587
|
||||
@ -261,10 +263,12 @@ ESI_SSO_CALLBACK_URL = ''
|
||||
# LOGIN_REDIRECT_URL - default destination when logging in if no redirect specified
|
||||
# LOGOUT_REDIRECT_URL - destination after logging out
|
||||
# LOGIN_TOKEN_SCOPES - scopes required on new tokens when logging in. Cannot be blank.
|
||||
# ACCOUNT_ACTIVATION_DAYS - number of days email verification tokens are valid for
|
||||
##################
|
||||
LOGIN_REDIRECT_URL = 'authentication:dashboard'
|
||||
LOGOUT_REDIRECT_URL = 'authentication:dashboard'
|
||||
LOGIN_TOKEN_SCOPES = ['esi-characters.read_opportunities.v1']
|
||||
ACCOUNT_ACTIVATION_DAYS = 1
|
||||
|
||||
#####################
|
||||
# Alliance Market
|
||||
|
@ -4,6 +4,7 @@ from django.conf.urls.i18n import i18n_patterns
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.contrib import admin
|
||||
import authentication.urls
|
||||
from authentication import hmac_urls
|
||||
import authentication.views
|
||||
import services.views
|
||||
import groupmanagement.views
|
||||
@ -19,6 +20,7 @@ import esi.urls
|
||||
import permissions_tool.urls
|
||||
from alliance_auth import NAME
|
||||
from alliance_auth.hooks import get_hooks
|
||||
from django.views.generic.base import TemplateView
|
||||
|
||||
admin.site.site_header = NAME
|
||||
|
||||
@ -30,6 +32,8 @@ urlpatterns = [
|
||||
|
||||
# Authentication
|
||||
url(r'', include(authentication.urls, namespace='authentication')),
|
||||
url(r'^account/login/$', TemplateView.as_view(template_name='public/login.html'), name='auth_login_user'),
|
||||
url(r'account/', include(hmac_urls)),
|
||||
|
||||
# Admin urls
|
||||
url(r'^admin/', include(admin.site.urls)),
|
||||
|
@ -5,7 +5,7 @@ from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
|
||||
from django.contrib.auth.models import User
|
||||
from django.utils.text import slugify
|
||||
from django import forms
|
||||
from authentication.models import State, get_guest_state
|
||||
from authentication.models import State, get_guest_state, CharacterOwnership, UserProfile
|
||||
from alliance_auth.hooks import get_hooks
|
||||
from services.hooks import ServicesHook
|
||||
|
||||
@ -97,3 +97,6 @@ class StateAdmin(admin.ModelAdmin):
|
||||
if obj == get_guest_state():
|
||||
return False
|
||||
|
||||
|
||||
admin.site.register(CharacterOwnership)
|
||||
admin.site.register(UserProfile)
|
||||
|
@ -45,7 +45,7 @@ class StateBackend(ModelBackend):
|
||||
return self.create_user(token)
|
||||
|
||||
def create_user(self, token):
|
||||
username = self.iterate_username(token.charater_name) # build unique username off character name
|
||||
username = self.iterate_username(token.character_name) # build unique username off character name
|
||||
user = User.objects.create_user(username)
|
||||
user.set_unusable_password() # prevent login via password
|
||||
user.is_active = False # prevent login until email set
|
||||
|
13
authentication/hmac_urls.py
Normal file
13
authentication/hmac_urls.py
Normal file
@ -0,0 +1,13 @@
|
||||
from django.conf.urls import url, include
|
||||
from authentication import views
|
||||
|
||||
urlpatterns = [
|
||||
url(r'^activate/complete/$', views.activation_complete, name='registration_activation_complete'),
|
||||
# The activation key can make use of any character from the
|
||||
# URL-safe base64 alphabet, plus the colon as a separator.
|
||||
url(r'^activate/(?P<activation_key>[-:\w]+)/$', views.ActivationView.as_view(), name='registration_activate'),
|
||||
url(r'^register/$', views.RegistrationView.as_view(), name='registration_register'),
|
||||
url(r'^register/complete/$', views.registration_complete, name='registration_complete'),
|
||||
url(r'^register/closed/$', views.registration_closed, name='registration_disallowed'),
|
||||
url(r'', include('registration.auth_urls')),
|
||||
]
|
@ -7,21 +7,25 @@ import logging
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def available_states_query(character):
|
||||
query = Q(member_characters__character_id=character.character_id)
|
||||
query |= Q(member_corporations__corporation_id=character.corporation_id)
|
||||
query |= Q(member_alliances__alliance_id=character.alliance_id)
|
||||
query |= Q(public=True)
|
||||
return query
|
||||
|
||||
|
||||
class CharacterOwnershipManager(Manager):
|
||||
def create_by_token(self, token):
|
||||
if not EveCharacter.objects.filter(character_id=token.character_id).exists():
|
||||
EveManager.create_character(token.character_id)
|
||||
return self.create(character=EveCharacter.objects.get(characte_id=token.character_id), user=token.user,
|
||||
return self.create(character=EveCharacter.objects.get(character_id=token.character_id), user=token.user,
|
||||
owner_hash=token.character_owner_hash)
|
||||
|
||||
|
||||
class StateQuerySet(QuerySet):
|
||||
def available_to_character(self, character):
|
||||
query = Q(member_characters__character_id=character.character_id)
|
||||
query |= Q(member_corporations__corporation_id=character.corporation_id)
|
||||
query |= Q(member_alliances__alliance_id=character.alliance_id)
|
||||
query |= Q(public=True)
|
||||
return self.filter(query)
|
||||
return self.filter(available_states_query(character))
|
||||
|
||||
def available_to_user(self, user):
|
||||
if user.profile.main_character:
|
||||
@ -41,7 +45,7 @@ class StateManager(Manager):
|
||||
return self.get_queryset().available_to_user(user)
|
||||
|
||||
def get_for_character(self, character):
|
||||
states = self.get_queryset().available_to_character(character).order_by('priority')
|
||||
states = self.get_queryset().available_to_character(character)
|
||||
if states.exists():
|
||||
return states[0]
|
||||
else:
|
||||
|
@ -6,6 +6,7 @@ import authentication.models
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
from django.contrib.auth.hashers import make_password
|
||||
|
||||
|
||||
def create_guest_state(apps, schema_editor):
|
||||
@ -41,8 +42,8 @@ def create_member_group(apps, schema_editor):
|
||||
State = apps.get_model('authentication', 'State')
|
||||
member_state_name = getattr(settings, 'DEFAULT_AUTH_GROUP', 'Member')
|
||||
|
||||
g = Group.objects.get_or_create(name=member_state_name)[0]
|
||||
try:
|
||||
g = Group.objects.get(name=member_state_name)
|
||||
# move permissions back
|
||||
state = State.objects.get(name=member_state_name)
|
||||
[g.permissions.add(p.pk) for p in state.permissions.all()]
|
||||
@ -50,7 +51,7 @@ def create_member_group(apps, schema_editor):
|
||||
# move users back
|
||||
for profile in state.userprofile_set.all().select_related('user'):
|
||||
profile.user.groups.add(g.pk)
|
||||
except State.DoesNotExist:
|
||||
except (Group.DoesNotExist, State.DoesNotExist):
|
||||
pass
|
||||
|
||||
|
||||
@ -82,8 +83,8 @@ def create_blue_group(apps, schema_editor):
|
||||
State = apps.get_model('authentication', 'State')
|
||||
blue_state_name = getattr(settings, 'DEFAULT_BLUE_GROUP', 'Blue')
|
||||
|
||||
g = Group.objects.get_or_create(name=blue_state_name)[0]
|
||||
try:
|
||||
g = Group.objects.get(name=blue_state_name)
|
||||
# move permissions back
|
||||
state = State.objects.get(name=blue_state_name)
|
||||
[g.permissions.add(p.pk) for p in state.permissions.all()]
|
||||
@ -91,7 +92,7 @@ def create_blue_group(apps, schema_editor):
|
||||
# move users back
|
||||
for profile in state.userprofile_set.all().select_related('user'):
|
||||
profile.user.groups.add(g.pk)
|
||||
except State.DoesNotExist:
|
||||
except (Group.DoesNotExist, State.DoesNotExist):
|
||||
pass
|
||||
|
||||
|
||||
@ -124,17 +125,18 @@ def create_profiles(apps, schema_editor):
|
||||
unique_mains = [auth['main_char_id'] for auth in
|
||||
AuthServicesInfo.objects.exclude(main_char_id='').values('main_char_id').annotate(
|
||||
n=models.Count('main_char_id')) if
|
||||
auth['n'] == 1 and EveCharacter.objects.filter(character_id=auth['main_char_id'].exists())]
|
||||
auth['n'] == 1 and EveCharacter.objects.filter(character_id=auth['main_char_id']).exists()]
|
||||
|
||||
auths = AuthServicesInfo.objects.filter(main_char_id__in=unique_mains).select_related('user')
|
||||
for auth in auths:
|
||||
# carry states and mains forward
|
||||
profile = UserProfile.objects.get_or_create(user=auth.user.pk)
|
||||
state = State.objects.get(name=auth.state if auth.state else 'Guest')
|
||||
profile.state = state.pk
|
||||
char = EveCharacter.objects.get(character_id=auth.main_char_id)
|
||||
profile.main_character = char.pk
|
||||
profile.save()
|
||||
profile = UserProfile.objects.create(user=auth.user, state=state, main_character=char)
|
||||
for auth in AuthServicesInfo.objects.exclude(main_char_id__in=unique_mains).select_related('user'):
|
||||
# prepare empty profiles
|
||||
state = State.objects.get(name='Guest')
|
||||
UserProfile.objects.create(user=auth.user, state=state)
|
||||
|
||||
|
||||
def recreate_authservicesinfo(apps, schema_editor):
|
||||
@ -154,6 +156,15 @@ def recreate_authservicesinfo(apps, schema_editor):
|
||||
AuthServicesInfo.objects.update_or_create(user=profile.user, defaults={'state': profile.state.name})
|
||||
|
||||
|
||||
def disable_passwords(apps, schema_editor):
|
||||
User = apps.get_model('auth', 'User')
|
||||
for u in User.objects.exclude(is_staff=True):
|
||||
# remove passwords for non-staff users to prevent password-based authentication
|
||||
# set_unusable_password is unavailable in migrations because :reasons:
|
||||
u.password = make_password(None)
|
||||
u.save()
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
('auth', '0008_alter_user_username_max_length'),
|
||||
@ -187,13 +198,13 @@ class Migration(migrations.Migration):
|
||||
('name', models.CharField(max_length=20, unique=True)),
|
||||
('priority', models.IntegerField(unique=True)),
|
||||
('public', models.BooleanField(default=False)),
|
||||
('member_alliances', models.ManyToManyField(to='eveonline.EveAllianceInfo')),
|
||||
('member_characters', models.ManyToManyField(to='eveonline.EveCharacter')),
|
||||
('member_corporations', models.ManyToManyField(to='eveonline.EveCorporationInfo')),
|
||||
('member_alliances', models.ManyToManyField(blank=True,to='eveonline.EveAllianceInfo')),
|
||||
('member_characters', models.ManyToManyField(blank=True,to='eveonline.EveCharacter')),
|
||||
('member_corporations', models.ManyToManyField(blank=True,to='eveonline.EveCorporationInfo')),
|
||||
('permissions', models.ManyToManyField(blank=True, to='auth.Permission')),
|
||||
],
|
||||
options={
|
||||
'ordering': ['priority'],
|
||||
'ordering': ['-priority'],
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
@ -204,7 +215,7 @@ class Migration(migrations.Migration):
|
||||
models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL,
|
||||
to='eveonline.EveCharacter')),
|
||||
('state', models.ForeignKey(on_delete=models.SET(authentication.models.get_guest_state),
|
||||
to='authentication.State')),
|
||||
to='authentication.State', default=authentication.models.get_guest_state_pk)),
|
||||
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='profile',
|
||||
to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
@ -224,4 +235,5 @@ class Migration(migrations.Migration):
|
||||
migrations.DeleteModel(
|
||||
name='AuthServicesInfo',
|
||||
),
|
||||
migrations.RunPython(disable_passwords, migrations.RunPython.noop),
|
||||
]
|
||||
|
@ -4,6 +4,9 @@ from django.db import models
|
||||
from django.contrib.auth.models import User, Permission
|
||||
from authentication.managers import CharacterOwnershipManager, StateManager
|
||||
from eveonline.models import EveCharacter, EveCorporationInfo, EveAllianceInfo
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@python_2_unicode_compatible
|
||||
@ -12,22 +15,35 @@ class State(models.Model):
|
||||
permissions = models.ManyToManyField(Permission, blank=True)
|
||||
priority = models.IntegerField(unique=True)
|
||||
|
||||
member_characters = models.ManyToManyField(EveCharacter)
|
||||
member_corporations = models.ManyToManyField(EveCorporationInfo)
|
||||
member_alliances = models.ManyToManyField(EveAllianceInfo)
|
||||
member_characters = models.ManyToManyField(EveCharacter, blank=True)
|
||||
member_corporations = models.ManyToManyField(EveCorporationInfo, blank=True)
|
||||
member_alliances = models.ManyToManyField(EveAllianceInfo, blank=True)
|
||||
public = models.BooleanField(default=False)
|
||||
|
||||
objects = StateManager()
|
||||
|
||||
class Meta:
|
||||
ordering = ['priority']
|
||||
ordering = ['-priority']
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
def available_to_character(self, character):
|
||||
return self in State.objects.available_to_character(character)
|
||||
|
||||
def available_to_user(self, user):
|
||||
return self in State.objects.available_to_user(user)
|
||||
|
||||
|
||||
def get_guest_state():
|
||||
return State.objects.update_or_create(name='Guest', defaults={'priority': 0, 'public': True})[0]
|
||||
try:
|
||||
return State.objects.get(name='Guest')
|
||||
except State.DoesNotExist:
|
||||
return State.objects.create(name='Guest', priority=0, public=True)
|
||||
|
||||
|
||||
def get_guest_state_pk():
|
||||
return get_guest_state().pk
|
||||
|
||||
|
||||
@python_2_unicode_compatible
|
||||
@ -37,15 +53,18 @@ class UserProfile(models.Model):
|
||||
|
||||
user = models.OneToOneField(User, related_name='profile', on_delete=models.CASCADE)
|
||||
main_character = models.OneToOneField(EveCharacter, blank=True, null=True, on_delete=models.SET_NULL)
|
||||
state = models.ForeignKey(State, on_delete=models.SET(get_guest_state))
|
||||
state = models.ForeignKey(State, on_delete=models.SET(get_guest_state), default=get_guest_state_pk)
|
||||
|
||||
def assign_state(self, commit=True):
|
||||
self.state = State.objects.get_for_user(self.user)
|
||||
if commit:
|
||||
self.save(update_fields=['state'])
|
||||
state = State.objects.get_for_user(self.user)
|
||||
if self.state != state:
|
||||
self.state = state
|
||||
if commit:
|
||||
logger.info('Updating {} state to {}'.format(self.user, self.state))
|
||||
self.save(update_fields=['state'])
|
||||
|
||||
def __str__(self):
|
||||
return "%s Profile" % self.user
|
||||
return str(self.user)
|
||||
|
||||
|
||||
@python_2_unicode_compatible
|
||||
|
@ -1,8 +1,9 @@
|
||||
from __future__ import unicode_literals
|
||||
from django.db.models.signals import post_save, pre_delete
|
||||
from django.db.models.signals import post_save, pre_delete, m2m_changed
|
||||
from django.db.models import Q
|
||||
from django.dispatch import receiver
|
||||
from django.contrib.auth.models import User
|
||||
from authentication.models import CharacterOwnership, UserProfile, get_guest_state
|
||||
from authentication.models import CharacterOwnership, UserProfile, get_guest_state, State
|
||||
from services.tasks import validate_services
|
||||
from esi.models import Token
|
||||
from eveonline.managers import EveManager
|
||||
@ -12,12 +13,48 @@ import logging
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def trigger_state_check(state):
|
||||
# evaluate all current members to ensure they still have access
|
||||
for profile in state.userprofile_set.all():
|
||||
profile.assign_state()
|
||||
|
||||
# we may now be available to others with lower states
|
||||
check_states = State.objects.filter(priority__lt=state.priority)
|
||||
for profile in UserProfile.objects.filter(state__in=check_states):
|
||||
if state.available_to_user(profile.user):
|
||||
profile.state = state
|
||||
profile.save(update_fields=['state'])
|
||||
|
||||
|
||||
@receiver(m2m_changed, sender=State.member_characters.through)
|
||||
def state_member_characters_changed(sender, instance, action, *args, **kwargs):
|
||||
if action.startswith('post_'):
|
||||
trigger_state_check(instance)
|
||||
|
||||
|
||||
@receiver(m2m_changed, sender=State.member_corporations.through)
|
||||
def state_member_corporations_changed(sender, instance, action, *args, **kwargs):
|
||||
if action.startswith('post_'):
|
||||
trigger_state_check(instance)
|
||||
|
||||
|
||||
@receiver(m2m_changed, sender=State.member_alliances.through)
|
||||
def state_member_alliances_changed(sender, instance, action, *args, **kwargs):
|
||||
if action.startswith('post_'):
|
||||
trigger_state_check(instance)
|
||||
|
||||
|
||||
@receiver(post_save, sender=State)
|
||||
def state_saved(sender, instance, *args, **kwargs):
|
||||
trigger_state_check(instance)
|
||||
|
||||
|
||||
# Is there a smarter way to intercept pre_save with a diff main_character or state?
|
||||
@receiver(post_save, sender=UserProfile)
|
||||
def reassess_on_profile_save(sender, instance, created, *args, **kwargs):
|
||||
# catches post_save from profiles to trigger necessary service and state checks
|
||||
if not created:
|
||||
update_fields = kwargs.pop('update_fields', [])
|
||||
update_fields = kwargs.pop('update_fields', []) or []
|
||||
if 'state' not in update_fields:
|
||||
instance.assign_state()
|
||||
# TODO: how do we prevent running this twice on profile state change?
|
||||
@ -35,14 +72,17 @@ def create_required_models(sender, instance, created, *args, **kwargs):
|
||||
def record_character_ownership(sender, instance, created, *args, **kwargs):
|
||||
if created:
|
||||
# purge ownership records if the hash or auth user account has changed
|
||||
CharacterOwnership.objects.filter(character__character_id=instance.character_id).exclude(
|
||||
owner_hash=instance.owner_hash).exclude(user=instance.user).delete()
|
||||
CharacterOwnership.objects.filter(character__character_id=instance.character_id).exclude(Q(
|
||||
owner_hash=instance.character_owner_hash) & Q(user=instance.user)).delete()
|
||||
# create character if needed
|
||||
if EveCharacter.objects.filter(character_id=instance.character_id).exists() is False:
|
||||
EveManager.create_character(instance.character_id)
|
||||
char = EveCharacter.objects.get(character_id=instance.character_id)
|
||||
CharacterOwnership.objects.update_or_create(character=char,
|
||||
defaults={'owner_hash': instance.owner_hash, 'user': instance.user})
|
||||
# check if we need to create ownership
|
||||
if instance.user and not CharacterOwnership.objects.filter(character__character_id=instance.character_id).exists():
|
||||
CharacterOwnership.objects.update_or_create(character=char,
|
||||
defaults={'owner_hash': instance.character_owner_hash,
|
||||
'user': instance.user})
|
||||
|
||||
|
||||
@receiver(pre_delete, sender=CharacterOwnership)
|
||||
|
@ -49,23 +49,23 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-6 text-center">
|
||||
<div class="panel panel-success">
|
||||
<div class="panel-heading">{% trans "Groups" %}</div>
|
||||
<div class="panel-body">
|
||||
<div style="height: 236px;overflow:-moz-scrollbars-vertical;overflow-y:auto;">
|
||||
<table class="table table-striped">
|
||||
{% for group in user.groups.all %}
|
||||
<tr>
|
||||
<td>{{ group.name }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
<div class="col-lg-6 text-center">
|
||||
<div class="panel panel-success">
|
||||
<div class="panel-heading">{% trans "Groups" %}</div>
|
||||
<div class="panel-body">
|
||||
<div style="height: 236px;overflow:-moz-scrollbars-vertical;overflow-y:auto;">
|
||||
<table class="table table-striped">
|
||||
{% for group in user.groups.all %}
|
||||
<tr>
|
||||
<td>{{ group.name }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
</div>
|
||||
<div class="clearfix"></div>
|
||||
<div class="panel panel-default">
|
||||
@ -81,6 +81,7 @@
|
||||
{% for ownership in request.user.character_ownerships.all %}
|
||||
{% with ownership.character as char %}
|
||||
<tr>
|
||||
<td class="text-center"><img class="ra-avatar img-circle" src="https://image.eveonline.com/Character/{{ char.character_id }}_32.jpg"></td>
|
||||
<td class="text-center">{{ char.character_name }}</td>
|
||||
<td class="text-center">{{ char.corporation_name }}</td>
|
||||
<td class="text-center">{{ char.alliance_name }}</td>
|
||||
|
@ -1,3 +1,4 @@
|
||||
{% load static %}
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
|
@ -1,27 +1,10 @@
|
||||
{% extends 'public/base.html' %}
|
||||
{% extends 'public/middle_box.html' %}
|
||||
{% load static %}
|
||||
{% block title %}Login{% endblock %}
|
||||
{% block content %}
|
||||
<div class="col-md-4 col-md-offset-4">
|
||||
{% if messages %}
|
||||
{% for message in messages %}
|
||||
<div class="alert alert-{{ message.level_tag}}">{{ message }}</div>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
<div class="panel panel-default panel-transparent">
|
||||
<div class="panel-body">
|
||||
<div class="col-md-12">
|
||||
<p style="text-align:center">
|
||||
<a href="{% url 'auth_sso_login' %}">
|
||||
<img src="{% static 'img/sso/EVE_SSO_Login_Buttons_Large_Black.png' %}" border=0>
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% include 'public/lang_select.html' %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% block extra_include %}
|
||||
{% include 'bundles/bootstrap-js.html' %}
|
||||
{% endblock %}
|
||||
|
||||
{% block middle_box_content %}
|
||||
<p style="text-align:center">
|
||||
<a href="{% url 'auth_sso_login' %}">
|
||||
<img src="{% static 'img/sso/EVE_SSO_Login_Buttons_Large_Black.png' %}" border=0>
|
||||
</a>
|
||||
</p>
|
||||
{% endblock %}
|
24
authentication/templates/public/middle_box.html
Normal file
24
authentication/templates/public/middle_box.html
Normal file
@ -0,0 +1,24 @@
|
||||
{% extends 'public/base.html' %}
|
||||
{% load static %}
|
||||
{% block title %}Login{% endblock %}
|
||||
{% block content %}
|
||||
<div class="col-md-4 col-md-offset-4">
|
||||
{% if messages %}
|
||||
{% for message in messages %}
|
||||
<div class="alert alert-{{ message.level_tag}}">{{ message }}</div>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
<div class="panel panel-default panel-transparent">
|
||||
<div class="panel-body">
|
||||
<div class="col-md-12">
|
||||
{% block middle_box_content %}
|
||||
{% endblock %}
|
||||
</div>
|
||||
</div>
|
||||
{% include 'public/lang_select.html' %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% block extra_include %}
|
||||
{% include 'bundles/bootstrap-js.html' %}
|
||||
{% endblock %}
|
@ -67,9 +67,9 @@
|
||||
{% if user.is_staff %}
|
||||
<li><a href="{% url 'admin:index' %}">{% trans "Admin" %}</a></li>
|
||||
{% endif %}
|
||||
<li><a href="{% url 'auth_logout_user' %}">{% trans "Logout" %}</a></li>
|
||||
<li><a href="{% url 'auth_logout' %}">{% trans "Logout" %}</a></li>
|
||||
{% else %}
|
||||
<li><a href="{% url 'auth_login_user' %}">{% trans "Login" %}</a></li>
|
||||
<li><a href="{% url 'authentication:login' %}">{% trans "Login" %}</a></li>
|
||||
{% endif %}
|
||||
|
||||
</ul>
|
||||
@ -85,7 +85,7 @@
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a class="{% navactive request 'auth_dashboard' %}" href="{% url 'auth_dashboard' %}">
|
||||
<a class="{% navactive request 'authentication:dashboard' %}" href="{% url 'authentication:dashboard' %}">
|
||||
<i class="fa fa-dashboard fa-fw grayiconecolor"></i>{% trans " Dashboard" %}
|
||||
</a>
|
||||
</li>
|
||||
@ -95,7 +95,7 @@
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a class="{% navactive request 'auth_help' %}" href="{% url 'auth_help' %}">
|
||||
<a class="{% navactive request 'authentication:help' %}" href="{% url 'authentication:help' %}">
|
||||
<i class="fa fa-question fa-fw grayiconecolor"></i>{% trans " Help" %}
|
||||
</a>
|
||||
</li>
|
||||
@ -170,9 +170,6 @@
|
||||
</a>
|
||||
</li>
|
||||
{% menu_aux %}
|
||||
<li class="text-center divider-horizontal">
|
||||
<h5>{% trans "Util" %}</h5>
|
||||
</li>
|
||||
|
||||
{% if perms.auth.jabber_broadcast or perms.auth.jabber_broadcast_all or user.is_superuser %}
|
||||
<li>
|
||||
|
5
authentication/templates/registration/activate.html
Normal file
5
authentication/templates/registration/activate.html
Normal file
@ -0,0 +1,5 @@
|
||||
{% extends 'public/middle_box.html' %}
|
||||
{% load i18n %}
|
||||
{% block middle_box_content %}
|
||||
<div class="alert alert-danger">{% trans 'Invalid or expired activation link.' %}</div>
|
||||
{% endblock %}
|
@ -0,0 +1,9 @@
|
||||
You're receiving this email because someone has entered this email address while registering for an account on {{ site.domain }}
|
||||
|
||||
If this was you, please go to the following URL to confirm your email address:
|
||||
|
||||
{{ url }}
|
||||
|
||||
This link will expire in {{ expiration_days }} day{{ plural }}.
|
||||
|
||||
If this was not you, it is safe to ignore this email.
|
@ -0,0 +1 @@
|
||||
Confirm your Alliance Auth account email address
|
@ -1,24 +0,0 @@
|
||||
{% extends "registered/base.html" %}
|
||||
{% load bootstrap %}
|
||||
{% load i18n static %}
|
||||
|
||||
|
||||
{% block title %}{% trans 'Password Change' %}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="col-lg-12">
|
||||
<h1 class="page-header text-center">{% trans "Change Password" %}</h1>
|
||||
|
||||
<div class="container-fluid">
|
||||
<div class="col-md-4 col-md-offset-4">
|
||||
<div class="row">
|
||||
<p class="text-center">
|
||||
{% trans "Completed" %}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
{% endblock %}
|
@ -1,26 +0,0 @@
|
||||
{% extends "registered/base.html" %}
|
||||
{% load bootstrap %}
|
||||
{% load i18n static %}
|
||||
|
||||
{% block title %}{% trans "Password Change" %}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="col-lg-12">
|
||||
<h1 class="page-header text-center">{% trans "Change Password" %}</h1>
|
||||
|
||||
<div class="container-fluid">
|
||||
<div class="col-md-4 col-md-offset-4">
|
||||
<div class="row">
|
||||
<form class="form-signin" role="form" action="" method="POST">
|
||||
{% csrf_token %}
|
||||
{{ form|bootstrap }}
|
||||
<br/>
|
||||
<button class="btn btn-lg btn-primary btn-block" type="submit">{% trans "Change Password" %}</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
{% endblock %}
|
@ -1,44 +0,0 @@
|
||||
{% load staticfiles %}
|
||||
{% load i18n %}
|
||||
{% load bootstrap %}
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="description" content="">
|
||||
<meta name="author" content="">
|
||||
|
||||
<title>{{ SITE_NAME }} - {% block page_title %}{% endblock page_title %}</title>
|
||||
|
||||
{% include 'bundles/bootstrap-css.html' %}
|
||||
{% include 'bundles/fontawesome.html' %}
|
||||
|
||||
<style>
|
||||
body {
|
||||
background: url('{% static 'img/index_images/index_blank_bg.jpg' %}') no-repeat scroll;
|
||||
-webkit-background-size: cover;
|
||||
-moz-background-size: cover;
|
||||
-o-background-size: cover;
|
||||
background-size: cover;
|
||||
}
|
||||
|
||||
.panel-transparent {
|
||||
background: rgba(48, 48, 48, 0.7);
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.panel-body {
|
||||
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
{% block content %}
|
||||
{% endblock content %}
|
||||
{% include 'bundles/bootstrap-js.html' %}
|
||||
</body>
|
||||
</html>
|
@ -1,22 +0,0 @@
|
||||
{% extends 'registration/password_reset_base.html' %}
|
||||
{% load staticfiles %}
|
||||
{% load i18n %}
|
||||
{% load bootstrap %}
|
||||
|
||||
{% block page_title %}Login{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container" style="margin-top:150px">
|
||||
<div class="col-md-4 col-md-offset-4">
|
||||
<div class="panel panel-default panel-transparent">
|
||||
<div class="panel-body">
|
||||
<h1 class="text-center">{% trans 'Password reset complete' %}</h1>
|
||||
|
||||
<p class="text-center">{% trans "Your password has been set." %}</p>
|
||||
|
||||
<a href="{{ login_url }}" class="btn btn-lg btn-success btn-block">{% trans "Login" %}</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock content %}
|
@ -1,32 +0,0 @@
|
||||
{% extends 'registration/password_reset_base.html' %}
|
||||
{% load staticfiles %}
|
||||
{% load i18n %}
|
||||
{% load bootstrap %}
|
||||
|
||||
{% block page_title %}Login{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container" style="margin-top:150px">
|
||||
<div class="col-md-4 col-md-offset-4">
|
||||
<div class="panel panel-default panel-transparent">
|
||||
<div class="panel-body">
|
||||
{% if validlink %}
|
||||
<form class="form-signin" role="form" action="" method="POST">
|
||||
{% csrf_token %}
|
||||
{{ form |bootstrap }}
|
||||
<div class="">
|
||||
<button class="btn btn-lg btn-primary btn-block" type="submit">{% trans "Change Password" %}</button>
|
||||
</div>
|
||||
</form>
|
||||
{% else %}
|
||||
|
||||
<h1>{% trans 'Password reset unsuccessful' %}</h1>
|
||||
|
||||
<p>{% trans "The password reset link was invalid, possibly because it has already been used. Please request a new password reset." %}</p>
|
||||
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
@ -1,23 +0,0 @@
|
||||
{% extends 'registration/password_reset_base.html' %}
|
||||
{% load staticfiles %}
|
||||
{% load i18n %}
|
||||
{% load bootstrap %}
|
||||
|
||||
{% block page_title %}Login{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container" style="margin-top:150px">
|
||||
<div class="col-md-4 col-md-offset-4">
|
||||
<div class="panel panel-default panel-transparent">
|
||||
<div class="panel-body">
|
||||
<h1 class="text-center">{% trans 'Password Reset Success' %}</h1>
|
||||
|
||||
<p>{% trans "We've emailed you instructions for setting your password. You should be receiving them shortly." %}</p>
|
||||
|
||||
<p>{% trans "If you don't receive an email, please make sure you've entered the address you registered with, and check your spam folder." %}</p>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock content %}
|
@ -1,27 +0,0 @@
|
||||
{% extends 'registration/password_reset_base.html' %}
|
||||
{% load staticfiles %}
|
||||
{% load i18n %}
|
||||
{% load bootstrap %}
|
||||
|
||||
{% block page_title %}Login{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container" style="margin-top:150px">
|
||||
<div class="col-md-4 col-md-offset-4">
|
||||
<div class="panel panel-default panel-transparent">
|
||||
<div class="panel-body">
|
||||
<form class="form-signin" role="form" action="" method="POST">
|
||||
{% csrf_token %}
|
||||
<h1 class="text-center">{% trans "Password Reset" %}</h1>
|
||||
|
||||
<p class="text-center">{% trans "Forgotten your password? Enter your email below." %}</p>
|
||||
{{ form|bootstrap }}
|
||||
<div class="">
|
||||
<button class="btn btn-lg btn-primary btn-block" type="submit">{% trans "Reset Password" %}</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock content %}
|
14
authentication/templates/registration/registration_form.html
Normal file
14
authentication/templates/registration/registration_form.html
Normal file
@ -0,0 +1,14 @@
|
||||
{% extends 'public/middle_box.html' %}
|
||||
{% load bootstrap %}
|
||||
{% load i18n %}
|
||||
{% load static %}
|
||||
{% block title %}Register{% endblock %}
|
||||
{% block middle_box_content %}
|
||||
<form class="form-signin" role="form" action="" method="POST">
|
||||
{% csrf_token %}
|
||||
{{ form|bootstrap }}
|
||||
<br/>
|
||||
<button class="btn btn-lg btn-primary btn-block" type="submit">{% trans "Submit" %}</button>
|
||||
<br/>
|
||||
</form>
|
||||
{% endblock %}
|
@ -1,20 +1,15 @@
|
||||
from django.conf.urls import url, include
|
||||
from django.conf.urls import url
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.views.generic.base import TemplateView
|
||||
from authentication import views
|
||||
from registration.backends.hmac import urls
|
||||
|
||||
# inject our custom view classes into the HMAC scheme but use their urlpatterns because :efficiency:
|
||||
urls.views = views
|
||||
|
||||
app_name = 'authentication'
|
||||
|
||||
urlpatterns = [
|
||||
url(r'^$', TemplateView.as_view(template_name='public/login.html'), name='login'),
|
||||
url(r'^account/login/$', TemplateView.as_view(template_name='public/login.html')),
|
||||
url(r'^$', login_required(TemplateView.as_view(template_name='authentication/dashboard.html')),),
|
||||
url(r'^account/login/$', TemplateView.as_view(template_name='public/login.html'), name='login'),
|
||||
url(r'^account/characters/main/$', views.main_character_change, name='change_main_character'),
|
||||
url(r'^account/characters/add/$', views.add_character, name='add_character'),
|
||||
url(r'^account/', include(urls, namespace='registration')),
|
||||
url(r'^help/$', login_required(TemplateView.as_view(template_name='public/help.html')), name='help'),
|
||||
url(r'^dashboard/$',
|
||||
login_required(TemplateView.as_view(template_name='authentication/dashboard.html')), name='dashboard'),
|
||||
|
@ -9,6 +9,7 @@ from django.contrib import messages
|
||||
from django.contrib.auth.models import User
|
||||
from django.conf import settings
|
||||
from django.core import signing
|
||||
from django.core.urlresolvers import reverse
|
||||
from esi.decorators import token_required
|
||||
from registration.backends.hmac.views import RegistrationView as BaseRegistrationView, \
|
||||
ActivationView as BaseActivationView, REGISTRATION_SALT
|
||||
@ -23,13 +24,19 @@ logger = logging.getLogger(__name__)
|
||||
def main_character_change(request, token):
|
||||
logger.debug("main_character_change called by user %s for character %s" % (request.user, token.character_name))
|
||||
try:
|
||||
co = CharacterOwnership.objects.get(character__character_id=token.character_id)
|
||||
co = CharacterOwnership.objects.get(character__character_id=token.character_id, user=request.user)
|
||||
except CharacterOwnership.DoesNotExist:
|
||||
co = CharacterOwnership.objects.create_by_token(token)
|
||||
request.user.profile.main_character = co.character
|
||||
request.user.profile.save(update_fields=['main_character'])
|
||||
messages.success(request, _('Changed main character to %(char)s') % {"char": co.character})
|
||||
return redirect("auth_dashboard")
|
||||
if not CharacterOwnership.objects.filter(character__character_id=token.character_id).exists():
|
||||
co = CharacterOwnership.objects.create_by_token(token)
|
||||
else:
|
||||
messages.error(request, 'Cannot change main character to %(char)s: character owned by a different account.' % ({'char': token.character_name}))
|
||||
co = None
|
||||
if co:
|
||||
request.user.profile.main_character = co.character
|
||||
request.user.profile.save(update_fields=['main_character'])
|
||||
messages.success(request, _('Changed main character to %(char)s') % {"char": co.character})
|
||||
logger.info('Changed user %(user)s main character to %(char)s' % ({'user': request.user, 'char': co.character}))
|
||||
return redirect("authentication:dashboard")
|
||||
|
||||
|
||||
@token_required(new=True, scopes=settings.LOGIN_TOKEN_SCOPES)
|
||||
@ -38,7 +45,7 @@ def add_character(request, token):
|
||||
owner_hash=token.character_owner_hash).filter(user=request.user).exists():
|
||||
messages.success(request, _('Added %(name)s to your account.'% ({'name': token.character_name})))
|
||||
else:
|
||||
messages.error(request, _('Failed to add %(name)s to your account.' % ({'name': token.charater_name})))
|
||||
messages.error(request, _('Failed to add %(name)s to your account: they already have an account.' % ({'name': token.character_name})))
|
||||
return redirect('authentication:dashboard')
|
||||
|
||||
|
||||
@ -65,12 +72,12 @@ def sso_login(request, token):
|
||||
user = authenticate(token=token)
|
||||
if user and user.is_active:
|
||||
login(request, user)
|
||||
return redirect(request.POST.get('next', request.GET.get('next', 'auth_dashboard')))
|
||||
return redirect(request.POST.get('next', request.GET.get('next', 'authentication:dashboard')))
|
||||
elif user and not user.email:
|
||||
# Store the new user PK in the session to enable us to identify the registering user in Step 2
|
||||
request.session['registration_uid'] = user.pk
|
||||
# Go to Step 2
|
||||
return redirect('authentication:register')
|
||||
return redirect('registration_register')
|
||||
else:
|
||||
messages.error(request, _('Unable to authenticate as the selected character.'))
|
||||
return redirect(settings.LOGIN_URL)
|
||||
@ -100,6 +107,13 @@ class RegistrationView(BaseRegistrationView):
|
||||
def get_activation_key(self, user):
|
||||
return signing.dumps(obj=[getattr(user, User.USERNAME_FIELD), user.email], salt=REGISTRATION_SALT)
|
||||
|
||||
def get_email_context(self, activation_key):
|
||||
context = super(RegistrationView, self).get_email_context(activation_key)
|
||||
context['url'] = context['site'].domain + reverse('registration_activate', args=[activation_key])
|
||||
context['plural'] = 's' if context['expiration_days'] > 1 else '',
|
||||
print(context)
|
||||
return context
|
||||
|
||||
|
||||
# Step 3
|
||||
class ActivationView(BaseActivationView):
|
||||
@ -121,3 +135,18 @@ class ActivationView(BaseActivationView):
|
||||
user.save()
|
||||
return user
|
||||
return False
|
||||
|
||||
|
||||
def registration_complete(request):
|
||||
messages.success(request, _('Sent confirmation email. Please follow the link to confirm your email address.'))
|
||||
return redirect('authentication:login')
|
||||
|
||||
|
||||
def activation_complete(request):
|
||||
messages.success(request, _('Confirmed your email address. Please login to continue.'))
|
||||
return redirect('authentication:dashboard')
|
||||
|
||||
|
||||
def registration_closed(request):
|
||||
messages.error(request, _('Registraion of new accounts it not allowed at this time.'))
|
||||
return redirect('authentication:login')
|
||||
|
@ -145,7 +145,7 @@ class CorpStats(models.Model):
|
||||
class ViewModel(object):
|
||||
def __init__(self, corpstats, user):
|
||||
self.corp = corpstats.corp
|
||||
self.members = corpstats.get_member_objects(user)
|
||||
self.members = corpstats.get_member_objects()
|
||||
self.can_update = corpstats.can_update(user)
|
||||
self.total_members = len(self.members)
|
||||
self.total_users = corpstats.user_count(self.members)
|
||||
|
@ -90,7 +90,7 @@ def corpstats_view(request, corp_id=None):
|
||||
members = []
|
||||
if corpstats:
|
||||
page = request.GET.get('page', 1)
|
||||
members = get_page(corpstats.get_member_objects(request.user), page)
|
||||
members = get_page(corpstats.get_member_objects(), page)
|
||||
|
||||
if corpstats:
|
||||
context.update({
|
||||
|
@ -7,20 +7,14 @@ def auth_settings(request):
|
||||
return {
|
||||
'DOMAIN': settings.DOMAIN,
|
||||
'MUMBLE_URL': settings.MUMBLE_URL,
|
||||
'FORUM_URL': settings.FORUM_URL,
|
||||
'FORUM_URL': settings.PHPBB3_URL,
|
||||
'TEAMSPEAK3_PUBLIC_URL': settings.TEAMSPEAK3_PUBLIC_URL,
|
||||
'DISCORD_SERVER_ID': settings.DISCORD_GUILD_ID,
|
||||
'KILLBOARD_URL': settings.KILLBOARD_URL,
|
||||
'DISCOURSE_URL': settings.DISCOURSE_URL,
|
||||
'IPS4_URL': settings.IPS4_URL,
|
||||
'SMF_URL': settings.SMF_URL,
|
||||
'MARKET_URL': settings.MARKET_URL,
|
||||
'EXTERNAL_MEDIA_URL': settings.EXTERNAL_MEDIA_URL,
|
||||
'CURRENT_UTC_TIME': timezone.now(),
|
||||
'BLUE_API_MASK': settings.BLUE_API_MASK,
|
||||
'BLUE_API_ACCOUNT': settings.BLUE_API_ACCOUNT,
|
||||
'MEMBER_API_MASK': settings.MEMBER_API_MASK,
|
||||
'MEMBER_API_ACCOUNT': settings.MEMBER_API_ACCOUNT,
|
||||
'JABBER_URL': settings.JABBER_URL,
|
||||
'SITE_NAME': settings.SITE_NAME,
|
||||
}
|
||||
|
@ -41,7 +41,7 @@ def only_one(function=None, key="", timeout=None):
|
||||
|
||||
@app.task(bind=True)
|
||||
def validate_services(self, user):
|
||||
logger.debug('Ensuring user %s has permissions for active services'.format(user))
|
||||
logger.debug('Ensuring user {} has permissions for active services'.format(user))
|
||||
# Iterate through services hooks and have them check the validity of the user
|
||||
for svc in ServicesHook.get_services():
|
||||
try:
|
||||
|
@ -1,12 +1,9 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.contrib import messages
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.shortcuts import render
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from alliance_auth.hooks import get_hooks
|
||||
from eveonline.models import EveCharacter
|
||||
from services.forms import FleetFormatterForm
|
||||
|
||||
import logging
|
||||
@ -47,7 +44,7 @@ def fleet_formatter_view(request):
|
||||
@login_required
|
||||
def services_view(request):
|
||||
logger.debug("services_view called by user %s" % request.user)
|
||||
char = request.profile.main_character
|
||||
char = request.user.profile.main_character
|
||||
context = {'service_ctrls': []}
|
||||
for fn in get_hooks('services_hook'):
|
||||
# Render hooked services controls
|
||||
|
Loading…
x
Reference in New Issue
Block a user