mirror of
https://gitlab.com/allianceauth/allianceauth.git
synced 2025-07-14 06:50:15 +02:00
Capture signals sent by admin proxy models.
This will prevent those weird missing UserProfile and AuthGroup errors. Add logging to authentication signals. Correct reverse migration authservicesinfo creation. Rename proxy models so they look better on the admin site.
This commit is contained in:
parent
5060d3f408
commit
3ed0f873f3
@ -1,6 +1,6 @@
|
|||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
|
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
|
||||||
from django.contrib.auth.models import User, Permission
|
from django.contrib.auth.models import User as BaseUser, Permission as BasePermission
|
||||||
from django.utils.text import slugify
|
from django.utils.text import slugify
|
||||||
from allianceauth.services.hooks import ServicesHook
|
from allianceauth.services.hooks import ServicesHook
|
||||||
|
|
||||||
@ -120,7 +120,7 @@ class CharacterOwnershipAdmin(admin.ModelAdmin):
|
|||||||
|
|
||||||
class PermissionAdmin(admin.ModelAdmin):
|
class PermissionAdmin(admin.ModelAdmin):
|
||||||
actions = None
|
actions = None
|
||||||
readonly_fields = [field.name for field in Permission._meta.fields]
|
readonly_fields = [field.name for field in BasePermission._meta.fields]
|
||||||
list_display = ('admin_name', 'name', 'codename', 'content_type')
|
list_display = ('admin_name', 'name', 'codename', 'content_type')
|
||||||
list_filter = ('content_type__app_label',)
|
list_filter = ('content_type__app_label',)
|
||||||
|
|
||||||
@ -136,21 +136,22 @@ class PermissionAdmin(admin.ModelAdmin):
|
|||||||
|
|
||||||
|
|
||||||
# Hack to allow registration of django.contrib.auth models in our authentication app
|
# Hack to allow registration of django.contrib.auth models in our authentication app
|
||||||
class ProxyUser(User):
|
class User(BaseUser):
|
||||||
class Meta:
|
class Meta:
|
||||||
proxy = True
|
proxy = True
|
||||||
verbose_name = User._meta.verbose_name
|
verbose_name = BaseUser._meta.verbose_name
|
||||||
verbose_name_plural = User._meta.verbose_name_plural
|
verbose_name_plural = BaseUser._meta.verbose_name_plural
|
||||||
|
|
||||||
|
|
||||||
class ProxyPermission(Permission):
|
class Permission(BasePermission):
|
||||||
class Meta:
|
class Meta:
|
||||||
proxy = True
|
proxy = True
|
||||||
verbose_name = Permission._meta.verbose_name
|
verbose_name = BasePermission._meta.verbose_name
|
||||||
verbose_name_plural = Permission._meta.verbose_name_plural
|
verbose_name_plural = BasePermission._meta.verbose_name_plural
|
||||||
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
admin.site.unregister(User)
|
admin.site.unregister(BaseUser)
|
||||||
finally:
|
finally:
|
||||||
admin.site.register(ProxyUser, UserAdmin)
|
admin.site.register(User, UserAdmin)
|
||||||
admin.site.register(ProxyPermission, PermissionAdmin)
|
admin.site.register(Permission, PermissionAdmin)
|
@ -145,7 +145,7 @@ def recreate_authservicesinfo(apps, schema_editor):
|
|||||||
User = apps.get_model('auth', 'User')
|
User = apps.get_model('auth', 'User')
|
||||||
|
|
||||||
# recreate all missing AuthServicesInfo models
|
# recreate all missing AuthServicesInfo models
|
||||||
AuthServicesInfo.objects.bulk_create([AuthServicesInfo(user=u.pk) for u in User.objects.all()])
|
AuthServicesInfo.objects.bulk_create([AuthServicesInfo(user_id=u.pk) for u in User.objects.all()])
|
||||||
|
|
||||||
# repopulate main characters
|
# repopulate main characters
|
||||||
for profile in UserProfile.objects.exclude(main_character__isnull=True).select_related('user', 'main_character'):
|
for profile in UserProfile.objects.exclude(main_character__isnull=True).select_related('user', 'main_character'):
|
||||||
@ -233,7 +233,7 @@ class Migration(migrations.Migration):
|
|||||||
),
|
),
|
||||||
migrations.RunPython(disable_passwords, migrations.RunPython.noop),
|
migrations.RunPython(disable_passwords, migrations.RunPython.noop),
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='ProxyPermission',
|
name='Permission',
|
||||||
fields=[
|
fields=[
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
@ -247,7 +247,7 @@ class Migration(migrations.Migration):
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='ProxyUser',
|
name='User',
|
||||||
fields=[
|
fields=[
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
|
@ -6,12 +6,12 @@ from django.db.models import Q
|
|||||||
from django.db.models.signals import post_save, pre_delete, m2m_changed, pre_save
|
from django.db.models.signals import post_save, pre_delete, m2m_changed, pre_save
|
||||||
from django.dispatch import receiver, Signal
|
from django.dispatch import receiver, Signal
|
||||||
from esi.models import Token
|
from esi.models import Token
|
||||||
|
from allianceauth.authentication.admin import User as AdminUser
|
||||||
|
|
||||||
from allianceauth.eveonline.models import EveCharacter
|
from allianceauth.eveonline.models import EveCharacter
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
state_changed = Signal(providing_args=['user', 'state'])
|
state_changed = Signal(providing_args=['user', 'state'])
|
||||||
|
|
||||||
|
|
||||||
@ -32,23 +32,27 @@ def trigger_state_check(state):
|
|||||||
@receiver(m2m_changed, sender=State.member_characters.through)
|
@receiver(m2m_changed, sender=State.member_characters.through)
|
||||||
def state_member_characters_changed(sender, instance, action, *args, **kwargs):
|
def state_member_characters_changed(sender, instance, action, *args, **kwargs):
|
||||||
if action.startswith('post_'):
|
if action.startswith('post_'):
|
||||||
|
logger.debug('State {} member characters changed. Re-evaluating membership.'.format(instance))
|
||||||
trigger_state_check(instance)
|
trigger_state_check(instance)
|
||||||
|
|
||||||
|
|
||||||
@receiver(m2m_changed, sender=State.member_corporations.through)
|
@receiver(m2m_changed, sender=State.member_corporations.through)
|
||||||
def state_member_corporations_changed(sender, instance, action, *args, **kwargs):
|
def state_member_corporations_changed(sender, instance, action, *args, **kwargs):
|
||||||
if action.startswith('post_'):
|
if action.startswith('post_'):
|
||||||
|
logger.debug('State {} member corporations changed. Re-evaluating membership.'.format(instance))
|
||||||
trigger_state_check(instance)
|
trigger_state_check(instance)
|
||||||
|
|
||||||
|
|
||||||
@receiver(m2m_changed, sender=State.member_alliances.through)
|
@receiver(m2m_changed, sender=State.member_alliances.through)
|
||||||
def state_member_alliances_changed(sender, instance, action, *args, **kwargs):
|
def state_member_alliances_changed(sender, instance, action, *args, **kwargs):
|
||||||
if action.startswith('post_'):
|
if action.startswith('post_'):
|
||||||
|
logger.debug('State {} member alliances changed. Re-evaluating membership.'.format(instance))
|
||||||
trigger_state_check(instance)
|
trigger_state_check(instance)
|
||||||
|
|
||||||
|
|
||||||
@receiver(post_save, sender=State)
|
@receiver(post_save, sender=State)
|
||||||
def state_saved(sender, instance, *args, **kwargs):
|
def state_saved(sender, instance, *args, **kwargs):
|
||||||
|
logger.debug('State {} saved. Re-evaluating membership.'.format(instance))
|
||||||
trigger_state_check(instance)
|
trigger_state_check(instance)
|
||||||
|
|
||||||
|
|
||||||
@ -59,19 +63,26 @@ def reassess_on_profile_save(sender, instance, created, *args, **kwargs):
|
|||||||
if not created:
|
if not created:
|
||||||
update_fields = kwargs.pop('update_fields', []) or []
|
update_fields = kwargs.pop('update_fields', []) or []
|
||||||
if 'state' not in update_fields:
|
if 'state' not in update_fields:
|
||||||
|
logger.debug('Profile for {} saved without state change. Re-evaluating state.'.format(instance.user))
|
||||||
instance.assign_state()
|
instance.assign_state()
|
||||||
|
|
||||||
|
|
||||||
@receiver(post_save, sender=User)
|
|
||||||
def create_required_models(sender, instance, created, *args, **kwargs):
|
def create_required_models(sender, instance, created, *args, **kwargs):
|
||||||
# ensure all users have a model
|
# ensure all users have a model
|
||||||
if created:
|
if created:
|
||||||
|
logger.debug('User {} created. Creating default UserProfile.'.format(instance))
|
||||||
UserProfile.objects.get_or_create(user=instance)
|
UserProfile.objects.get_or_create(user=instance)
|
||||||
|
|
||||||
|
|
||||||
|
post_save.connect(create_required_models, sender=User)
|
||||||
|
post_save.connect(create_required_models, sender=AdminUser)
|
||||||
|
|
||||||
|
|
||||||
@receiver(post_save, sender=Token)
|
@receiver(post_save, sender=Token)
|
||||||
def record_character_ownership(sender, instance, created, *args, **kwargs):
|
def record_character_ownership(sender, instance, created, *args, **kwargs):
|
||||||
if created:
|
if created:
|
||||||
|
logger.debug('New token for {0} character {1} saved. Evaluating ownership.'.format(instance.user,
|
||||||
|
instance.character_name))
|
||||||
if instance.user:
|
if instance.user:
|
||||||
query = Q(owner_hash=instance.character_owner_hash) & Q(user=instance.user)
|
query = Q(owner_hash=instance.character_owner_hash) & Q(user=instance.user)
|
||||||
else:
|
else:
|
||||||
@ -80,10 +91,15 @@ def record_character_ownership(sender, instance, created, *args, **kwargs):
|
|||||||
CharacterOwnership.objects.filter(character__character_id=instance.character_id).exclude(query).delete()
|
CharacterOwnership.objects.filter(character__character_id=instance.character_id).exclude(query).delete()
|
||||||
# create character if needed
|
# create character if needed
|
||||||
if EveCharacter.objects.filter(character_id=instance.character_id).exists() is False:
|
if EveCharacter.objects.filter(character_id=instance.character_id).exists() is False:
|
||||||
|
logger.debug('Token is for a new character. Creating model for {0} ({1})'.format(instance.character_name,
|
||||||
|
instance.character_id))
|
||||||
EveCharacter.objects.create_character(instance.character_id)
|
EveCharacter.objects.create_character(instance.character_id)
|
||||||
char = EveCharacter.objects.get(character_id=instance.character_id)
|
char = EveCharacter.objects.get(character_id=instance.character_id)
|
||||||
# check if we need to create ownership
|
# check if we need to create ownership
|
||||||
if instance.user and not CharacterOwnership.objects.filter(character__character_id=instance.character_id).exists():
|
if instance.user and not CharacterOwnership.objects.filter(
|
||||||
|
character__character_id=instance.character_id).exists():
|
||||||
|
logger.debug("Character {0} is not yet owned. Assigning ownership to {1}".format(instance.character_name,
|
||||||
|
instance.user))
|
||||||
CharacterOwnership.objects.update_or_create(character=char,
|
CharacterOwnership.objects.update_or_create(character=char,
|
||||||
defaults={'owner_hash': instance.character_owner_hash,
|
defaults={'owner_hash': instance.character_owner_hash,
|
||||||
'user': instance.user})
|
'user': instance.user})
|
||||||
@ -92,6 +108,8 @@ def record_character_ownership(sender, instance, created, *args, **kwargs):
|
|||||||
@receiver(pre_delete, sender=CharacterOwnership)
|
@receiver(pre_delete, sender=CharacterOwnership)
|
||||||
def validate_main_character(sender, instance, *args, **kwargs):
|
def validate_main_character(sender, instance, *args, **kwargs):
|
||||||
if instance.user.profile.main_character == instance.character:
|
if instance.user.profile.main_character == instance.character:
|
||||||
|
logger.debug("Ownership of a main character {0} has been revoked. Resetting {1} main character.".format(
|
||||||
|
instance.character, instance.user))
|
||||||
# clear main character as user no longer owns them
|
# clear main character as user no longer owns them
|
||||||
instance.user.profile.main_character = None
|
instance.user.profile.main_character = None
|
||||||
instance.user.profile.save()
|
instance.user.profile.save()
|
||||||
@ -100,30 +118,45 @@ def validate_main_character(sender, instance, *args, **kwargs):
|
|||||||
@receiver(pre_delete, sender=Token)
|
@receiver(pre_delete, sender=Token)
|
||||||
def validate_main_character_token(sender, instance, *args, **kwargs):
|
def validate_main_character_token(sender, instance, *args, **kwargs):
|
||||||
if UserProfile.objects.filter(main_character__character_id=instance.character_id).exists():
|
if UserProfile.objects.filter(main_character__character_id=instance.character_id).exists():
|
||||||
|
logger.debug(
|
||||||
|
"Token for a main character {0} is being deleted. Ensuring there are valid tokens to refresh.".format(
|
||||||
|
instance.character_name))
|
||||||
profile = UserProfile.objects.get(main_character__character_id=instance.character_id)
|
profile = UserProfile.objects.get(main_character__character_id=instance.character_id)
|
||||||
if not Token.objects.filter(character_id=instance.character_id).filter(user=profile.user).exclude(pk=instance.pk).exists():
|
if not Token.objects.filter(character_id=instance.character_id).filter(user=profile.user).exclude(
|
||||||
|
pk=instance.pk).require_valid().exists():
|
||||||
|
logger.debug(
|
||||||
|
"No remaining tokens to validate {0} ownership of main character {1}. Resetting main character.".format(
|
||||||
|
profile.user, profile.main_character))
|
||||||
# clear main character as we can no longer verify ownership
|
# clear main character as we can no longer verify ownership
|
||||||
profile.main_character = None
|
profile.main_character = None
|
||||||
profile.save()
|
profile.save()
|
||||||
|
|
||||||
|
|
||||||
@receiver(pre_save, sender=User)
|
|
||||||
def assign_state_on_active_change(sender, instance, *args, **kwargs):
|
def assign_state_on_active_change(sender, instance, *args, **kwargs):
|
||||||
# set to guest state if inactive, assign proper state if reactivated
|
# set to guest state if inactive, assign proper state if reactivated
|
||||||
if instance.pk:
|
if instance.pk:
|
||||||
old_instance = User.objects.get(pk=instance.pk)
|
old_instance = User.objects.get(pk=instance.pk)
|
||||||
if old_instance.is_active != instance.is_active:
|
if old_instance.is_active != instance.is_active:
|
||||||
if instance.is_active:
|
if instance.is_active:
|
||||||
|
logger.debug("User {0} has been activated. Assigning state.".format(instance))
|
||||||
instance.profile.assign_state()
|
instance.profile.assign_state()
|
||||||
else:
|
else:
|
||||||
|
logger.debug(
|
||||||
|
"User {0} has been deactivated. Revoking state and assigning to guest state.".format(instance))
|
||||||
instance.profile.state = get_guest_state()
|
instance.profile.state = get_guest_state()
|
||||||
instance.profile.save(update_fields=['state'])
|
instance.profile.save(update_fields=['state'])
|
||||||
|
|
||||||
|
|
||||||
|
pre_save.connect(assign_state_on_active_change, sender=User)
|
||||||
|
pre_save.connect(assign_state_on_active_change, sender=AdminUser)
|
||||||
|
|
||||||
|
|
||||||
@receiver(post_save, sender=EveCharacter)
|
@receiver(post_save, sender=EveCharacter)
|
||||||
def check_state_on_character_update(sender, instance, *args, **kwargs):
|
def check_state_on_character_update(sender, instance, *args, **kwargs):
|
||||||
# if this is a main character updating, check that user's state
|
# if this is a main character updating, check that user's state
|
||||||
try:
|
try:
|
||||||
|
logger.debug("Character {0} has been saved. Assessing owner's state for changes.".format(instance))
|
||||||
instance.userprofile.assign_state()
|
instance.userprofile.assign_state()
|
||||||
except UserProfile.DoesNotExist:
|
except UserProfile.DoesNotExist:
|
||||||
|
logger.debug("Character {0} is not a main character. No state assessment required.".format(instance))
|
||||||
pass
|
pass
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from django.contrib.auth.models import Group
|
from django.contrib.auth.models import Group as BaseGroup
|
||||||
|
from django.db.models.signals import post_save
|
||||||
|
|
||||||
from .models import AuthGroup
|
from .models import AuthGroup, save_auth_group, create_auth_group
|
||||||
from .models import GroupRequest
|
from .models import GroupRequest
|
||||||
|
|
||||||
|
|
||||||
@ -12,17 +13,21 @@ class AuthGroupAdmin(admin.ModelAdmin):
|
|||||||
filter_horizontal = ('group_leaders',)
|
filter_horizontal = ('group_leaders',)
|
||||||
|
|
||||||
|
|
||||||
class ProxyGroup(Group):
|
class Group(BaseGroup):
|
||||||
class Meta:
|
class Meta:
|
||||||
proxy = True
|
proxy = True
|
||||||
verbose_name = Group._meta.verbose_name
|
verbose_name = BaseGroup._meta.verbose_name
|
||||||
verbose_name_plural = Group._meta.verbose_name_plural
|
verbose_name_plural = BaseGroup._meta.verbose_name_plural
|
||||||
|
|
||||||
try:
|
try:
|
||||||
admin.site.unregister(Group)
|
admin.site.unregister(BaseGroup)
|
||||||
finally:
|
finally:
|
||||||
admin.site.register(ProxyGroup)
|
admin.site.register(Group)
|
||||||
|
|
||||||
|
|
||||||
admin.site.register(GroupRequest)
|
admin.site.register(GroupRequest)
|
||||||
admin.site.register(AuthGroup, AuthGroupAdmin)
|
admin.site.register(AuthGroup, AuthGroupAdmin)
|
||||||
|
|
||||||
|
|
||||||
|
post_save.connect(create_auth_group, sender=Group)
|
||||||
|
post_save.connect(save_auth_group, sender=Group)
|
||||||
|
@ -15,7 +15,7 @@ class Migration(migrations.Migration):
|
|||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='ProxyGroup',
|
name='Group',
|
||||||
fields=[
|
fields=[
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
|
@ -11,6 +11,7 @@ class Migration(migrations.Migration):
|
|||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
('services', '0001_squashed_0003_delete_groupcache'),
|
('services', '0001_squashed_0003_delete_groupcache'),
|
||||||
|
('authentication', '0015_user_profiles'),
|
||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
|
@ -8,6 +8,7 @@ from django.db.models.signals import pre_save
|
|||||||
from django.dispatch import receiver
|
from django.dispatch import receiver
|
||||||
from .hooks import ServicesHook
|
from .hooks import ServicesHook
|
||||||
from .tasks import disable_user
|
from .tasks import disable_user
|
||||||
|
from allianceauth.authentication.admin import User as AdminUser
|
||||||
|
|
||||||
from allianceauth.authentication.models import State, UserProfile
|
from allianceauth.authentication.models import State, UserProfile
|
||||||
from allianceauth.authentication.signals import state_changed
|
from allianceauth.authentication.signals import state_changed
|
||||||
@ -140,7 +141,6 @@ def pre_delete_user(sender, instance, *args, **kwargs):
|
|||||||
disable_user(instance)
|
disable_user(instance)
|
||||||
|
|
||||||
|
|
||||||
@receiver(pre_save, sender=User)
|
|
||||||
def pre_save_user(sender, instance, *args, **kwargs):
|
def pre_save_user(sender, instance, *args, **kwargs):
|
||||||
logger.debug("Received pre_save from %s" % instance)
|
logger.debug("Received pre_save from %s" % instance)
|
||||||
# check if user is being marked active/inactive
|
# check if user is being marked active/inactive
|
||||||
@ -154,3 +154,7 @@ def pre_save_user(sender, instance, *args, **kwargs):
|
|||||||
disable_user(instance)
|
disable_user(instance)
|
||||||
except User.DoesNotExist:
|
except User.DoesNotExist:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
pre_save.connect(pre_save_user, sender=User)
|
||||||
|
pre_save.connect(pre_save_user, sender=AdminUser)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user