diff --git a/allianceauth/analytics/migrations/0011_v5squash.py b/allianceauth/analytics/migrations/0011_v5squash.py
new file mode 100644
index 00000000..e8ac54b5
--- /dev/null
+++ b/allianceauth/analytics/migrations/0011_v5squash.py
@@ -0,0 +1,56 @@
+# Generated by Django 5.1.6 on 2025-03-04 01:03
+
+# This was built by Deleting Every Migration, Creating one from scratch
+# And porting in anything necessary
+
+import uuid
+
+from django.db import migrations, models
+
+
+def add_aa_team_token(apps, schema_editor):
+ Tokens = apps.get_model('analytics', 'AnalyticsTokens')
+ token = Tokens()
+
+ token.type = 'GA-V4'
+ token.token = 'G-6LYSMYK8DE'
+ token.secret = 'KLlpjLZ-SRGozS5f5wb_kw'
+ token.name = 'AA Team Public Google Analytics (V4)'
+ token.save()
+
+
+class Migration(migrations.Migration):
+
+ replaces = [('analytics', '0001_initial'), ('analytics', '0002_add_AA_Team_Token'), ('analytics', '0003_Generate_Identifier'), ('analytics', '0004_auto_20211015_0502'), ('analytics', '0005_alter_analyticspath_ignore_path'), ('analytics', '0006_more_ignore_paths'), ('analytics', '0007_analyticstokens_secret'), ('analytics', '0008_add_AA_GA-4_Team_Token '), ('analytics', '0009_remove_analyticstokens_ignore_paths_and_more'), ('analytics', '0010_alter_analyticsidentifier_options')]
+
+ initial = True
+
+ dependencies = [
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='AnalyticsIdentifier',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('identifier', models.UUIDField(default=uuid.uuid4, editable=False)),
+ ],
+ options={
+ 'verbose_name': 'Analytics Identifier',
+ },
+ ),
+ migrations.CreateModel(
+ name='AnalyticsTokens',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('name', models.CharField(max_length=254)),
+ ('type', models.CharField(choices=[('GA-U', 'Google Analytics Universal'), ('GA-V4', 'Google Analytics V4')], max_length=254)),
+ ('token', models.CharField(max_length=254)),
+ ('secret', models.CharField(blank=True, max_length=254)),
+ ('send_stats', models.BooleanField(default=False)),
+ ],
+ ),
+ migrations.RunPython(
+ add_aa_team_token
+ ),
+ ]
diff --git a/allianceauth/analytics/models.py b/allianceauth/analytics/models.py
index a1d1398b..64bbcc28 100644
--- a/allianceauth/analytics/models.py
+++ b/allianceauth/analytics/models.py
@@ -17,6 +17,7 @@ class AnalyticsIdentifier(SingletonModel):
class Meta:
verbose_name = "Analytics Identifier"
+
class AnalyticsTokens(models.Model):
class Analytics_Type(models.TextChoices):
diff --git a/allianceauth/authentication/migrations/0025_v5squash.py b/allianceauth/authentication/migrations/0025_v5squash.py
new file mode 100644
index 00000000..9d23d874
--- /dev/null
+++ b/allianceauth/authentication/migrations/0025_v5squash.py
@@ -0,0 +1,124 @@
+# Generated by Django 5.1.6 on 2025-03-04 02:44
+
+import django.contrib.auth.models
+import django.db.models.deletion
+from django.conf import settings
+from django.db import migrations, models
+
+import allianceauth.authentication.models
+
+
+def create_states(apps, schema_editor) -> None:
+ State = apps.get_model('authentication', 'State')
+
+ State.objects.update_or_create(name="Guest", defaults={'priority': 0, 'public': True})[0]
+ State.objects.update_or_create(name="Blue", defaults={'priority': 50, 'public': False})[0]
+ State.objects.update_or_create(name="Member", defaults={'priority': 100, 'public': False})[0]
+
+
+def create_states_reverse(apps, schema_editor) -> None:
+ pass
+
+
+class Migration(migrations.Migration):
+
+ replaces = [('authentication', '0001_initial'), ('authentication', '0002_auto_20160907_1914'), ('authentication', '0003_authservicesinfo_state'), ('authentication', '0004_create_permissions'), ('authentication', '0005_delete_perms'), ('authentication', '0006_auto_20160910_0542'), ('authentication', '0007_remove_authservicesinfo_is_blue'), ('authentication', '0008_set_state'), ('authentication', '0009_auto_20161021_0228'), ('authentication', '0010_only_one_authservicesinfo'), ('authentication', '0011_authservicesinfo_user_onetoonefield'), ('authentication', '0012_remove_add_delete_authservicesinfo_permissions'), ('authentication', '0013_service_modules'), ('authentication', '0014_fleetup_permission'), ('authentication', '0015_user_profiles'), ('authentication', '0016_ownershiprecord'), ('authentication', '0017_remove_fleetup_permission'), ('authentication', '0018_state_member_factions'), ('authentication', '0018_alter_state_name_length'), ('authentication', '0019_merge_20211026_0919'), ('authentication', '0020_userprofile_language_userprofile_night_mode'), ('authentication', '0021_alter_userprofile_language'), ('authentication', '0022_userprofile_theme'), ('authentication', '0023_alter_userprofile_language'), ('authentication', '0024_alter_userprofile_language')]
+
+ initial = True
+
+ dependencies = [
+ migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+ ('esi', '0012_fix_token_type_choices'),
+ ('eveonline', '0019_v5squash'),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='CharacterOwnership',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('owner_hash', models.CharField(max_length=28, unique=True)),
+ ('character', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='character_ownership', to='eveonline.evecharacter')),
+ ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='character_ownerships', to=settings.AUTH_USER_MODEL)),
+ ],
+ options={
+ 'default_permissions': ('change', 'delete'),
+ 'ordering': ['user', 'character__character_name'],
+ },
+ ),
+ migrations.CreateModel(
+ name='State',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('name', models.CharField(max_length=32, unique=True)),
+ ('priority', models.IntegerField(help_text='Users get assigned the state with the highest priority available to them.', unique=True)),
+ ('public', models.BooleanField(default=False, help_text='Make this state available to any character.')),
+ ('member_alliances', models.ManyToManyField(blank=True, help_text='Alliances to whose members this state is available.', to='eveonline.eveallianceinfo')),
+ ('member_characters', models.ManyToManyField(blank=True, help_text='Characters to which this state is available.', to='eveonline.evecharacter')),
+ ('member_corporations', models.ManyToManyField(blank=True, help_text='Corporations to whose members this state is available.', to='eveonline.evecorporationinfo')),
+ ('permissions', models.ManyToManyField(blank=True, to='auth.permission')),
+ ('member_factions', models.ManyToManyField(blank=True, help_text='Factions to whose members this state is available.', to='eveonline.evefactioninfo')),
+ ],
+ options={
+ 'ordering': ['-priority'],
+ },
+ ),
+ migrations.CreateModel(
+ name='UserProfile',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('main_character', models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='eveonline.evecharacter')),
+ ('state', models.ForeignKey(default=allianceauth.authentication.models.get_guest_state_pk, on_delete=django.db.models.deletion.SET_DEFAULT, to='authentication.state')),
+ ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='profile', to=settings.AUTH_USER_MODEL)),
+ ('night_mode', models.BooleanField(blank=True, null=True, verbose_name='Night Mode')),
+ ('theme', models.CharField(blank=True, help_text='Bootstrap 5 Themes from https://bootswatch.com/ or Community Apps', max_length=200, null=True, verbose_name='Theme')),
+ ('language', models.CharField(blank=True, choices=[('en', 'English'), ('cs-cz', 'Czech'), ('de', 'German'), ('es', 'Spanish'), ('it-it', 'Italian'), ('ja', 'Japanese'), ('ko-kr', 'Korean'), ('fr-fr', 'French'), ('ru', 'Russian'), ('nl-nl', 'Dutch'), ('pl-pl', 'Polish'), ('uk', 'Ukrainian'), ('zh-hans', 'Simplified Chinese')], default='', max_length=10, verbose_name='Language')),
+ ],
+ options={
+ 'default_permissions': ('change',),
+ },
+ ),
+ migrations.CreateModel(
+ name='Permission',
+ fields=[
+ ],
+ options={
+ 'proxy': True,
+ 'verbose_name': 'permission',
+ 'verbose_name_plural': 'permissions',
+ },
+ bases=('auth.permission',),
+ managers=[
+ ('objects', django.contrib.auth.models.PermissionManager()),
+ ],
+ ),
+ migrations.CreateModel(
+ name='User',
+ fields=[
+ ],
+ options={
+ 'proxy': True,
+ 'verbose_name': 'user',
+ 'verbose_name_plural': 'users',
+ },
+ bases=('auth.user',),
+ managers=[
+ ('objects', django.contrib.auth.models.UserManager()),
+ ],
+ ),
+ migrations.CreateModel(
+ name='OwnershipRecord',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('owner_hash', models.CharField(db_index=True, max_length=28)),
+ ('created', models.DateTimeField(auto_now=True)),
+ ('character', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='ownership_records', to='eveonline.evecharacter')),
+ ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='ownership_records', to=settings.AUTH_USER_MODEL)),
+ ],
+ options={
+ 'ordering': ['-created'],
+ },
+ ),
+ migrations.RunPython(create_states, create_states_reverse),
+
+ ]
diff --git a/allianceauth/authentication/models.py b/allianceauth/authentication/models.py
index 9670376b..29d53264 100644
--- a/allianceauth/authentication/models.py
+++ b/allianceauth/authentication/models.py
@@ -16,22 +16,28 @@ logger = logging.getLogger(__name__)
class State(models.Model):
name = models.CharField(max_length=32, unique=True)
permissions = models.ManyToManyField(Permission, blank=True)
- priority = models.IntegerField(unique=True, help_text="Users get assigned the state with the highest priority available to them.")
+ priority = models.IntegerField(
+ unique=True, help_text="Users get assigned the state with the highest priority available to them."
+ )
- member_characters = models.ManyToManyField(EveCharacter, blank=True,
- help_text="Characters to which this state is available.")
- member_corporations = models.ManyToManyField(EveCorporationInfo, blank=True,
- help_text="Corporations to whose members this state is available.")
- member_alliances = models.ManyToManyField(EveAllianceInfo, blank=True,
- help_text="Alliances to whose members this state is available.")
- member_factions = models.ManyToManyField(EveFactionInfo, blank=True,
- help_text="Factions to whose members this state is available.")
+ member_characters = models.ManyToManyField(
+ EveCharacter, blank=True, help_text="Characters to which this state is available."
+ )
+ member_corporations = models.ManyToManyField(
+ EveCorporationInfo, blank=True, help_text="Corporations to whose members this state is available."
+ )
+ member_alliances = models.ManyToManyField(
+ EveAllianceInfo, blank=True, help_text="Alliances to whose members this state is available."
+ )
+ member_factions = models.ManyToManyField(
+ EveFactionInfo, blank=True, help_text="Factions to whose members this state is available."
+ )
public = models.BooleanField(default=False, help_text="Make this state available to any character.")
objects: ClassVar[StateManager] = StateManager()
class Meta:
- ordering = ['-priority']
+ ordering = ["-priority"]
def __str__(self) -> str:
return self.name
@@ -49,11 +55,11 @@ class State(models.Model):
super().delete(**kwargs)
-def get_guest_state():
+def get_guest_state() -> State:
try:
- return State.objects.get(name='Guest')
+ return State.objects.get(name="Guest")
except State.DoesNotExist:
- return State.objects.create(name='Guest', priority=0, public=True)
+ return State.objects.create(name="Guest", priority=0, public=True)
def get_guest_state_pk():
@@ -61,76 +67,58 @@ def get_guest_state_pk():
class UserProfile(models.Model):
-
-
class Language(models.TextChoices):
"""
Choices for UserProfile.language
"""
- # Sorted by Language Code alphabetical order + English at top
- ENGLISH = 'en', _('English')
- CZECH = 'cs-cz', _("Czech") # Not yet at 50% translated
- GERMAN = 'de', _('German')
- SPANISH = 'es', _('Spanish')
- ITALIAN = 'it-it', _('Italian')
- JAPANESE = 'ja', _('Japanese')
- KOREAN = 'ko-kr', _('Korean')
- FRENCH = 'fr-fr', _('French')
- RUSSIAN = 'ru', _('Russian')
- DUTCH = 'nl-nl', _("Dutch")
- POLISH = 'pl-pl', _("Polish")
- UKRAINIAN = 'uk', _('Ukrainian')
- CHINESE = 'zh-hans', _('Simplified Chinese')
- 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_DEFAULT,
- default=get_guest_state_pk)
- language = models.CharField(
- _("Language"), max_length=10,
- choices=Language.choices,
- blank=True,
- default='')
- night_mode = models.BooleanField(
- _("Night Mode"),
- blank=True,
- null=True)
- theme = models.CharField(
+ # Sorted by Language Code alphabetical order + English at top
+ ENGLISH = "en", _("English")
+ CZECH = "cs-cz", _("Czech") # Not yet at 50% translated
+ GERMAN = "de", _("German")
+ SPANISH = "es", _("Spanish")
+ ITALIAN = "it-it", _("Italian")
+ JAPANESE = "ja", _("Japanese")
+ KOREAN = "ko-kr", _("Korean")
+ FRENCH = "fr-fr", _("French")
+ RUSSIAN = "ru", _("Russian")
+ DUTCH = "nl-nl", _("Dutch")
+ POLISH = "pl-pl", _("Polish")
+ UKRAINIAN = "uk", _("Ukrainian")
+ CHINESE = "zh-hans", _("Simplified Chinese")
+
+ 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_DEFAULT, default=get_guest_state_pk)
+ language = models.CharField(_("Language"), max_length=10, choices=Language.choices, blank=True, default="")
+ night_mode = models.BooleanField(_("Night Mode"), blank=True, null=True)
+ theme = models.CharField( # noqa:DJ001 Null has a specific meaning, never set by user
_("Theme"),
max_length=200,
blank=True,
- help_text="Bootstrap 5 Themes from https://bootswatch.com/ or Community Apps"
+ null=True,
+ help_text="Bootstrap 5 Themes from https://bootswatch.com/ or Community Apps",
)
class Meta:
- default_permissions = ('change',)
+ default_permissions = ("change",)
def __str__(self) -> str:
return str(self.user)
- def assign_state(self, state=None, commit=True):
+ def assign_state(self, state=None, commit=True) -> None:
if not state:
state = State.objects.get_for_user(self.user)
if self.state != state:
self.state = state
if commit:
- logger.info(f'Updating {self.user} state to {self.state}')
- self.save(update_fields=['state'])
+ logger.info(f"Updating {self.user} state to {self.state}")
+ self.save(update_fields=["state"])
notify(
self.user,
- _(f'State changed to: {state}'),
- _('Your user\'s state is now: %(state)s')
- % ({'state': state}),
- 'info'
+ _(f"State changed to: {state}"),
+ _("Your user's state is now: %(state)s") % ({"state": state}),
+ "info",
)
from allianceauth.authentication.signals import state_changed
@@ -138,16 +126,14 @@ class UserProfile(models.Model):
# Clear all attribute caches and reload the model that will get passed to the signals!
self.refresh_from_db()
- state_changed.send(
- sender=self.__class__, user=self.user, state=self.state
- )
+ state_changed.send(sender=self.__class__, user=self.user, state=self.state)
class CharacterOwnership(models.Model):
character = models.OneToOneField(EveCharacter, on_delete=models.CASCADE, related_name='character_ownership')
owner_hash = models.CharField(max_length=28, unique=True)
- user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='character_ownerships')
+ user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="character_ownerships")
objects: ClassVar[CharacterOwnershipManager] = CharacterOwnershipManager()
@@ -160,13 +146,13 @@ class CharacterOwnership(models.Model):
class OwnershipRecord(models.Model):
- character = models.ForeignKey(EveCharacter, on_delete=models.CASCADE, related_name='ownership_records')
+ character = models.ForeignKey(EveCharacter, on_delete=models.CASCADE, related_name="ownership_records")
owner_hash = models.CharField(max_length=28, db_index=True)
- user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='ownership_records')
+ user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="ownership_records")
created = models.DateTimeField(auto_now=True)
class Meta:
- ordering = ['-created']
+ ordering = ["-created"]
def __str__(self) -> str:
return f"{self.user}: {self.character} on {self.created}"
diff --git a/allianceauth/corputils/migrations/0006_v5squash.py b/allianceauth/corputils/migrations/0006_v5squash.py
new file mode 100644
index 00000000..be392489
--- /dev/null
+++ b/allianceauth/corputils/migrations/0006_v5squash.py
@@ -0,0 +1,52 @@
+# Generated by Django 5.1.6 on 2025-03-04 01:29
+
+# This was built by Deleting Every Migration, Creating one from scratch
+# And porting in anything necessary
+# Some functions were skipped as they only make sense _if you are migrating in place_
+# i.e. permissions migration
+
+
+import django.db.models.deletion
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ replaces = [('corputils', '0001_initial'), ('corputils', '0002_migrate_permissions'), ('corputils', '0003_granular_permissions'), ('corputils', '0004_member_models'), ('corputils', '0005_cleanup_permissions')]
+
+ initial = True
+
+ dependencies = [
+ ('esi', '0012_fix_token_type_choices'),
+ ('eveonline', '0019_v5squash'),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='CorpStats',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('last_update', models.DateTimeField(auto_now=True)),
+ ('corp', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to='eveonline.evecorporationinfo')),
+ ('token', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='esi.token')),
+ ],
+ options={
+ 'verbose_name': 'corp stats',
+ 'verbose_name_plural': 'corp stats',
+ 'permissions': (('view_corp_corpstats', 'Can view corp stats of their corporation.'), ('view_alliance_corpstats', 'Can view corp stats of members of their alliance.'), ('view_state_corpstats', 'Can view corp stats of members of their auth state.')),
+ },
+ ),
+ migrations.CreateModel(
+ name='CorpMember',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('character_id', models.PositiveIntegerField()),
+ ('character_name', models.CharField(max_length=37)),
+ ('corpstats', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='members', to='corputils.corpstats')),
+ ],
+ options={
+ 'ordering': ['character_name'],
+ 'unique_together': {('corpstats', 'character_id')},
+ },
+ ),
+ ]
diff --git a/allianceauth/corputils/models.py b/allianceauth/corputils/models.py
index 3be25bdc..6ee3dbcf 100644
--- a/allianceauth/corputils/models.py
+++ b/allianceauth/corputils/models.py
@@ -48,7 +48,7 @@ class CorpStats(models.Model):
def __str__(self) -> str:
return f"{self.__class__.__name__} for {self.corp}"
- def update(self):
+ def update(self) -> None:
try:
c = self.token.get_esi_client(spec_file=SWAGGER_SPEC_PATH)
assert c.Character.get_characters_character_id(character_id=self.token.character_id).result()['corporation_id'] == int(self.corp.corporation_id)
@@ -101,11 +101,11 @@ class CorpStats(models.Model):
return self.members.count()
@property
- def user_count(self):
+ def user_count(self) -> int:
return len({m.main_character for m in self.members.all() if m.main_character})
@property
- def registered_member_count(self):
+ def registered_member_count(self) -> int:
return len(self.registered_members)
@property
@@ -121,7 +121,7 @@ class CorpStats(models.Model):
return self.members.filter(pk__in=[m.pk for m in self.members.all() if not m.registered])
@property
- def main_count(self):
+ def main_count(self) -> int:
return len(self.mains)
@property
@@ -134,10 +134,10 @@ class CorpStats(models.Model):
def can_update(self, user):
return self.token.user == user or self.visible_to(user)
- def corp_logo(self, size=128):
+ def corp_logo(self, size=128) -> str:
return self.corp.logo_url(size)
- def alliance_logo(self, size=128):
+ def alliance_logo(self, size=128) -> str:
if self.corp.alliance:
return self.corp.alliance.logo_url(size)
else:
@@ -158,7 +158,7 @@ class CorpMember(models.Model):
return self.character_name
@property
- def character(self):
+ def character(self) -> EveCharacter | None:
try:
return EveCharacter.objects.get(character_id=self.character_id)
except EveCharacter.DoesNotExist:
@@ -179,20 +179,20 @@ class CorpMember(models.Model):
return []
@property
- def registered(self):
+ def registered(self) -> bool:
return CharacterOwnership.objects.filter(character__character_id=self.character_id).exists()
- def portrait_url(self, size=32):
+ def portrait_url(self, size=32) -> str:
return EveCharacter.generic_portrait_url(self.character_id, size)
@property
- def portrait_url_32(self):
+ def portrait_url_32(self) -> str:
return self.portrait_url(32)
@property
- def portrait_url_64(self):
+ def portrait_url_64(self) -> str:
return self.portrait_url(64)
@property
- def portrait_url_128(self):
+ def portrait_url_128(self) -> str:
return self.portrait_url(128)
diff --git a/allianceauth/crontab/models.py b/allianceauth/crontab/models.py
index 9b9875ad..bac89748 100644
--- a/allianceauth/crontab/models.py
+++ b/allianceauth/crontab/models.py
@@ -11,7 +11,6 @@ def random_default() -> float:
class CronOffset(SingletonModel):
-
minute = models.FloatField(_("Minute Offset"), default=random_default)
hour = models.FloatField(_("Hour Offset"), default=random_default)
day_of_month = models.FloatField(_("Day of Month Offset"), default=random_default)
diff --git a/allianceauth/custom_css/migrations/0002_alter_customcss_css.py b/allianceauth/custom_css/migrations/0002_alter_customcss_css.py
new file mode 100644
index 00000000..c0da84ee
--- /dev/null
+++ b/allianceauth/custom_css/migrations/0002_alter_customcss_css.py
@@ -0,0 +1,18 @@
+# Generated by Django 5.1.6 on 2025-03-05 00:59
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('custom_css', '0001_initial'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='customcss',
+ name='css',
+ field=models.TextField(blank=True, default='', help_text='This CSS will be added to the site after the default CSS.', verbose_name='Your custom CSS'),
+ ),
+ ]
diff --git a/allianceauth/custom_css/models.py b/allianceauth/custom_css/models.py
index 2b116fb4..259dac53 100644
--- a/allianceauth/custom_css/models.py
+++ b/allianceauth/custom_css/models.py
@@ -22,6 +22,7 @@ class CustomCSS(SingletonModel):
css = models.TextField(
blank=True,
verbose_name=_("Your custom CSS"),
+ default="",
help_text=_("This CSS will be added to the site after the default CSS."),
)
timestamp = models.DateTimeField(auto_now=True)
@@ -45,7 +46,7 @@ class CustomCSS(SingletonModel):
return str(_("Custom CSS"))
- def save(self, *args, **kwargs):
+ def save(self, *args, **kwargs) -> None:
"""
Save method for CustomCSS
@@ -61,9 +62,7 @@ class CustomCSS(SingletonModel):
if self.css and len(self.css.replace(" ", "")) > 0:
# Write the custom CSS to a file
- custom_css_file = open(
- f"{settings.STATIC_ROOT}allianceauth/custom-styles.css", "w+"
- )
+ custom_css_file = open(f"{settings.STATIC_ROOT}allianceauth/custom-styles.css", "w+")
custom_css_file.write(self.compress_css())
custom_css_file.close()
else:
@@ -105,9 +104,7 @@ class CustomCSS(SingletonModel):
)
# Fragment values can loose zeros
- css = re.sub(
- pattern=r":\s*0(\.\d+([cm]m|e[mx]|in|p[ctx]))\s*;", repl=r":\1;", string=css
- )
+ css = re.sub(pattern=r":\s*0(\.\d+([cm]m|e[mx]|in|p[ctx]))\s*;", repl=r":\1;", string=css)
for rule in re.findall(pattern=r"([^{]+){([^}]*)}", string=css):
# We don't need spaces around operators
diff --git a/allianceauth/eveonline/autogroups/migrations/0001_initial.py b/allianceauth/eveonline/autogroups/migrations/0001_initial.py
index 9716d3af..fc62cad5 100644
--- a/allianceauth/eveonline/autogroups/migrations/0001_initial.py
+++ b/allianceauth/eveonline/autogroups/migrations/0001_initial.py
@@ -1,6 +1,7 @@
-# Generated by Django 1.11.6 on 2017-12-23 04:30
+# Generated by Django 5.1.6 on 2025-03-05 02:08
import django.db.models.deletion
+from django.conf import settings
from django.db import migrations, models
@@ -9,9 +10,9 @@ class Migration(migrations.Migration):
initial = True
dependencies = [
- ('authentication', '0015_user_profiles'),
- ('auth', '0008_alter_user_username_max_length'),
- ('eveonline', '0009_on_delete'),
+ migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+ ('authentication', '0025_v5squash'),
+ ('eveonline', '0019_v5squash'),
]
operations = [
@@ -27,27 +28,16 @@ class Migration(migrations.Migration):
('alliance_name_source', models.CharField(choices=[('ticker', 'Ticker'), ('name', 'Full name')], default='name', max_length=20)),
('replace_spaces', models.BooleanField(default=False)),
('replace_spaces_with', models.CharField(blank=True, default='', help_text='Any spaces in the group name will be replaced with this.', max_length=10)),
+ ('states', models.ManyToManyField(related_name='autogroups', to='authentication.state')),
],
),
migrations.CreateModel(
name='ManagedAllianceGroup',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
- ('alliance', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='eveonline.EveAllianceInfo')),
- ('config', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='eve_autogroups.AutogroupsConfig')),
- ('group', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='auth.Group')),
- ],
- options={
- 'abstract': False,
- },
- ),
- migrations.CreateModel(
- name='ManagedCorpGroup',
- fields=[
- ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
- ('config', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='eve_autogroups.AutogroupsConfig')),
- ('corp', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='eveonline.EveCorporationInfo')),
- ('group', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='auth.Group')),
+ ('alliance', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='eveonline.eveallianceinfo')),
+ ('config', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='eve_autogroups.autogroupsconfig')),
+ ('group', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='auth.group')),
],
options={
'abstract': False,
@@ -56,16 +46,23 @@ class Migration(migrations.Migration):
migrations.AddField(
model_name='autogroupsconfig',
name='alliance_managed_groups',
- field=models.ManyToManyField(help_text="A list of alliance groups created and maintained by this AutogroupConfig. You should not edit this list unless you know what you're doing.", related_name='alliance_managed_config', through='eve_autogroups.ManagedAllianceGroup', to='auth.Group'),
+ field=models.ManyToManyField(help_text="A list of alliance groups created and maintained by this AutogroupConfig. You should not edit this list unless you know what you're doing.", related_name='alliance_managed_config', through='eve_autogroups.ManagedAllianceGroup', to='auth.group'),
+ ),
+ migrations.CreateModel(
+ name='ManagedCorpGroup',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('config', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='eve_autogroups.autogroupsconfig')),
+ ('corp', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='eveonline.evecorporationinfo')),
+ ('group', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='auth.group')),
+ ],
+ options={
+ 'abstract': False,
+ },
),
migrations.AddField(
model_name='autogroupsconfig',
name='corp_managed_groups',
- field=models.ManyToManyField(help_text="A list of corporation groups created and maintained by this AutogroupConfig. You should not edit this list unless you know what you're doing.", related_name='corp_managed_config', through='eve_autogroups.ManagedCorpGroup', to='auth.Group'),
- ),
- migrations.AddField(
- model_name='autogroupsconfig',
- name='states',
- field=models.ManyToManyField(related_name='autogroups', to='authentication.State'),
+ field=models.ManyToManyField(help_text="A list of corporation groups created and maintained by this AutogroupConfig. You should not edit this list unless you know what you're doing.", related_name='corp_managed_config', through='eve_autogroups.ManagedCorpGroup', to='auth.group'),
),
]
diff --git a/allianceauth/eveonline/autogroups/models.py b/allianceauth/eveonline/autogroups/models.py
index 4ae5a24f..2d896076 100644
--- a/allianceauth/eveonline/autogroups/models.py
+++ b/allianceauth/eveonline/autogroups/models.py
@@ -85,20 +85,20 @@ class AutogroupsConfig(models.Model):
def __str__(self) -> str:
return 'States: ' + (' '.join(list(self.states.all().values_list('name', flat=True))) if self.pk else str(None))
- def __init__(self, *args, **kwargs):
+ def __init__(self, *args, **kwargs) -> None:
super().__init__(*args, **kwargs)
- def __repr__(self):
+ def __repr__(self) -> str:
return self.__class__.__name__
- def update_all_states_group_membership(self):
+ def update_all_states_group_membership(self) -> None:
list(map(self.update_group_membership_for_state, self.states.all()))
def update_group_membership_for_state(self, state: State):
list(map(self.update_group_membership_for_user, get_users_for_state(state)))
@transaction.atomic
- def update_group_membership_for_user(self, user: User):
+ def update_group_membership_for_user(self, user: User) -> None:
self.update_alliance_group_membership(user)
self.update_corp_group_membership(user)
@@ -239,6 +239,7 @@ class ManagedGroup(models.Model):
def __str__(self) -> str:
return f"Managed Group: {self.group.name}"
+
class ManagedCorpGroup(ManagedGroup):
corp = models.ForeignKey(EveCorporationInfo, on_delete=models.CASCADE)
diff --git a/allianceauth/eveonline/migrations/0018_alter_evecharacter_alliance_name_and_more.py b/allianceauth/eveonline/migrations/0018_alter_evecharacter_alliance_name_and_more.py
new file mode 100644
index 00000000..73d5a94c
--- /dev/null
+++ b/allianceauth/eveonline/migrations/0018_alter_evecharacter_alliance_name_and_more.py
@@ -0,0 +1,28 @@
+# Generated by Django 5.1.6 on 2025-03-04 01:29
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('eveonline', '0017_alliance_and_corp_names_are_not_unique'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='evecharacter',
+ name='alliance_name',
+ field=models.CharField(blank=True, default='', max_length=254, null=True),
+ ),
+ migrations.AlterField(
+ model_name='evecharacter',
+ name='alliance_ticker',
+ field=models.CharField(blank=True, default='', max_length=5, null=True),
+ ),
+ migrations.AlterField(
+ model_name='evecharacter',
+ name='faction_name',
+ field=models.CharField(blank=True, default='', max_length=254, null=True),
+ ),
+ ]
diff --git a/allianceauth/eveonline/migrations/0019_v5squash.py b/allianceauth/eveonline/migrations/0019_v5squash.py
new file mode 100644
index 00000000..88bf42e9
--- /dev/null
+++ b/allianceauth/eveonline/migrations/0019_v5squash.py
@@ -0,0 +1,73 @@
+# Generated by Django 5.1.6 on 2025-03-05 02:19
+
+import django.db.models.deletion
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ replaces = [('eveonline', '0001_initial'), ('eveonline', '0002_remove_eveapikeypair_error_count'), ('eveonline', '0003_auto_20161026_0149'), ('eveonline', '0004_eveapikeypair_sso_verified'), ('eveonline', '0005_remove_eveallianceinfo_member_count'), ('eveonline', '0006_allow_null_evecharacter_alliance'), ('eveonline', '0007_unique_id_name'), ('eveonline', '0008_remove_apikeys'), ('eveonline', '0009_on_delete'), ('eveonline', '0010_alliance_ticker'), ('eveonline', '0011_ids_to_integers'), ('eveonline', '0012_index_additions'), ('eveonline', '0013_evecorporationinfo_ceo_id'), ('eveonline', '0014_auto_20210105_1413'), ('eveonline', '0015_factions'), ('eveonline', '0016_character_names_are_not_unique'), ('eveonline', '0017_alliance_and_corp_names_are_not_unique'), ('eveonline', '0018_alter_evecharacter_alliance_name_and_more')]
+
+ initial = True
+
+ dependencies = [
+ ('auth', '__first__'),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='EveAllianceInfo',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('alliance_id', models.PositiveIntegerField(unique=True)),
+ ('alliance_name', models.CharField(db_index=True, max_length=254)),
+ ('alliance_ticker', models.CharField(max_length=254)),
+ ('executor_corp_id', models.PositiveIntegerField()),
+ ],
+ options={
+ 'indexes': [models.Index(fields=['executor_corp_id'], name='eveonline_e_executo_7f3280_idx')],
+ },
+ ),
+ migrations.CreateModel(
+ name='EveFactionInfo',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('faction_id', models.PositiveIntegerField(db_index=True, unique=True)),
+ ('faction_name', models.CharField(max_length=254, unique=True)),
+ ],
+ ),
+ migrations.CreateModel(
+ name='EveCorporationInfo',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('corporation_id', models.PositiveIntegerField(unique=True)),
+ ('corporation_name', models.CharField(db_index=True, max_length=254)),
+ ('corporation_ticker', models.CharField(max_length=254)),
+ ('member_count', models.IntegerField()),
+ ('alliance', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='eveonline.eveallianceinfo')),
+ ('ceo_id', models.PositiveIntegerField(blank=True, default=None, null=True)),
+ ],
+ options={
+ 'indexes': [models.Index(fields=['ceo_id'], name='eveonline_e_ceo_id_eea7b8_idx')],
+ },
+ ),
+ migrations.CreateModel(
+ name='EveCharacter',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('character_id', models.PositiveIntegerField(unique=True)),
+ ('character_name', models.CharField(db_index=True, max_length=254)),
+ ('corporation_id', models.PositiveIntegerField()),
+ ('corporation_name', models.CharField(max_length=254)),
+ ('corporation_ticker', models.CharField(max_length=5)),
+ ('alliance_id', models.PositiveIntegerField(blank=True, default=None, null=True)),
+ ('alliance_name', models.CharField(blank=True, default='', max_length=254, null=True)),
+ ('alliance_ticker', models.CharField(blank=True, default='', max_length=5, null=True)),
+ ('faction_id', models.PositiveIntegerField(blank=True, default=None, null=True)),
+ ('faction_name', models.CharField(blank=True, default='', max_length=254, null=True)),
+ ],
+ options={
+ 'indexes': [models.Index(fields=['corporation_id'], name='eveonline_e_corpora_cb4cd9_idx'), models.Index(fields=['alliance_id'], name='eveonline_e_allianc_39ee2a_idx'), models.Index(fields=['corporation_name'], name='eveonline_e_corpora_893c60_idx'), models.Index(fields=['alliance_name'], name='eveonline_e_allianc_63fd98_idx'), models.Index(fields=['faction_id'], name='eveonline_e_faction_d5274e_idx')],
+ },
+ ),
+ ]
diff --git a/allianceauth/eveonline/models.py b/allianceauth/eveonline/models.py
index d2645888..813ccc9b 100644
--- a/allianceauth/eveonline/models.py
+++ b/allianceauth/eveonline/models.py
@@ -81,9 +81,11 @@ class EveAllianceInfo(models.Model):
class Meta:
indexes = [models.Index(fields=['executor_corp_id',])]
+
def __str__(self) -> str:
return self.alliance_name
- def populate_alliance(self):
+
+ def populate_alliance(self) -> None:
alliance = self.provider.get_alliance(self.alliance_id)
for corp_id in alliance.corp_ids:
if not EveCorporationInfo.objects.filter(corporation_id=corp_id).exists():
@@ -102,8 +104,6 @@ class EveAllianceInfo(models.Model):
self.save()
return self
-
-
@staticmethod
def generic_logo_url(
alliance_id: int, size: int = _DEFAULT_IMAGE_SIZE
@@ -153,8 +153,10 @@ class EveCorporationInfo(models.Model):
class Meta:
indexes = [models.Index(fields=['ceo_id',]),]
+
def __str__(self) -> str:
return self.corporation_name
+
def update_corporation(self, corp: providers.Corporation = None):
if corp is None:
corp = self.provider.get_corporation(self.corporation_id)
@@ -167,8 +169,6 @@ class EveCorporationInfo(models.Model):
self.save()
return self
-
-
@staticmethod
def generic_logo_url(
corporation_id: int, size: int = _DEFAULT_IMAGE_SIZE
@@ -210,10 +210,10 @@ class EveCharacter(models.Model):
corporation_name = models.CharField(max_length=254)
corporation_ticker = models.CharField(max_length=5)
alliance_id = models.PositiveIntegerField(blank=True, null=True, default=None)
- alliance_name = models.CharField(max_length=254, blank=True, default='')
- alliance_ticker = models.CharField(max_length=5, blank=True, default='')
- faction_id = models.PositiveIntegerField(blank=True, default=None)
- faction_name = models.CharField(max_length=254, blank=True, default='')
+ alliance_name = models.CharField(max_length=254, blank=True, null=True, default='') # noqa: DJ001
+ alliance_ticker = models.CharField(max_length=5, blank=True, null=True, default='') # noqa: DJ001
+ faction_id = models.PositiveIntegerField(blank=True, null=True, default=None)
+ faction_name = models.CharField(max_length=254, blank=True, null=True, default='') # noqa: DJ001
objects: ClassVar[EveCharacterManager] = EveCharacterManager()
provider = EveCharacterProviderManager()
diff --git a/allianceauth/eveonline/providers.py b/allianceauth/eveonline/providers.py
index 201db860..10caf1be 100644
--- a/allianceauth/eveonline/providers.py
+++ b/allianceauth/eveonline/providers.py
@@ -1,5 +1,6 @@
import logging
import os
+from typing import Literal
from bravado.client import SwaggerClient
from bravado.exception import HTTPError, HTTPNotFound, HTTPUnprocessableEntity
@@ -50,10 +51,10 @@ class Entity:
def __str__(self) -> str:
return self.name
- def __repr__(self):
+ def __repr__(self) -> str:
return f"<{self.__class__.__name__} ({self.id}): {self.name}>"
- def __bool__(self):
+ def __bool__(self) -> bool:
return bool(self.id)
def __eq__(self, other):
diff --git a/allianceauth/fleetactivitytracking/migrations/0008_v5squash.py b/allianceauth/fleetactivitytracking/migrations/0008_v5squash.py
new file mode 100644
index 00000000..9c272f97
--- /dev/null
+++ b/allianceauth/fleetactivitytracking/migrations/0008_v5squash.py
@@ -0,0 +1,67 @@
+# Generated by Django 5.1.6 on 2025-03-04 01:20
+
+import django.db.models.deletion
+import django.utils.timezone
+from django.conf import settings
+from django.db import migrations, models
+
+import allianceauth.framework.api.user
+
+
+def create_permissions(apps, schema_editor) -> None:
+ # Remnant of AAv0
+ User = apps.get_model('auth', 'User')
+ ContentType = apps.get_model('contenttypes', 'ContentType')
+ Permission = apps.get_model('auth', 'Permission')
+ ct = ContentType.objects.get_for_model(User)
+ Permission.objects.get_or_create(codename="fleetactivitytracking", content_type=ct, name="fleetactivitytracking")
+ Permission.objects.get_or_create(codename="fleetactivitytracking_statistics", content_type=ct, name="fleetactivitytracking_statistics")
+
+
+def reverse(apps, schema_editor) -> None:
+ pass
+
+
+class Migration(migrations.Migration):
+
+ replaces = [('fleetactivitytracking', '0001_initial'), ('fleetactivitytracking', '0002_auto_20160905_2220'), ('fleetactivitytracking', '0003_auto_20160906_2354'), ('fleetactivitytracking', '0004_make_strings_more_stringy'), ('fleetactivitytracking', '0005_remove_fat_name'), ('fleetactivitytracking', '0006_auto_20180803_0430'), ('fleetactivitytracking', '0007_sentinel_user')]
+
+ initial = True
+
+ dependencies = [
+ migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+ ('eveonline', '0019_v5squash'),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='Fatlink',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('fatdatetime', models.DateTimeField(default=django.utils.timezone.now)),
+ ('duration', models.PositiveIntegerField()),
+ ('fleet', models.CharField(max_length=254)),
+ ('hash', models.CharField(max_length=254, unique=True)),
+ ('creator', models.ForeignKey(on_delete=models.SET(allianceauth.framework.api.user.get_sentinel_user), to=settings.AUTH_USER_MODEL)),
+ ],
+ options={
+ 'permissions': ()
+ },
+ ),
+ migrations.CreateModel(
+ name='Fat',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('system', models.CharField(max_length=30)),
+ ('shiptype', models.CharField(max_length=100)),
+ ('station', models.CharField(max_length=125)),
+ ('character', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='eveonline.evecharacter')),
+ ('fatlink', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='fleetactivitytracking.fatlink')),
+ ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
+ ],
+ options={
+ 'unique_together': {('character', 'fatlink')},
+ },
+ ),
+ migrations.RunPython(create_permissions, reverse)
+ ]
diff --git a/allianceauth/fleetactivitytracking/models.py b/allianceauth/fleetactivitytracking/models.py
index a250fc68..eb2a5d36 100644
--- a/allianceauth/fleetactivitytracking/models.py
+++ b/allianceauth/fleetactivitytracking/models.py
@@ -13,6 +13,14 @@ class Fatlink(models.Model):
hash = models.CharField(max_length=254, unique=True)
creator = models.ForeignKey(User, on_delete=models.SET(get_sentinel_user))
+ class Meta:
+ permissions = (
+ # Intentionally Commented out
+ # AAv0 has these in the Auth_ Content Type
+ # ('fleetactivitytracking', 'fleetactivitytracking'),
+ # ('fleetactivitytracking_statistics', 'fleetactivitytracking_statistics'),
+ )
+
def __str__(self) -> str:
return self.fleet
@@ -26,7 +34,7 @@ class Fat(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
class Meta:
- unique_together = (('character', 'fatlink'),)
+ unique_together = (("character", "fatlink"),)
def __str__(self) -> str:
return f"Fat-link for {self.character.character_name}"
diff --git a/allianceauth/groupmanagement/migrations/0020_v5squash.py b/allianceauth/groupmanagement/migrations/0020_v5squash.py
new file mode 100644
index 00000000..f813c055
--- /dev/null
+++ b/allianceauth/groupmanagement/migrations/0020_v5squash.py
@@ -0,0 +1,102 @@
+# Generated by Django 5.1.6 on 2025-03-04 02:50
+
+import django.contrib.auth.models
+import django.db.models.deletion
+import django.utils.timezone
+from django.conf import settings
+from django.db import migrations, models
+
+
+def create_permissions(apps, schema_editor) -> None:
+ # Remnant of AAv0
+ User = apps.get_model('auth', 'User')
+ ContentType = apps.get_model('contenttypes', 'ContentType')
+ Permission = apps.get_model('auth', 'Permission')
+ ct = ContentType.objects.get_for_model(User)
+ Permission.objects.get_or_create(codename="group_management", content_type=ct, name="group_management")
+
+
+def reverse(apps, schema_editor) -> None:
+ pass
+
+
+class Migration(migrations.Migration):
+
+ replaces = [('groupmanagement', '0001_initial'), ('groupmanagement', '0002_auto_20160906_2354'), ('groupmanagement', '0003_default_groups'), ('groupmanagement', '0004_authgroup'), ('groupmanagement', '0005_authgroup_public'), ('groupmanagement', '0006_request_groups_perm'), ('groupmanagement', '0007_on_delete'), ('groupmanagement', '0008_remove_authgroup_permissions'), ('groupmanagement', '0009_requestlog'), ('groupmanagement', '0010_authgroup_states'), ('groupmanagement', '0011_requestlog_date'), ('groupmanagement', '0012_group_leads'), ('groupmanagement', '0013_fix_requestlog_date_field'), ('groupmanagement', '0014_auto_20200918_1412'), ('groupmanagement', '0015_make_descriptions_great_again'), ('groupmanagement', '0016_remove_grouprequest_status_field'), ('groupmanagement', '0017_improve_groups_documentation'), ('groupmanagement', '0018_reservedgroupname'), ('groupmanagement', '0019_adding_restricted_to_groups')]
+
+ initial = True
+
+ dependencies = [
+ migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+ ('authentication', '0025_v5squash'),
+ ('eveonline', '0019_v5squash'),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='GroupRequest',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('leave_request', models.BooleanField(default=0)),
+ ('group', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='auth.group')),
+ ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
+ ],
+ ),
+ migrations.CreateModel(
+ name='AuthGroup',
+ fields=[
+ ('group', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, primary_key=True, serialize=False, to='auth.group')),
+ ('internal', models.BooleanField(default=True, help_text='Internal group, users cannot see, join or request to join this group.
Used for groups such as Members, Corp_*, Alliance_* etc.
Overrides Hidden and Open options when selected.')),
+ ('hidden', models.BooleanField(default=True, help_text='Group is hidden from users but can still join with the correct link.')),
+ ('open', models.BooleanField(default=False, help_text='Group is open and users will be automatically added upon request.
If the group is not open users will need their request manually approved.')),
+ ('description', models.TextField(blank=True, help_text='Short description (max. 512 characters) of the group shown to users.', max_length=512)),
+ ('group_leaders', models.ManyToManyField(blank=True, help_text='Group leaders can process requests for this group. Use the auth.group_management
permission to allow a user to manage all groups.
', related_name='leads_groups', to=settings.AUTH_USER_MODEL)),
+ ('public', models.BooleanField(default=False, help_text='Group is public. Any registered user is able to join this group, with visibility based on the other options set for this group.
Auth will not remove users from this group automatically when they are no longer authenticated.')),
+ ('group_leader_groups', models.ManyToManyField(blank=True, help_text='Members of leader groups can process requests for this group. Use the auth.group_management
permission to allow a user to manage all groups.
', related_name='leads_group_groups', to='auth.group')),
+ ('states', models.ManyToManyField(blank=True, help_text='States listed here will have the ability to join this group provided they have the proper permissions.
', related_name='valid_states', to='authentication.state')),
+ ('restricted', models.BooleanField(default=False, help_text='Group is restricted. This means that adding or removing users for this group requires a superuser admin.')),
+ ],
+ options={
+ 'default_permissions': (),
+ 'permissions': (('request_groups', 'Can request non-public groups'),),
+ },
+ ),
+ migrations.CreateModel(
+ name='Group',
+ fields=[
+ ],
+ options={
+ 'verbose_name': 'group',
+ 'indexes': [],
+ 'proxy': True,
+ 'verbose_name_plural': 'groups',
+ },
+ bases=('auth.group',),
+ managers=[
+ ('objects', django.contrib.auth.models.GroupManager()),
+ ],
+ ),
+ migrations.CreateModel(
+ name='RequestLog',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('request_type', models.BooleanField(null=True)),
+ ('request_info', models.CharField(max_length=254)),
+ ('action', models.BooleanField(default=0)),
+ ('group', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='auth.group')),
+ ('request_actor', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
+ ('date', models.DateTimeField(auto_now_add=True)),
+ ],
+ ),
+ migrations.CreateModel(
+ name='ReservedGroupName',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('name', models.CharField(help_text='Name that can not be used for groups.', max_length=150, unique=True, verbose_name='name')),
+ ('reason', models.TextField(help_text='Reason why this name is reserved.', verbose_name='reason')),
+ ('created_by', models.CharField(help_text='Name of the user who created this entry.', max_length=255, verbose_name='created by')),
+ ('created_at', models.DateTimeField(default=django.utils.timezone.now, help_text='Date when this entry was created', verbose_name='created at')),
+ ],
+ ),
+ migrations.RunPython(create_permissions, reverse)
+ ]
diff --git a/allianceauth/groupmanagement/models.py b/allianceauth/groupmanagement/models.py
index 70f5380f..b1df1b5e 100644
--- a/allianceauth/groupmanagement/models.py
+++ b/allianceauth/groupmanagement/models.py
@@ -53,7 +53,7 @@ class RequestLog(models.Model):
def __str__(self) -> str:
return self.pk
- def requestor(self):
+ def requestor(self) -> str:
return self.request_info.split(":")[0]
def type_to_str(self):
@@ -176,6 +176,9 @@ class AuthGroup(models.Model):
class Meta:
permissions = (
("request_groups", _("Can request non-public groups")),
+ # Intentionally Commented out
+ # AAv0 has these in the Auth_ Content Type
+ # ('group_management', 'group_management'))
)
default_permissions = ()
diff --git a/allianceauth/hrapplications/migrations/0008_v5squash.py b/allianceauth/hrapplications/migrations/0008_v5squash.py
new file mode 100644
index 00000000..3a34f407
--- /dev/null
+++ b/allianceauth/hrapplications/migrations/0008_v5squash.py
@@ -0,0 +1,100 @@
+# Generated by Django 5.1.6 on 2025-03-04 04:31
+
+import sortedm2m.fields
+
+import django.db.models.deletion
+from django.conf import settings
+from django.db import migrations, models
+
+
+def create_permissions(apps, schema_editor) -> None:
+ # Remnant of AAv0
+ User = apps.get_model('auth', 'User')
+ ContentType = apps.get_model('contenttypes', 'ContentType')
+ Permission = apps.get_model('auth', 'Permission')
+ ct = ContentType.objects.get_for_model(User)
+ Permission.objects.get_or_create(codename="human_resources", content_type=ct, name="human_resources")
+
+
+def reverse(apps, schema_editor) -> None:
+ pass
+
+
+class Migration(migrations.Migration):
+
+ replaces = [('hrapplications', '0001_initial'), ('hrapplications', '0002_choices_for_questions'), ('hrapplications', '0003_applicationquestion_multi_select'), ('hrapplications', '0004_make_strings_more_stringy'), ('hrapplications', '0005_sorted_questions'), ('hrapplications', '0006_remove_legacy_models'), ('hrapplications', '0007_auto_20200918_1412')]
+
+ initial = True
+
+ dependencies = [
+ migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+ ('eveonline', '0019_v5squash'),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='ApplicationQuestion',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('title', models.CharField(max_length=254, verbose_name='Question')),
+ ('help_text', models.CharField(blank=True, max_length=254, null=True)),
+ ('multi_select', models.BooleanField(default=False)),
+ ],
+ ),
+ migrations.CreateModel(
+ name='ApplicationForm',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('corp', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to='eveonline.evecorporationinfo')),
+ ('questions', sortedm2m.fields.SortedManyToManyField(help_text=None, to='hrapplications.applicationquestion')),
+ ],
+ ),
+ migrations.CreateModel(
+ name='ApplicationChoice',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('choice_text', models.CharField(max_length=200, verbose_name='Choice')),
+ ('question', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='choices', to='hrapplications.applicationquestion')),
+ ],
+ ),
+ migrations.CreateModel(
+ name='Application',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('approved', models.BooleanField(blank=True, default=None, null=True)),
+ ('created', models.DateTimeField(auto_now_add=True)),
+ ('form', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='applications', to='hrapplications.applicationform')),
+ ('reviewer', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL)),
+ ('reviewer_character', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='eveonline.evecharacter')),
+ ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='applications', to=settings.AUTH_USER_MODEL)),
+ ],
+ options={
+ 'permissions': (('approve_application', 'Can approve applications'), ('reject_application', 'Can reject applications'), ('view_apis', 'Can view applicant APIs')),
+ 'unique_together': {('form', 'user')},
+ },
+ ),
+ migrations.CreateModel(
+ name='ApplicationComment',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('text', models.TextField()),
+ ('created', models.DateTimeField(auto_now_add=True)),
+ ('application', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='comments', to='hrapplications.application')),
+ ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
+ ],
+ ),
+ migrations.CreateModel(
+ name='ApplicationResponse',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('answer', models.TextField()),
+ ('application', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='responses', to='hrapplications.application')),
+ ('question', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='hrapplications.applicationquestion')),
+ ],
+ options={
+ 'unique_together': {('question', 'application')},
+ },
+ ),
+ migrations.RunPython(create_permissions, reverse)
+
+ ]
diff --git a/allianceauth/hrapplications/models.py b/allianceauth/hrapplications/models.py
index 54c271ff..edc69dc4 100644
--- a/allianceauth/hrapplications/models.py
+++ b/allianceauth/hrapplications/models.py
@@ -30,6 +30,13 @@ class ApplicationForm(models.Model):
questions = SortedManyToManyField(ApplicationQuestion)
corp = models.OneToOneField(EveCorporationInfo, on_delete=models.CASCADE)
+ class Meta:
+ permissions = (
+ # Intentionally Commented out
+ # AAv0 has these in the Auth_ Content Type
+ # ('human_resources', 'human_resources'))
+ )
+
def __str__(self) -> str:
return str(self.corp)
@@ -44,11 +51,11 @@ class Application(models.Model):
objects: ClassVar[ApplicationManager] = ApplicationManager()
-
class Meta:
permissions = (
- ('approve_application', 'Can approve applications'), ('reject_application', 'Can reject applications'),
- ('view_apis', 'Can view applicant APIs'),)
+ ('approve_application', 'Can approve applications'),
+ ('reject_application', 'Can reject applications'),
+ )
unique_together = ('form', 'user')
def __str__(self) -> str:
@@ -76,14 +83,14 @@ class ApplicationResponse(models.Model):
question = models.ForeignKey(ApplicationQuestion, on_delete=models.CASCADE)
application = models.ForeignKey(Application, on_delete=models.CASCADE, related_name='responses')
answer = models.TextField()
+
class Meta:
unique_together = ('question', 'application')
+
def __str__(self) -> str:
return str(self.application) + " Answer To " + str(self.question)
-
-
class ApplicationComment(models.Model):
application = models.ForeignKey(Application, on_delete=models.CASCADE, related_name='comments')
user = models.ForeignKey(User, on_delete=models.CASCADE)
diff --git a/allianceauth/menu/migrations/0002_alter_menuitem_hook_hash.py b/allianceauth/menu/migrations/0002_alter_menuitem_hook_hash.py
new file mode 100644
index 00000000..a565c24a
--- /dev/null
+++ b/allianceauth/menu/migrations/0002_alter_menuitem_hook_hash.py
@@ -0,0 +1,18 @@
+# Generated by Django 5.1.6 on 2025-03-05 00:59
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('menu', '0001_initial'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='menuitem',
+ name='hook_hash',
+ field=models.CharField(default=None, editable=False, help_text='hash of a menu item hook. Must be nullable for unique comparison.', max_length=64, null=True, unique=True),
+ ),
+ ]
diff --git a/allianceauth/menu/models.py b/allianceauth/menu/models.py
index 0be8da19..9432c526 100644
--- a/allianceauth/menu/models.py
+++ b/allianceauth/menu/models.py
@@ -41,10 +41,7 @@ class MenuItem(models.Model):
is_hidden = models.BooleanField(
default=False,
verbose_name=_("is hidden"),
- help_text=_(
- "Hide this menu item."
- "If this item is a folder all items under it will be hidden too"
- ),
+ help_text=_("Hide this menu item." "If this item is a folder all items under it will be hidden too"),
)
# app related properties
@@ -54,7 +51,7 @@ class MenuItem(models.Model):
null=True,
unique=True,
editable=False,
- help_text="hash of a menu item hook. Must be nullable for unique comparison."
+ help_text="hash of a menu item hook. Must be nullable for unique comparison.",
)
# user defined properties
@@ -63,10 +60,7 @@ class MenuItem(models.Model):
default="",
blank=True,
verbose_name=_("icon classes"),
- help_text=_(
- "Font Awesome classes to show as icon on menu, "
- "e.g. fa-solid fa-house
"
- ),
+ help_text=_("Font Awesome classes to show as icon on menu, " "e.g. fa-solid fa-house
"),
)
url = models.TextField(
default="",
@@ -79,7 +73,7 @@ class MenuItem(models.Model):
def __str__(self) -> str:
return self.text
- def save(self, *args, **kwargs):
+ def save(self, *args, **kwargs) -> None:
if not self.hook_hash:
self.hook_hash = None # empty strings can create problems
return super().save(*args, **kwargs)
@@ -125,14 +119,12 @@ class MenuItem(models.Model):
if self.is_app_item:
raise ValueError("The related hook objects should be used for app items.")
- hook_obj = MenuItemHookCustom(
- text=self.text, classes=self.classes, url_name="", order=self.order
- )
+ hook_obj = MenuItemHookCustom(text=self.text, classes=self.classes, url_name="", order=self.order)
hook_obj.navactive = []
if self.is_folder and not self.classes:
hook_obj.classes = DEFAULT_FOLDER_ICON_CLASSES
hook_obj.url = self.url
hook_obj.is_folder = self.is_folder
- hook_obj.html_id = f"id-folder-{self.id}" if self.is_folder else ""
+ hook_obj.html_id = f"id-folder-{self.pk}" if self.is_folder else ""
return hook_obj
diff --git a/allianceauth/notifications/migrations/0006_v5squash.py b/allianceauth/notifications/migrations/0006_v5squash.py
new file mode 100644
index 00000000..68fc7b49
--- /dev/null
+++ b/allianceauth/notifications/migrations/0006_v5squash.py
@@ -0,0 +1,46 @@
+# Generated by Django 5.1.6 on 2025-03-04 01:24
+
+import django.db.models.deletion
+from django.conf import settings
+from django.db import migrations, models
+
+
+def create_permissions(apps, schema_editor) -> None:
+ # Remnant of AAv0
+ User = apps.get_model('auth', 'User')
+ ContentType = apps.get_model('contenttypes', 'ContentType')
+ Permission = apps.get_model('auth', 'Permission')
+ ct = ContentType.objects.get_for_model(User)
+ Permission.objects.get_or_create(codename="logging_notifications", content_type=ct, name="logging_notifications")
+
+
+def reverse(apps, schema_editor) -> None:
+ pass
+
+
+class Migration(migrations.Migration):
+
+ replaces = [('notifications', '0001_initial'), ('notifications', '0002_auto_20160910_1649'), ('notifications', '0003_make_strings_more_stringy'), ('notifications', '0004_performance_tuning'), ('notifications', '0005_fix_level_choices')]
+
+ initial = True
+
+ dependencies = [
+ migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='Notification',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('level', models.CharField(choices=[('danger', 'danger'), ('warning', 'warning'), ('info', 'info'), ('success', 'success')], default='info', max_length=10)),
+ ('title', models.CharField(max_length=254)),
+ ('message', models.TextField()),
+ ('timestamp', models.DateTimeField(auto_now_add=True, db_index=True)),
+ ('viewed', models.BooleanField(db_index=True, default=False)),
+ ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
+ ],
+ options={'permissions': ()},
+ ),
+ migrations.RunPython(create_permissions, reverse)
+ ]
diff --git a/allianceauth/notifications/models.py b/allianceauth/notifications/models.py
index 3e3f6826..4624260e 100644
--- a/allianceauth/notifications/models.py
+++ b/allianceauth/notifications/models.py
@@ -59,15 +59,22 @@ class Notification(models.Model):
objects: ClassVar[NotificationManager] = NotificationManager()
+ class Meta:
+ permissions = (
+ # Intentionally Commented out
+ # AAv0 has these in the Auth_ Content Type
+ # ('logging_notifications', 'logging_notifications')
+ )
+
def __str__(self) -> str:
return f"{self.user}: {self.title}"
- def save(self, *args, **kwargs):
+ def save(self, *args, **kwargs) -> None:
# overriden save to ensure cache is invaidated on very call
super().save(*args, **kwargs)
Notification.objects.invalidate_user_notification_cache(self.user.pk)
- def delete(self, *args, **kwargs):
+ def delete(self, *args, **kwargs) -> None:
# overriden delete to ensure cache is invaidated on very call
super().delete(*args, **kwargs)
Notification.objects.invalidate_user_notification_cache(self.user.pk)
diff --git a/allianceauth/optimer/migrations/0005_v5squash.py b/allianceauth/optimer/migrations/0005_v5squash.py
new file mode 100644
index 00000000..d2312294
--- /dev/null
+++ b/allianceauth/optimer/migrations/0005_v5squash.py
@@ -0,0 +1,67 @@
+# Generated by Django 5.1.6 on 2025-03-04 01:26
+
+import datetime
+
+import django.db.models.deletion
+import django.utils.timezone
+from django.db import migrations, models
+
+
+def create_permissions(apps, schema_editor) -> None:
+ # Remnant of AAv0
+ User = apps.get_model('auth', 'User')
+ ContentType = apps.get_model('contenttypes', 'ContentType')
+ Permission = apps.get_model('auth', 'Permission')
+ ct = ContentType.objects.get_for_model(User)
+ Permission.objects.get_or_create(codename="optimer_management", content_type=ct, name="optimer_management")
+ Permission.objects.get_or_create(codename="optimer_view", content_type=ct, name="optimer_view")
+
+
+def reverse(apps, schema_editor) -> None:
+ pass
+
+
+class Migration(migrations.Migration):
+
+ replaces = [('optimer', '0001_initial'), ('optimer', '0002_auto_20170413_0442'), ('optimer', '0003_make_strings_more_stringy'), ('optimer', '0004_on_delete'), ('optimer', '0005_add_type_and_description')]
+
+ initial = True
+
+ dependencies = [
+ ('eveonline', '0001_initial'),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='OpTimerType',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('type', models.CharField(default='', max_length=254)),
+ ],
+ options={
+ 'ordering': ['type'],
+ 'default_permissions': (),
+ },
+ ),
+ migrations.CreateModel(
+ name='optimer',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('doctrine', models.CharField(default='', max_length=254)),
+ ('system', models.CharField(default='', max_length=254)),
+ ('start', models.DateTimeField(default=datetime.datetime.now)),
+ ('duration', models.CharField(default='', max_length=25)),
+ ('operation_name', models.CharField(default='', max_length=254)),
+ ('fc', models.CharField(default='', max_length=254)),
+ ('post_time', models.DateTimeField(default=django.utils.timezone.now)),
+ ('eve_character', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='eveonline.evecharacter')),
+ ('description', models.TextField(blank=True, default='')),
+ ('type', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='optimer.optimertype')),
+ ],
+ options={
+ 'ordering': ['start'],
+ 'default_permissions': (),
+ },
+ ),
+ migrations.RunPython(create_permissions, reverse)
+ ]
diff --git a/allianceauth/optimer/models.py b/allianceauth/optimer/models.py
index 6c044eae..cc447285 100644
--- a/allianceauth/optimer/models.py
+++ b/allianceauth/optimer/models.py
@@ -7,24 +7,17 @@ from allianceauth.eveonline.models import EveCharacter
class OpTimerType(models.Model):
- """
- Optimer Type
- """
-
type = models.CharField(max_length=254, default="")
-
-
class Meta:
- ordering = ['type']
+ ordering = ["type"]
default_permissions = ()
def __str__(self) -> str:
return self.type
+
class OpTimer(models.Model):
-
-
doctrine = models.CharField(max_length=254, default="")
system = models.CharField(max_length=254, default="")
start = models.DateTimeField(default=datetime.now)
@@ -32,12 +25,19 @@ class OpTimer(models.Model):
operation_name = models.CharField(max_length=254, default="")
fc = models.CharField(max_length=254, default="")
post_time = models.DateTimeField(default=timezone.now)
- eve_character = models.ForeignKey(EveCharacter, null=True,
- on_delete=models.SET_NULL)
+ eve_character = models.ForeignKey(EveCharacter, null=True, on_delete=models.SET_NULL)
description = models.TextField(blank=True, default="")
type = models.ForeignKey(OpTimerType, null=True, on_delete=models.SET_NULL)
+
class Meta:
- ordering = ['start']
+ ordering = ["start"]
default_permissions = ()
+ # Intentionally Commented out
+ # AAv0 has these in the Auth_ Content Type
+ # permissions = (
+ # ('optimer_view', 'optimer_view'),
+ # ('optimer_management', 'optimer_management'),
+ # )
+
def __str__(self) -> str:
return self.operation_name
diff --git a/allianceauth/permissions_tool/models.py b/allianceauth/permissions_tool/models.py
index bce74dc9..19e576fc 100644
--- a/allianceauth/permissions_tool/models.py
+++ b/allianceauth/permissions_tool/models.py
@@ -5,11 +5,10 @@ class PermissionsTool(models.Model):
"""
Dummy model for holding permissions
"""
+
class Meta:
managed = False
- permissions = (
- ('audit_permissions', 'Can audit permissions'),
- )
+ permissions = (("audit_permissions", "Can audit permissions"),)
def __str__(self) -> str:
return f"{self.pk}"
diff --git a/allianceauth/services/migrations/0001_squashed_0003_delete_groupcache.py b/allianceauth/services/migrations/0001_squashed_0003_delete_groupcache.py
index 7c37fc47..8e1033ce 100644
--- a/allianceauth/services/migrations/0001_squashed_0003_delete_groupcache.py
+++ b/allianceauth/services/migrations/0001_squashed_0003_delete_groupcache.py
@@ -6,8 +6,6 @@ from django.db import migrations
class Migration(migrations.Migration):
- replaces = [('services', '0001_initial'), ('services', '0002_auto_20161016_0135'), ('services', '0003_delete_groupcache')]
-
initial = True
dependencies = [
diff --git a/allianceauth/services/migrations/0004_v5squash.py b/allianceauth/services/migrations/0004_v5squash.py
new file mode 100644
index 00000000..be0ef92c
--- /dev/null
+++ b/allianceauth/services/migrations/0004_v5squash.py
@@ -0,0 +1,29 @@
+# Generated by Django 5.1.6 on 2025-03-05 00:12
+
+from django.conf import settings
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ replaces = [('services', '0001_squashed_0003_delete_groupcache'), ('services', '0002_nameformatter'), ('services', '0003_remove_broken_link')]
+
+ initial = True
+
+ dependencies = [
+ migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+ ('authentication', '0025_v5squash'),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='NameFormatConfig',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('service_name', models.CharField(max_length=100)),
+ ('default_to_username', models.BooleanField(default=True, help_text='If a user has no main_character, default to using their Auth username instead.')),
+ ('format', models.CharField(help_text='For information on constructing name formats please see the official documentation, topic "Services Name Formats".', max_length=100)),
+ ('states', models.ManyToManyField(help_text='States to apply this format to. You should only have one formatter for each state for each service.', to='authentication.state')),
+ ],
+ ),
+ ]
diff --git a/allianceauth/services/modules/discord/migrations/0004_v5squash.py b/allianceauth/services/modules/discord/migrations/0004_v5squash.py
new file mode 100644
index 00000000..567e9857
--- /dev/null
+++ b/allianceauth/services/modules/discord/migrations/0004_v5squash.py
@@ -0,0 +1,33 @@
+# Generated by Django 5.1.6 on 2025-03-05 00:18
+
+import django.db.models.deletion
+from django.conf import settings
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ replaces = [('discord', '0001_initial'), ('discord', '0002_service_permissions'), ('discord', '0003_big_overhaul')]
+
+ initial = True
+
+ dependencies = [
+ migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='DiscordUser',
+ fields=[
+ ('user', models.OneToOneField(help_text='Auth user owning this Discord account', on_delete=django.db.models.deletion.CASCADE, primary_key=True, related_name='discord', serialize=False, to=settings.AUTH_USER_MODEL)),
+ ('uid', models.BigIntegerField(db_index=True, help_text="user's ID on Discord")),
+ ('activated', models.DateTimeField(blank=True, default=None, help_text='Date & time this service account was activated', null=True)),
+ ('discriminator', models.CharField(blank=True, default='', help_text="user's discriminator on Discord", max_length=4)),
+ ('username', models.CharField(blank=True, db_index=True, default='', help_text="user's username on Discord", max_length=32)),
+ ],
+ options={
+ 'default_permissions': (),
+ 'permissions': (('access_discord', 'Can access the Discord service'),),
+ },
+ ),
+ ]
diff --git a/allianceauth/services/modules/discord/models.py b/allianceauth/services/modules/discord/models.py
index c46215d6..beba4219 100644
--- a/allianceauth/services/modules/discord/models.py
+++ b/allianceauth/services/modules/discord/models.py
@@ -26,45 +26,29 @@ class DiscordUser(models.Model):
User,
primary_key=True,
on_delete=models.CASCADE,
- related_name='discord',
- help_text='Auth user owning this Discord account'
- )
- uid = models.BigIntegerField(
- db_index=True,
- help_text='user\'s ID on Discord'
+ related_name="discord",
+ help_text="Auth user owning this Discord account",
)
+ uid = models.BigIntegerField(db_index=True, help_text="user's ID on Discord")
username = models.CharField(
- max_length=32,
- default='',
- blank=True,
- db_index=True,
- help_text='user\'s username on Discord'
- )
- discriminator = models.CharField(
- max_length=4,
- default='',
- blank=True,
- help_text='user\'s discriminator on Discord'
+ max_length=32, default="", blank=True, db_index=True, help_text="user's username on Discord"
)
+ discriminator = models.CharField(max_length=4, default="", blank=True, help_text="user's discriminator on Discord")
activated = models.DateTimeField(
- default=None,
- null=True,
- blank=True,
- help_text='Date & time this service account was activated'
+ default=None, null=True, blank=True, help_text="Date & time this service account was activated"
)
objects: ClassVar[DiscordUserManager] = DiscordUserManager()
class Meta:
- permissions = (
- ("access_discord", "Can access the Discord service"),
- )
+ default_permissions = ()
+ permissions = (("access_discord", "Can access the Discord service"),)
- def __str__(self):
- return f'{self.user.username} - {self.uid}'
+ def __str__(self) -> str:
+ return f"{self.user.username} - {self.uid}"
- def __repr__(self):
- return f'{type(self).__name__}(user=\'{self.user}\', uid={self.uid})'
+ def __repr__(self) -> str:
+ return f"{type(self).__name__}(user='{self.user}', uid={self.uid})"
def update_nickname(self, nickname: str = None) -> bool:
"""Update nickname with formatted name of main character
@@ -81,15 +65,11 @@ class DiscordUser(models.Model):
nickname = user_formatted_nick(self.user)
if not nickname:
return False
- success = default_bot_client.modify_guild_member(
- guild_id=DISCORD_GUILD_ID,
- user_id=self.uid,
- nick=nickname
- )
+ success = default_bot_client.modify_guild_member(guild_id=DISCORD_GUILD_ID, user_id=self.uid, nick=nickname)
if success:
- logger.info('Nickname for %s has been updated', self.user)
+ logger.info("Nickname for %s has been updated", self.user)
else:
- logger.warning('Failed to update nickname for %s', self.user)
+ logger.warning("Failed to update nickname for %s", self.user)
return success
def update_groups(self, state_name: str = None) -> bool | None:
@@ -105,27 +85,22 @@ class DiscordUser(models.Model):
- False on error or raises exception
"""
new_roles, is_changed = calculate_roles_for_user(
- user=self.user,
- client=default_bot_client,
- discord_uid=self.uid,
- state_name=state_name
+ user=self.user, client=default_bot_client, discord_uid=self.uid, state_name=state_name
)
if is_changed is None:
- logger.debug('User is not a member of this guild %s', self.user)
+ logger.debug("User is not a member of this guild %s", self.user)
return None
if is_changed:
- logger.debug('Need to update roles for user %s', self.user)
+ logger.debug("Need to update roles for user %s", self.user)
success = default_bot_client.modify_guild_member(
- guild_id=DISCORD_GUILD_ID,
- user_id=self.uid,
- role_ids=list(new_roles.ids())
+ guild_id=DISCORD_GUILD_ID, user_id=self.uid, role_ids=list(new_roles.ids())
)
if success:
- logger.info('Roles for %s have been updated', self.user)
+ logger.info("Roles for %s have been updated", self.user)
else:
- logger.warning('Failed to update roles for %s', self.user)
+ logger.warning("Failed to update roles for %s", self.user)
return success
- logger.info('No need to update roles for user %s', self.user)
+ logger.info("No need to update roles for user %s", self.user)
return True
def update_username(self) -> bool | None:
@@ -136,23 +111,18 @@ class DiscordUser(models.Model):
- True on success
- None if user is no longer a member of the Discord server
"""
- member_info = default_bot_client.guild_member(
- guild_id=DISCORD_GUILD_ID, user_id=self.uid
- )
+ member_info = default_bot_client.guild_member(guild_id=DISCORD_GUILD_ID, user_id=self.uid)
if not member_info:
- logger.warning('%s: User not a guild member', self.user)
+ logger.warning("%s: User not a guild member", self.user)
return None
self.username = member_info.user.username
self.discriminator = member_info.user.discriminator
self.save()
- logger.info('%s: Username has been updated', self.user)
+ logger.info("%s: Username has been updated", self.user)
return True
def delete_user(
- self,
- notify_user: bool = False,
- is_rate_limited: bool = True,
- handle_api_exceptions: bool = False
+ self, notify_user: bool = False, is_rate_limited: bool = True, handle_api_exceptions: bool = False
) -> bool | None:
"""Deletes the Discount user both on the server and locally
@@ -169,37 +139,31 @@ class DiscordUser(models.Model):
try:
_user = self.user
client = create_bot_client(is_rate_limited=is_rate_limited)
- success = client.remove_guild_member(
- guild_id=DISCORD_GUILD_ID, user_id=self.uid
- )
+ success = client.remove_guild_member(guild_id=DISCORD_GUILD_ID, user_id=self.uid)
if success is not False:
deleted_count, _ = self.delete()
if deleted_count > 0:
if notify_user:
notify(
user=_user,
- title=gettext_lazy('Discord Account Disabled'),
+ title=gettext_lazy("Discord Account Disabled"),
message=gettext_lazy(
- 'Your Discord account was disabled automatically '
- 'by Auth. If you think this was a mistake, '
- 'please contact an admin.'
+ "Your Discord account was disabled automatically "
+ "by Auth. If you think this was a mistake, "
+ "please contact an admin."
),
- level='warning'
+ level="warning",
)
- logger.info('Account for user %s was deleted.', _user)
+ logger.info("Account for user %s was deleted.", _user)
return True
- logger.debug('Account for user %s was already deleted.', _user)
+ logger.debug("Account for user %s was already deleted.", _user)
return None
- logger.warning(
- 'Failed to remove user %s from the Discord server', _user
- )
+ logger.warning("Failed to remove user %s from the Discord server", _user)
return False
except (HTTPError, ConnectionError, DiscordApiBackoff) as ex:
if handle_api_exceptions:
- logger.exception(
- 'Failed to remove user %s from Discord server: %s',self.user, ex
- )
+ logger.exception("Failed to remove user %s from Discord server: %s", self.user, ex)
return False
raise ex
diff --git a/allianceauth/services/modules/discourse/manager.py b/allianceauth/services/modules/discourse/manager.py
index f6756788..0c4482c7 100644
--- a/allianceauth/services/modules/discourse/manager.py
+++ b/allianceauth/services/modules/discourse/manager.py
@@ -17,7 +17,7 @@ class DiscourseError(Exception):
self.endpoint = endpoint
self.errors = errors
- def __str__(self):
+ def __str__(self) -> str:
return f"API execution failed.\nErrors: {self.errors}\nEndpoint: {self.endpoint}"
diff --git a/allianceauth/services/modules/discourse/migrations/0003_v5squash.py b/allianceauth/services/modules/discourse/migrations/0003_v5squash.py
new file mode 100644
index 00000000..c36f4bc2
--- /dev/null
+++ b/allianceauth/services/modules/discourse/migrations/0003_v5squash.py
@@ -0,0 +1,31 @@
+# Generated by Django 5.1.6 on 2025-03-05 00:23
+
+import django.db.migrations.operations.special
+import django.db.models.deletion
+from django.conf import settings
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ replaces = [('discourse', '0001_initial'), ('discourse', '0002_service_permissions')]
+
+ initial = True
+
+ dependencies = [
+ migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='DiscourseUser',
+ fields=[
+ ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, primary_key=True, related_name='discourse', serialize=False, to=settings.AUTH_USER_MODEL)),
+ ('enabled', models.BooleanField()),
+ ],
+ options={
+ 'default_permissions': (),
+ 'permissions': (('access_discourse', 'Can access the Discourse service'),),
+ },
+ ),
+ ]
diff --git a/allianceauth/services/modules/discourse/models.py b/allianceauth/services/modules/discourse/models.py
index 395d6931..3511259e 100644
--- a/allianceauth/services/modules/discourse/models.py
+++ b/allianceauth/services/modules/discourse/models.py
@@ -3,18 +3,12 @@ from django.db import models
class DiscourseUser(models.Model):
- user = models.OneToOneField(User,
- primary_key=True,
- on_delete=models.CASCADE,
- related_name='discourse')
+ user = models.OneToOneField(User, primary_key=True, on_delete=models.CASCADE, related_name="discourse")
enabled = models.BooleanField()
-
-
class Meta:
- permissions = (
- ("access_discourse", "Can access the Discourse service"),
- )
+ default_permissions = ()
+ permissions = (("access_discourse", "Can access the Discourse service"),)
def __str__(self) -> str:
return self.user.username
diff --git a/allianceauth/services/modules/example/models.py b/allianceauth/services/modules/example/models.py
index c8c18dd1..b64dac8b 100644
--- a/allianceauth/services/modules/example/models.py
+++ b/allianceauth/services/modules/example/models.py
@@ -9,5 +9,5 @@ class ExampleUser(models.Model):
related_name='example')
username = models.CharField(max_length=254)
- def __str__(self):
+ def __str__(self) -> str:
return self.username
diff --git a/allianceauth/services/modules/ips4/migrations/0003_v5squash.py b/allianceauth/services/modules/ips4/migrations/0003_v5squash.py
new file mode 100644
index 00000000..2467994a
--- /dev/null
+++ b/allianceauth/services/modules/ips4/migrations/0003_v5squash.py
@@ -0,0 +1,32 @@
+# Generated by Django 5.1.6 on 2025-03-05 00:24
+
+import django.db.migrations.operations.special
+import django.db.models.deletion
+from django.conf import settings
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ replaces = [('ips4', '0001_initial'), ('ips4', '0002_service_permissions')]
+
+ initial = True
+
+ dependencies = [
+ migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='Ips4User',
+ fields=[
+ ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, primary_key=True, related_name='ips4', serialize=False, to=settings.AUTH_USER_MODEL)),
+ ('username', models.CharField(max_length=254)),
+ ('id', models.CharField(max_length=254)),
+ ],
+ options={
+ 'default_permissions': (),
+ 'permissions': (('access_ips4', 'Can access the IPS4 service'),),
+ },
+ ),
+ ]
diff --git a/allianceauth/services/modules/ips4/models.py b/allianceauth/services/modules/ips4/models.py
index 545a107c..2d17a050 100644
--- a/allianceauth/services/modules/ips4/models.py
+++ b/allianceauth/services/modules/ips4/models.py
@@ -3,18 +3,13 @@ from django.db import models
class Ips4User(models.Model):
- user = models.OneToOneField(User,
- primary_key=True,
- on_delete=models.CASCADE,
- related_name='ips4')
+ user = models.OneToOneField(User, primary_key=True, on_delete=models.CASCADE, related_name="ips4")
username = models.CharField(max_length=254)
id = models.CharField(max_length=254)
-
class Meta:
- permissions = (
- ("access_ips4", "Can access the IPS4 service"),
- )
+ default_permissions = ()
+ permissions = (("access_ips4", "Can access the IPS4 service"),)
- def __str__(self):
+ def __str__(self) -> str:
return self.username
diff --git a/allianceauth/services/modules/mumble/migrations/0001_initial.py b/allianceauth/services/modules/mumble/migrations/0001_initial.py
deleted file mode 100644
index ee74dfa1..00000000
--- a/allianceauth/services/modules/mumble/migrations/0001_initial.py
+++ /dev/null
@@ -1,26 +0,0 @@
-# Generated by Django 1.10.2 on 2016-12-12 00:58
-
-from django.db import migrations, models
-
-
-class Migration(migrations.Migration):
-
- initial = True
-
- dependencies = [
- ]
-
- operations = [
- migrations.CreateModel(
- name='MumbleUser',
- fields=[
- ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
- ('username', models.CharField(max_length=254, unique=True)),
- ('pwhash', models.CharField(max_length=40)),
- ('groups', models.TextField(blank=True, null=True)),
- ],
- options={
- 'db_table': 'services_mumbleuser',
- },
- ),
- ]
diff --git a/allianceauth/services/modules/mumble/migrations/0001_squashed_0011_auto_20201011_1009.py b/allianceauth/services/modules/mumble/migrations/0001_squashed_0011_auto_20201011_1009.py
index 6b6d96f6..8609f8a9 100644
--- a/allianceauth/services/modules/mumble/migrations/0001_squashed_0011_auto_20201011_1009.py
+++ b/allianceauth/services/modules/mumble/migrations/0001_squashed_0011_auto_20201011_1009.py
@@ -8,8 +8,6 @@ from django.db import migrations, models
class Migration(migrations.Migration):
- replaces = [('mumble', '0001_initial'), ('mumble', '0002_auto_20161212_0100'), ('mumble', '0003_mumbleuser_user'), ('mumble', '0004_auto_20161214_1024'), ('mumble', '0005_mumbleuser_hashfn'), ('mumble', '0006_service_permissions'), ('mumble', '0007_not_null_user'), ('mumble', '0008_mumbleuser_display_name'), ('mumble', '0009_set_mumble_dissplay_names'), ('mumble', '0010_mumbleuser_certhash'), ('mumble', '0011_auto_20201011_1009')]
-
initial = True
dependencies = [
@@ -25,13 +23,6 @@ class Migration(migrations.Migration):
('pwhash', models.CharField(max_length=40)),
('groups', models.TextField(blank=True, null=True)),
],
- options={
- 'db_table': 'services_mumbleuser',
- },
- ),
- migrations.AlterModelTable(
- name='mumbleuser',
- table=None,
),
migrations.AddField(
model_name='mumbleuser',
diff --git a/allianceauth/services/modules/mumble/migrations/0002_auto_20161212_0100.py b/allianceauth/services/modules/mumble/migrations/0002_auto_20161212_0100.py
deleted file mode 100644
index 2a253099..00000000
--- a/allianceauth/services/modules/mumble/migrations/0002_auto_20161212_0100.py
+++ /dev/null
@@ -1,17 +0,0 @@
-# Generated by Django 1.10.2 on 2016-12-12 01:00
-
-from django.db import migrations
-
-
-class Migration(migrations.Migration):
-
- dependencies = [
- ('mumble', '0001_initial'),
- ]
-
- operations = [
- migrations.AlterModelTable(
- name='mumbleuser',
- table=None,
- ),
- ]
diff --git a/allianceauth/services/modules/mumble/migrations/0003_mumbleuser_user.py b/allianceauth/services/modules/mumble/migrations/0003_mumbleuser_user.py
deleted file mode 100644
index f5f98351..00000000
--- a/allianceauth/services/modules/mumble/migrations/0003_mumbleuser_user.py
+++ /dev/null
@@ -1,21 +0,0 @@
-# Generated by Django 1.10.2 on 2016-12-12 03:31
-
-import django.db.models.deletion
-from django.conf import settings
-from django.db import migrations, models
-
-
-class Migration(migrations.Migration):
-
- dependencies = [
- migrations.swappable_dependency(settings.AUTH_USER_MODEL),
- ('mumble', '0002_auto_20161212_0100'),
- ]
-
- operations = [
- migrations.AddField(
- model_name='mumbleuser',
- name='user',
- field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='mumble', to=settings.AUTH_USER_MODEL),
- ),
- ]
diff --git a/allianceauth/services/modules/mumble/migrations/0004_auto_20161214_1024.py b/allianceauth/services/modules/mumble/migrations/0004_auto_20161214_1024.py
deleted file mode 100644
index 20ec8679..00000000
--- a/allianceauth/services/modules/mumble/migrations/0004_auto_20161214_1024.py
+++ /dev/null
@@ -1,20 +0,0 @@
-# Generated by Django 1.10.4 on 2016-12-14 10:24
-
-import django.db.models.deletion
-from django.conf import settings
-from django.db import migrations, models
-
-
-class Migration(migrations.Migration):
-
- dependencies = [
- ('mumble', '0003_mumbleuser_user'),
- ]
-
- operations = [
- migrations.AlterField(
- model_name='mumbleuser',
- name='user',
- field=models.OneToOneField(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='mumble', to=settings.AUTH_USER_MODEL),
- ),
- ]
diff --git a/allianceauth/services/modules/mumble/migrations/0005_mumbleuser_hashfn.py b/allianceauth/services/modules/mumble/migrations/0005_mumbleuser_hashfn.py
deleted file mode 100644
index 78fc8657..00000000
--- a/allianceauth/services/modules/mumble/migrations/0005_mumbleuser_hashfn.py
+++ /dev/null
@@ -1,23 +0,0 @@
-# Generated by Django 1.10.4 on 2017-01-23 10:28
-
-from django.db import migrations, models
-
-
-class Migration(migrations.Migration):
-
- dependencies = [
- ('mumble', '0004_auto_20161214_1024'),
- ]
-
- operations = [
- migrations.AddField(
- model_name='mumbleuser',
- name='hashfn',
- field=models.CharField(default='sha1', max_length=20),
- ),
- migrations.AlterField(
- model_name='mumbleuser',
- name='pwhash',
- field=models.CharField(max_length=80),
- ),
- ]
diff --git a/allianceauth/services/modules/mumble/migrations/0006_service_permissions.py b/allianceauth/services/modules/mumble/migrations/0006_service_permissions.py
deleted file mode 100644
index 171915c1..00000000
--- a/allianceauth/services/modules/mumble/migrations/0006_service_permissions.py
+++ /dev/null
@@ -1,59 +0,0 @@
-# Generated by Django 1.10.5 on 2017-02-02 05:59
-
-import logging
-
-from django.conf import settings
-from django.contrib.auth.management import create_permissions
-from django.core.exceptions import ObjectDoesNotExist
-from django.db import migrations
-
-logger = logging.getLogger(__name__)
-
-
-def migrate_service_enabled(apps, schema_editor):
- for app_config in apps.get_app_configs():
- app_config.models_module = True
- create_permissions(app_config, apps=apps, verbosity=0)
- app_config.models_module = None
-
- Group = apps.get_model("auth", "Group")
- Permission = apps.get_model("auth", "Permission")
- MumbleUser = apps.get_model("mumble", "MumbleUser")
-
- perm = Permission.objects.get(codename='access_mumble')
-
- member_group_name = getattr(settings, 'DEFAULT_AUTH_GROUP', 'Member')
- blue_group_name = getattr(settings, 'DEFAULT_BLUE_GROUP', 'Blue')
-
- # Migrate members
- if MumbleUser.objects.filter(user__groups__name=member_group_name).exists() or \
- getattr(settings, 'ENABLE_AUTH_MUMBLE', False):
- try:
- group = Group.objects.get(name=member_group_name)
- group.permissions.add(perm)
- except ObjectDoesNotExist:
- logger.warning('Failed to migrate ENABLE_AUTH_MUMBLE setting')
-
- # Migrate blues
- if MumbleUser.objects.filter(user__groups__name=blue_group_name).exists() or \
- getattr(settings, 'ENABLE_BLUE_MUMBLE', False):
- try:
- group = Group.objects.get(name=blue_group_name)
- group.permissions.add(perm)
- except ObjectDoesNotExist:
- logger.warning('Failed to migrate ENABLE_BLUE_MUMBLE setting')
-
-
-class Migration(migrations.Migration):
-
- dependencies = [
- ('mumble', '0005_mumbleuser_hashfn'),
- ]
-
- operations = [
- migrations.AlterModelOptions(
- name='mumbleuser',
- options={'permissions': (('access_mumble', 'Can access the Mumble service'),)},
- ),
- migrations.RunPython(migrate_service_enabled, migrations.RunPython.noop),
- ]
diff --git a/allianceauth/services/modules/mumble/migrations/0007_not_null_user.py b/allianceauth/services/modules/mumble/migrations/0007_not_null_user.py
deleted file mode 100644
index 14d4bd03..00000000
--- a/allianceauth/services/modules/mumble/migrations/0007_not_null_user.py
+++ /dev/null
@@ -1,24 +0,0 @@
-# Generated by Django 1.11.6 on 2017-10-09 09:19
-
-import django.db.models.deletion
-from django.conf import settings
-from django.db import migrations, models
-
-
-class Migration(migrations.Migration):
-
- dependencies = [
- ('mumble', '0006_service_permissions'),
- ]
-
- operations = [
- migrations.RemoveField(
- model_name='mumbleuser',
- name='id',
- ),
- migrations.AlterField(
- model_name='mumbleuser',
- name='user',
- field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, primary_key=True, related_name='mumble', serialize=False, to=settings.AUTH_USER_MODEL),
- ),
- ]
diff --git a/allianceauth/services/modules/mumble/migrations/0008_mumbleuser_display_name.py b/allianceauth/services/modules/mumble/migrations/0008_mumbleuser_display_name.py
deleted file mode 100644
index 5d89878e..00000000
--- a/allianceauth/services/modules/mumble/migrations/0008_mumbleuser_display_name.py
+++ /dev/null
@@ -1,18 +0,0 @@
-# Generated by Django 2.2.9 on 2020-03-16 07:49
-
-from django.db import migrations, models
-
-
-class Migration(migrations.Migration):
-
- dependencies = [
- ('mumble', '0007_not_null_user'),
- ]
-
- operations = [
- migrations.AddField(
- model_name='mumbleuser',
- name='display_name',
- field=models.CharField(max_length=254, null=True),
- )
- ]
diff --git a/allianceauth/services/modules/mumble/migrations/0009_set_mumble_dissplay_names.py b/allianceauth/services/modules/mumble/migrations/0009_set_mumble_dissplay_names.py
deleted file mode 100644
index 4048f61d..00000000
--- a/allianceauth/services/modules/mumble/migrations/0009_set_mumble_dissplay_names.py
+++ /dev/null
@@ -1,40 +0,0 @@
-from django.db import migrations, models
-
-from allianceauth.services.hooks import NameFormatter
-
-from ..auth_hooks import MumbleService
-
-
-def fwd_func(apps, schema_editor):
- MumbleUser = apps.get_model("mumble", "MumbleUser")
- db_alias = schema_editor.connection.alias
- all_users = MumbleUser.objects.using(db_alias).all()
- for user in all_users:
- display_name = NameFormatter(MumbleService(), user.user).format_name()
- user.display_name = display_name
- user.save()
-
-def rev_func(apps, schema_editor):
- MumbleUser = apps.get_model("mumble", "MumbleUser")
- db_alias = schema_editor.connection.alias
- all_users = MumbleUser.objects.using(db_alias).all()
- for user in all_users:
- user.display_name = None
- user.save()
-
-
-class Migration(migrations.Migration):
-
- dependencies = [
- ('mumble', '0008_mumbleuser_display_name'),
- ]
-
- operations = [
- migrations.RunPython(fwd_func, rev_func),
- migrations.AlterField(
- model_name='mumbleuser',
- name='display_name',
- field=models.CharField(max_length=254, unique=True),
- preserve_default=False,
- ),
- ]
diff --git a/allianceauth/services/modules/mumble/migrations/0010_mumbleuser_certhash.py b/allianceauth/services/modules/mumble/migrations/0010_mumbleuser_certhash.py
deleted file mode 100644
index 00237748..00000000
--- a/allianceauth/services/modules/mumble/migrations/0010_mumbleuser_certhash.py
+++ /dev/null
@@ -1,18 +0,0 @@
-# Generated by Django 2.2.11 on 2020-05-22 13:02
-
-from django.db import migrations, models
-
-
-class Migration(migrations.Migration):
-
- dependencies = [
- ('mumble', '0009_set_mumble_dissplay_names'),
- ]
-
- operations = [
- migrations.AddField(
- model_name='mumbleuser',
- name='certhash',
- field=models.CharField(blank=True, editable=False, help_text='Hash of Mumble client certificate as presented when user authenticates', max_length=254, null=True, verbose_name='Certificate Hash'),
- ),
- ]
diff --git a/allianceauth/services/modules/mumble/migrations/0011_auto_20201011_1009.py b/allianceauth/services/modules/mumble/migrations/0011_auto_20201011_1009.py
deleted file mode 100644
index 1c166b56..00000000
--- a/allianceauth/services/modules/mumble/migrations/0011_auto_20201011_1009.py
+++ /dev/null
@@ -1,18 +0,0 @@
-# Generated by Django 3.1.2 on 2020-10-11 10:09
-
-from django.db import migrations, models
-
-
-class Migration(migrations.Migration):
-
- dependencies = [
- ('mumble', '0010_mumbleuser_certhash'),
- ]
-
- operations = [
- migrations.AlterField(
- model_name='mumbleuser',
- name='pwhash',
- field=models.CharField(max_length=90),
- ),
- ]
diff --git a/allianceauth/services/modules/mumble/migrations/0014_alter_mumbleuser_certhash_alter_mumbleuser_groups_and_more.py b/allianceauth/services/modules/mumble/migrations/0014_alter_mumbleuser_certhash_alter_mumbleuser_groups_and_more.py
new file mode 100644
index 00000000..b8d20e58
--- /dev/null
+++ b/allianceauth/services/modules/mumble/migrations/0014_alter_mumbleuser_certhash_alter_mumbleuser_groups_and_more.py
@@ -0,0 +1,28 @@
+# Generated by Django 5.1.6 on 2025-03-05 00:44
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('mumble', '0013_connection_history'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='mumbleuser',
+ name='certhash',
+ field=models.CharField(blank=True, default='', editable=False, help_text='Hash of Mumble client certificate as presented when user authenticates', max_length=254, verbose_name='Certificate Hash'),
+ ),
+ migrations.AlterField(
+ model_name='mumbleuser',
+ name='groups',
+ field=models.TextField(blank=True, default=''),
+ ),
+ migrations.AlterField(
+ model_name='mumbleuser',
+ name='release',
+ field=models.TextField(blank=True, default='', editable=False, help_text='Client release. For official releases, this equals the version. For snapshots and git compiles, this will be something else.', max_length=254, verbose_name='Mumble Release'),
+ ),
+ ]
diff --git a/allianceauth/services/modules/mumble/migrations/0015_v5squash.py b/allianceauth/services/modules/mumble/migrations/0015_v5squash.py
new file mode 100644
index 00000000..477f2de1
--- /dev/null
+++ b/allianceauth/services/modules/mumble/migrations/0015_v5squash.py
@@ -0,0 +1,41 @@
+# Generated by Django 5.1.6 on 2025-03-05 00:46
+
+import django.db.models.deletion
+from django.conf import settings
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ replaces = [('mumble', '0001_squashed_0011_auto_20201011_1009'), ('mumble', '0012_mumble_client_info'), ('mumble', '0013_connection_history'), ('mumble', '0014_alter_mumbleuser_certhash_alter_mumbleuser_groups_and_more')]
+
+ initial = True
+
+ dependencies = [
+ ('auth', '__first__'),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='MumbleUser',
+ fields=[
+ ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, primary_key=True, related_name='mumble', serialize=False, to=settings.AUTH_USER_MODEL)),
+ ('username', models.CharField(max_length=254, unique=True)),
+ ('pwhash', models.CharField(max_length=90)),
+ ('groups', models.TextField(blank=True, default='')),
+ ('hashfn', models.CharField(default='sha1', max_length=20)),
+ ('display_name', models.CharField(max_length=254, unique=True)),
+ ('certhash', models.CharField(blank=True, default='', editable=False, help_text='Hash of Mumble client certificate as presented when user authenticates', max_length=254, verbose_name='Certificate Hash')),
+ ('last_connect', models.DateTimeField(blank=True, editable=False, help_text='Timestamp of the users Last Connection to Mumble', max_length=254, null=True, verbose_name='Last Connection')),
+ ('last_disconnect', models.DateTimeField(blank=True, editable=False, help_text='Timestamp of the users Last Disconnection to Mumble', max_length=254, null=True, verbose_name='Last Disconnection')),
+ ('release', models.TextField(blank=True, default='', editable=False, help_text='Client release. For official releases, this equals the version. For snapshots and git compiles, this will be something else.', max_length=254, verbose_name='Mumble Release')),
+ ('version', models.IntegerField(blank=True, editable=False, help_text='Client version. Major version in upper 16 bits, followed by 8 bits of minor version and 8 bits of patchlevel. Version 1.2.3 = 0x010203.', null=True, verbose_name='Mumble Version')),
+ ],
+ options={
+ 'default_permissions': (),
+ 'permissions': (
+ ('access_mumble', 'Can access the Mumble service'),
+ ('view_connection_history', 'Can access the connection history of the Mumble service')),
+ },
+ ),
+ ]
diff --git a/allianceauth/services/modules/mumble/models.py b/allianceauth/services/modules/mumble/models.py
index c313c789..87179b77 100644
--- a/allianceauth/services/modules/mumble/models.py
+++ b/allianceauth/services/modules/mumble/models.py
@@ -14,16 +14,17 @@ logger = logging.getLogger(__name__)
class MumbleManager(models.Manager):
- HASH_FN = 'bcrypt-sha256'
+ HASH_FN = "bcrypt-sha256"
@staticmethod
- def get_display_name(user):
+ def get_display_name(user) -> str:
from .auth_hooks import MumbleService
+
return NameFormatter(MumbleService(), user).format_name()
@staticmethod
def get_username(user):
- return user.profile.main_character.character_name # main character as the user.username may be incorect
+ return user.profile.main_character.character_name # main character as the user.username may be incorrect
@staticmethod
def sanitise_username(username):
@@ -31,11 +32,11 @@ class MumbleManager(models.Manager):
@staticmethod
def generate_random_pass():
- return ''.join([random.choice(string.ascii_letters + string.digits) for n in range(16)])
+ return "".join([random.choice(string.ascii_letters + string.digits) for n in range(16)])
@staticmethod
def gen_pwhash(password):
- return bcrypt_sha256.encrypt(password.encode('utf-8'))
+ return bcrypt_sha256.encrypt(password.encode("utf-8"))
def create(self, user):
try:
@@ -45,58 +46,54 @@ class MumbleManager(models.Manager):
display_name = self.get_display_name(user)
password = self.generate_random_pass()
pwhash = self.gen_pwhash(password)
- logger.debug(f"Proceeding with mumble user creation: clean username {username_clean}, pwhash starts with {pwhash[0:5]}")
+ logger.debug(
+ f"Proceeding with mumble user creation: clean username {username_clean}, pwhash starts with {pwhash[0:5]}"
+ )
logger.info(f"Creating mumble user {username_clean}")
- result = super().create(user=user, username=username_clean,
- pwhash=pwhash, hashfn=self.HASH_FN,
- display_name=display_name)
+ result = super().create(
+ user=user, username=username_clean, pwhash=pwhash, hashfn=self.HASH_FN, display_name=display_name
+ )
result.update_groups()
- result.credentials.update({'username': result.username, 'password': password})
+ result.credentials.update({"username": result.username, "password": password})
return result
except AttributeError: # No Main or similar errors
return False
return False
- def user_exists(self, username):
+ def user_exists(self, username) -> bool:
return self.filter(username=username).exists()
class MumbleUser(AbstractServiceModel):
- user = models.OneToOneField(
- 'auth.User',
- primary_key=True,
- on_delete=models.CASCADE,
- related_name='mumble'
- )
+ user = models.OneToOneField("auth.User", primary_key=True, on_delete=models.CASCADE, related_name="mumble")
username = models.CharField(max_length=254, unique=True)
pwhash = models.CharField(max_length=90)
- hashfn = models.CharField(max_length=20, default='sha1')
- groups = models.TextField(blank=True)
+ hashfn = models.CharField(max_length=20, default="sha1")
+ groups = models.TextField(blank=True, default="")
certhash = models.CharField(
verbose_name="Certificate Hash",
max_length=254,
blank=True,
+ default="",
editable=False,
- help_text="Hash of Mumble client certificate as presented when user authenticates"
- )
- display_name = models.CharField(
- max_length=254,
- unique=True
+ help_text="Hash of Mumble client certificate as presented when user authenticates",
)
+ display_name = models.CharField(max_length=254, unique=True)
release = models.TextField(
verbose_name="Mumble Release",
max_length=254,
blank=True,
editable=False,
- help_text="Client release. For official releases, this equals the version. For snapshots and git compiles, this will be something else."
+ default="",
+ help_text="Client release. For official releases, this equals the version. For snapshots and git compiles, this will be something else.",
)
version = models.IntegerField(
verbose_name="Mumble Version",
blank=True,
null=True,
editable=False,
- help_text="Client version. Major version in upper 16 bits, followed by 8 bits of minor version and 8 bits of patchlevel. Version 1.2.3 = 0x010203."
+ help_text="Client version. Major version in upper 16 bits, followed by 8 bits of minor version and 8 bits of patchlevel. Version 1.2.3 = 0x010203.",
)
last_connect = models.DateTimeField(
verbose_name="Last Connection",
@@ -104,7 +101,7 @@ class MumbleUser(AbstractServiceModel):
blank=True,
null=True,
editable=False,
- help_text="Timestamp of the users Last Connection to Mumble"
+ help_text="Timestamp of the users Last Connection to Mumble",
)
last_disconnect = models.DateTimeField(
verbose_name="Last Disconnection",
@@ -112,15 +109,15 @@ class MumbleUser(AbstractServiceModel):
blank=True,
null=True,
editable=False,
- help_text="Timestamp of the users Last Disconnection to Mumble"
+ help_text="Timestamp of the users Last Disconnection to Mumble",
)
objects: ClassVar[MumbleManager] = MumbleManager()
- def __str__(self):
+ def __str__(self) -> str:
return self.username
- def update_password(self, password=None):
+ def update_password(self, password=None) -> None:
init_password = password
logger.debug("Updating mumble user %s password.")
if not password:
@@ -131,18 +128,18 @@ class MumbleUser(AbstractServiceModel):
self.hashfn = MumbleManager.HASH_FN
self.save()
if init_password is None:
- self.credentials.update({'username': self.username, 'password': password})
+ self.credentials.update({"username": self.username, "password": password})
- def reset_password(self):
+ def reset_password(self) -> None:
self.update_password()
- def update_groups(self, groups: Group=None):
+ def update_groups(self, groups: Group = None):
if groups is None:
groups = self.user.groups.all()
groups_str = [self.user.profile.state.name]
for group in groups:
groups_str.append(str(group.name))
- safe_groups = ','.join({g.replace(' ', '-') for g in groups_str})
+ safe_groups = ",".join({g.replace(" ", "-") for g in groups_str})
logger.info(f"Updating mumble user {self.user} groups to {safe_groups}")
self.groups = safe_groups
self.save()
@@ -155,6 +152,7 @@ class MumbleUser(AbstractServiceModel):
return True
class Meta:
+ default_permissions = ()
permissions = (
("access_mumble", "Can access the Mumble service"),
("view_connection_history", "Can access the connection history of the Mumble service"),
diff --git a/allianceauth/services/modules/openfire/migrations/0003_v5squash.py b/allianceauth/services/modules/openfire/migrations/0003_v5squash.py
new file mode 100644
index 00000000..4b1442e5
--- /dev/null
+++ b/allianceauth/services/modules/openfire/migrations/0003_v5squash.py
@@ -0,0 +1,46 @@
+# Generated by Django 5.1.6 on 2025-03-05 00:48
+
+import django.db.migrations.operations.special
+import django.db.models.deletion
+from django.conf import settings
+from django.db import migrations, models
+
+
+def create_permissions(apps, schema_editor) -> None:
+ # Remnant of AAv0
+ User = apps.get_model('auth', 'User')
+ ContentType = apps.get_model('contenttypes', 'ContentType')
+ Permission = apps.get_model('auth', 'Permission')
+ ct = ContentType.objects.get_for_model(User)
+ Permission.objects.get_or_create(codename="jabber_broadcast", content_type=ct, name="jabber_broadcast")
+ Permission.objects.get_or_create(codename="jabber_broadcast_all", content_type=ct, name="jabber_broadcast_all")
+
+
+def reverse(apps, schema_editor) -> None:
+ pass
+
+
+class Migration(migrations.Migration):
+
+ replaces = [('openfire', '0001_initial'), ('openfire', '0002_service_permissions')]
+
+ initial = True
+
+ dependencies = [
+ migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='OpenfireUser',
+ fields=[
+ ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, primary_key=True, related_name='openfire', serialize=False, to=settings.AUTH_USER_MODEL)),
+ ('username', models.CharField(max_length=254)),
+ ],
+ options={
+ 'default_permissions': (),
+ 'permissions': (('access_openfire', 'Can access the Openfire service'),),
+ },
+ ),
+ migrations.RunPython(create_permissions, reverse)
+ ]
diff --git a/allianceauth/services/modules/openfire/models.py b/allianceauth/services/modules/openfire/models.py
index 672b9cb8..d676a225 100644
--- a/allianceauth/services/modules/openfire/models.py
+++ b/allianceauth/services/modules/openfire/models.py
@@ -2,17 +2,18 @@ from django.db import models
class OpenfireUser(models.Model):
- user = models.OneToOneField('auth.User',
- primary_key=True,
- on_delete=models.CASCADE,
- related_name='openfire')
+ user = models.OneToOneField("auth.User", primary_key=True, on_delete=models.CASCADE, related_name="openfire")
username = models.CharField(max_length=254)
-
-
class Meta:
+ default_permissions = ()
permissions = (
("access_openfire", "Can access the Openfire service"),
+ # Intentionally Commented out
+ # AAv0 has these in the Auth_ Content Type
+ # ('jabber_broadcast', 'jabber_broadcast'),
+ # ('jabber_broadcast_all', 'jabber_broadcast_all'),
)
- def __str__(self):
+
+ def __str__(self) -> str:
return self.username
diff --git a/allianceauth/services/modules/phpbb3/migrations/0003_v5squash.py b/allianceauth/services/modules/phpbb3/migrations/0003_v5squash.py
new file mode 100644
index 00000000..2d463237
--- /dev/null
+++ b/allianceauth/services/modules/phpbb3/migrations/0003_v5squash.py
@@ -0,0 +1,31 @@
+# Generated by Django 5.1.6 on 2025-03-05 00:50
+
+import django.db.migrations.operations.special
+import django.db.models.deletion
+from django.conf import settings
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ replaces = [('phpbb3', '0001_initial'), ('phpbb3', '0002_service_permissions')]
+
+ initial = True
+
+ dependencies = [
+ migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='Phpbb3User',
+ fields=[
+ ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, primary_key=True, related_name='phpbb3', serialize=False, to=settings.AUTH_USER_MODEL)),
+ ('username', models.CharField(max_length=254)),
+ ],
+ options={
+ 'default_permissions': (),
+ 'permissions': (('access_phpbb3', 'Can access the phpBB3 service'),),
+ },
+ ),
+ ]
diff --git a/allianceauth/services/modules/phpbb3/models.py b/allianceauth/services/modules/phpbb3/models.py
index 0d9d1d1c..57a32ae0 100644
--- a/allianceauth/services/modules/phpbb3/models.py
+++ b/allianceauth/services/modules/phpbb3/models.py
@@ -2,16 +2,12 @@ from django.db import models
class Phpbb3User(models.Model):
- user = models.OneToOneField('auth.User',
- primary_key=True,
- on_delete=models.CASCADE,
- related_name='phpbb3')
+ user = models.OneToOneField("auth.User", primary_key=True, on_delete=models.CASCADE, related_name="phpbb3")
username = models.CharField(max_length=254)
class Meta:
- permissions = (
- ("access_phpbb3", "Can access the phpBB3 service"),
- )
+ default_permissions = ()
+ permissions = (("access_phpbb3", "Can access the phpBB3 service"),)
def __str__(self) -> str:
return self.username
diff --git a/allianceauth/services/modules/smf/migrations/0004_v5squash.py b/allianceauth/services/modules/smf/migrations/0004_v5squash.py
new file mode 100644
index 00000000..0c06da52
--- /dev/null
+++ b/allianceauth/services/modules/smf/migrations/0004_v5squash.py
@@ -0,0 +1,31 @@
+# Generated by Django 5.1.6 on 2025-03-05 00:51
+
+import django.db.migrations.operations.special
+import django.db.models.deletion
+from django.conf import settings
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ replaces = [('smf', '0001_initial'), ('smf', '0002_service_permissions'), ('smf', '0003_set_smf_displayed_names')]
+
+ initial = True
+
+ dependencies = [
+ migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='SmfUser',
+ fields=[
+ ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, primary_key=True, related_name='smf', serialize=False, to=settings.AUTH_USER_MODEL)),
+ ('username', models.CharField(max_length=254)),
+ ],
+ options={
+ 'default_permissions': (),
+ 'permissions': (('access_smf', 'Can access the SMF service'),),
+ },
+ ),
+ ]
diff --git a/allianceauth/services/modules/smf/models.py b/allianceauth/services/modules/smf/models.py
index f8cd257e..a8ed1ec8 100644
--- a/allianceauth/services/modules/smf/models.py
+++ b/allianceauth/services/modules/smf/models.py
@@ -2,16 +2,12 @@ from django.db import models
class SmfUser(models.Model):
- user = models.OneToOneField('auth.User',
- primary_key=True,
- on_delete=models.CASCADE,
- related_name='smf')
+ user = models.OneToOneField("auth.User", primary_key=True, on_delete=models.CASCADE, related_name="smf")
username = models.CharField(max_length=254)
class Meta:
- permissions = (
- ("access_smf", "Can access the SMF service"),
- )
+ default_permissions = ()
+ permissions = (("access_smf", "Can access the SMF service"),)
def __str__(self) -> str:
return self.username
diff --git a/allianceauth/services/modules/teamspeak3/migrations/0006_v5squash.py b/allianceauth/services/modules/teamspeak3/migrations/0006_v5squash.py
new file mode 100644
index 00000000..25cfad50
--- /dev/null
+++ b/allianceauth/services/modules/teamspeak3/migrations/0006_v5squash.py
@@ -0,0 +1,73 @@
+# Generated by Django 5.1.6 on 2025-03-05 00:52
+
+import django.db.migrations.operations.special
+import django.db.models.deletion
+from django.conf import settings
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ replaces = [('teamspeak3', '0001_initial'), ('teamspeak3', '0002_auto_20161212_0133'), ('teamspeak3', '0003_teamspeak3user'), ('teamspeak3', '0004_service_permissions'), ('teamspeak3', '0005_stategroup')]
+
+ initial = True
+
+ dependencies = [
+ migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+ ('authentication', '0025_v5squash'),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='TSgroup',
+ fields=[
+ ('ts_group_id', models.IntegerField(primary_key=True, serialize=False)),
+ ('ts_group_name', models.CharField(max_length=30)),
+ ],
+ options={
+ 'verbose_name': 'TS Group',
+ },
+ ),
+ migrations.CreateModel(
+ name='UserTSgroup',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('ts_group', models.ManyToManyField(to='teamspeak3.tsgroup')),
+ ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
+ ],
+ options={
+ 'verbose_name': 'User TS Group',
+ },
+ ),
+ migrations.CreateModel(
+ name='AuthTS',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('auth_group', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='auth.group')),
+ ('ts_group', models.ManyToManyField(to='teamspeak3.tsgroup')),
+ ],
+ options={
+ 'verbose_name': 'Auth / TS Group',
+ },
+ ),
+ migrations.CreateModel(
+ name='Teamspeak3User',
+ fields=[
+ ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, primary_key=True, related_name='teamspeak3', serialize=False, to=settings.AUTH_USER_MODEL)),
+ ('uid', models.CharField(max_length=254)),
+ ('perm_key', models.CharField(max_length=254)),
+ ],
+ options={
+ 'default_permissions': (),
+ 'permissions': (('access_teamspeak3', 'Can access the Teamspeak3 service'),),
+ },
+ ),
+ migrations.CreateModel(
+ name='StateGroup',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('state', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='authentication.state')),
+ ('ts_group', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='teamspeak3.tsgroup')),
+ ],
+ ),
+ ]
diff --git a/allianceauth/services/modules/teamspeak3/models.py b/allianceauth/services/modules/teamspeak3/models.py
index c4b020f3..5b685c9e 100644
--- a/allianceauth/services/modules/teamspeak3/models.py
+++ b/allianceauth/services/modules/teamspeak3/models.py
@@ -5,17 +5,13 @@ from allianceauth.authentication.models import State
class Teamspeak3User(models.Model):
- user = models.OneToOneField(User,
- primary_key=True,
- on_delete=models.CASCADE,
- related_name='teamspeak3')
+ user = models.OneToOneField(User, primary_key=True, on_delete=models.CASCADE, related_name="teamspeak3")
uid = models.CharField(max_length=254)
perm_key = models.CharField(max_length=254)
class Meta:
- permissions = (
- ("access_teamspeak3", "Can access the Teamspeak3 service"),
- )
+ default_permissions = ()
+ permissions = (("access_teamspeak3", "Can access the Teamspeak3 service"),)
def __str__(self) -> str:
return self.uid
@@ -26,7 +22,7 @@ class TSgroup(models.Model):
ts_group_name = models.CharField(max_length=30)
class Meta:
- verbose_name = 'TS Group'
+ verbose_name = "TS Group"
def __str__(self) -> str:
return self.ts_group_name
@@ -37,7 +33,7 @@ class AuthTS(models.Model):
ts_group = models.ManyToManyField(TSgroup)
class Meta:
- verbose_name = 'Auth / TS Group'
+ verbose_name = "Auth / TS Group"
def __str__(self) -> str:
return self.auth_group.name
@@ -48,7 +44,7 @@ class UserTSgroup(models.Model):
ts_group = models.ManyToManyField(TSgroup)
class Meta:
- verbose_name = 'User TS Group'
+ verbose_name = "User TS Group"
def __str__(self) -> str:
return self.user.name
diff --git a/allianceauth/services/modules/teamspeak3/util/ts3.py b/allianceauth/services/modules/teamspeak3/util/ts3.py
index 6b03734a..b94f14f9 100644
--- a/allianceauth/services/modules/teamspeak3/util/ts3.py
+++ b/allianceauth/services/modules/teamspeak3/util/ts3.py
@@ -8,7 +8,7 @@ class ConnectionError:
self.ip = ip
self.port = port
- def __str__(self):
+ def __str__(self) -> str:
return f'Error connecting to host {self.ip} port {self.port}'
@@ -270,7 +270,7 @@ class TeamspeakError(Exception):
msg = ts3_errors[self.code]
self.msg = msg
- def __str__(self):
+ def __str__(self) -> str:
return self.code + ' ' + self.msg
ts3_errors = {
diff --git a/allianceauth/services/modules/xenforo/migrations/0003_v5squash.py b/allianceauth/services/modules/xenforo/migrations/0003_v5squash.py
new file mode 100644
index 00000000..5b055b12
--- /dev/null
+++ b/allianceauth/services/modules/xenforo/migrations/0003_v5squash.py
@@ -0,0 +1,31 @@
+# Generated by Django 5.1.6 on 2025-03-05 00:56
+
+import django.db.migrations.operations.special
+import django.db.models.deletion
+from django.conf import settings
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ replaces = [('xenforo', '0001_initial'), ('xenforo', '0002_service_permissions')]
+
+ initial = True
+
+ dependencies = [
+ migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='XenforoUser',
+ fields=[
+ ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, primary_key=True, related_name='xenforo', serialize=False, to=settings.AUTH_USER_MODEL)),
+ ('username', models.CharField(max_length=254)),
+ ],
+ options={
+ 'default_permissions': (),
+ 'permissions': (('access_xenforo', 'Can access the XenForo service'),),
+ },
+ ),
+ ]
diff --git a/allianceauth/services/modules/xenforo/models.py b/allianceauth/services/modules/xenforo/models.py
index 8b7ce337..b4514b8b 100644
--- a/allianceauth/services/modules/xenforo/models.py
+++ b/allianceauth/services/modules/xenforo/models.py
@@ -2,17 +2,12 @@ from django.db import models
class XenforoUser(models.Model):
- user = models.OneToOneField('auth.User',
- primary_key=True,
- on_delete=models.CASCADE,
- related_name='xenforo')
+ user = models.OneToOneField("auth.User", primary_key=True, on_delete=models.CASCADE, related_name="xenforo")
username = models.CharField(max_length=254)
-
class Meta:
- permissions = (
- ("access_xenforo", "Can access the XenForo service"),
- )
+ default_permissions = ()
+ permissions = (("access_xenforo", "Can access the XenForo service"),)
- def __str__(self):
+ def __str__(self) -> str:
return self.username
diff --git a/allianceauth/srp/migrations/0005_alter_srpfleetmain_options.py b/allianceauth/srp/migrations/0005_alter_srpfleetmain_options.py
new file mode 100644
index 00000000..6a008ea3
--- /dev/null
+++ b/allianceauth/srp/migrations/0005_alter_srpfleetmain_options.py
@@ -0,0 +1,17 @@
+# Generated by Django 5.1.6 on 2025-03-05 00:59
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('srp', '0004_on_delete'),
+ ]
+
+ operations = [
+ migrations.AlterModelOptions(
+ name='srpfleetmain',
+ options={'default_permissions': (), 'permissions': (('access_srp', 'Can access SRP module'), ('add_srpfleetmain', 'Can access SRP module'))},
+ ),
+ ]
diff --git a/allianceauth/srp/migrations/0006_v5squash.py b/allianceauth/srp/migrations/0006_v5squash.py
new file mode 100644
index 00000000..039d65b3
--- /dev/null
+++ b/allianceauth/srp/migrations/0006_v5squash.py
@@ -0,0 +1,66 @@
+# Generated by Django 5.1.6 on 2025-03-05 01:07
+
+import django.db.models.deletion
+import django.utils.timezone
+from django.db import migrations, models
+
+
+def create_permissions(apps, schema_editor) -> None:
+ # Remnant of AAv0
+ User = apps.get_model('auth', 'User')
+ ContentType = apps.get_model('contenttypes', 'ContentType')
+ Permission = apps.get_model('auth', 'Permission')
+ ct = ContentType.objects.get_for_model(User)
+ Permission.objects.get_or_create(codename="srp_management", content_type=ct, name="srp_management")
+
+
+def reverse(apps, schema_editor) -> None:
+ pass
+
+
+class Migration(migrations.Migration):
+
+ replaces = [('srp', '0001_initial'), ('srp', '0002_srpuserrequest_srp_status_choices'), ('srp', '0003_make_strings_more_stringy'), ('srp', '0004_on_delete'), ('srp', '0005_alter_srpfleetmain_options')]
+
+ initial = True
+
+ dependencies = [
+ ('eveonline', '0019_v5squash'),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='SrpFleetMain',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('fleet_name', models.CharField(default='', max_length=254)),
+ ('fleet_doctrine', models.CharField(default='', max_length=254)),
+ ('fleet_time', models.DateTimeField()),
+ ('fleet_srp_code', models.CharField(default='', max_length=254)),
+ ('fleet_srp_status', models.CharField(default='', max_length=254)),
+ ('fleet_srp_aar_link', models.CharField(default='', max_length=254)),
+ ('fleet_commander', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='eveonline.evecharacter')),
+ ],
+ options={
+ 'permissions': (('access_srp', 'Can access SRP module'), ('add_srpfleetmain', 'Can access SRP module')),
+ 'default_permissions': (),
+ },
+ ),
+ migrations.CreateModel(
+ name='SrpUserRequest',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('killboard_link', models.CharField(default='', max_length=254)),
+ ('after_action_report_link', models.CharField(default='', max_length=254)),
+ ('additional_info', models.CharField(default='', max_length=254)),
+ ('srp_status', models.CharField(choices=[('Pending', 'Pending'), ('Approved', 'Approved'), ('Rejected', 'Rejected')], default='Pending', max_length=8)),
+ ('srp_total_amount', models.BigIntegerField(default=0)),
+ ('kb_total_loss', models.BigIntegerField(default=0)),
+ ('srp_ship_name', models.CharField(default='', max_length=254)),
+ ('post_time', models.DateTimeField(default=django.utils.timezone.now)),
+ ('character', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='eveonline.evecharacter')),
+ ('srp_fleet_main', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='srp.srpfleetmain')),
+ ],
+ ),
+ migrations.RunPython(create_permissions, reverse)
+ ]
diff --git a/allianceauth/srp/models.py b/allianceauth/srp/models.py
index 78e3c384..f9cc36bc 100644
--- a/allianceauth/srp/models.py
+++ b/allianceauth/srp/models.py
@@ -13,26 +13,33 @@ class SrpFleetMain(models.Model):
fleet_commander = models.ForeignKey(EveCharacter, null=True, on_delete=models.SET_NULL)
fleet_srp_aar_link = models.CharField(max_length=254, default="")
-
-
class Meta:
- permissions = (('access_srp', 'Can access SRP module'),)
+ permissions = (
+ ("access_srp", "Can access SRP module"),
+ ("add_srpfleetmain", "Can access SRP module"),
+ # Intentionally Commented out
+ # AAv0 has these in the Auth_ Content Type
+ # ('srp_management', 'Can Approve and Deny SRP requests, Can create an SRP Fleet'),
+ )
+ default_permissions = ()
def __str__(self) -> str:
return self.fleet_name
@property
- def total_cost(self):
+ def total_cost(self) -> int:
return sum(int(r.srp_total_amount) for r in self.srpuserrequest_set.all())
@property
def pending_requests(self):
- return self.srpuserrequest_set.filter(srp_status='Pending').count()
+ return self.srpuserrequest_set.filter(srp_status="Pending").count()
+
+
class SrpUserRequest(models.Model):
SRP_STATUS_CHOICES = (
- ('Pending', 'Pending'),
- ('Approved', 'Approved'),
- ('Rejected', 'Rejected'),
+ ("Pending", "Pending"),
+ ("Approved", "Approved"),
+ ("Rejected", "Rejected"),
)
killboard_link = models.CharField(max_length=254, default="")
@@ -47,4 +54,4 @@ class SrpUserRequest(models.Model):
post_time = models.DateTimeField(default=timezone.now)
def __str__(self) -> str:
- return self.character.character_name + ' SRP request for ' + self.srp_ship_name
+ return f"{self.character.character_name} SRP request for {self.srp_ship_name}"
diff --git a/allianceauth/timerboard/migrations/0008_v5squash.py b/allianceauth/timerboard/migrations/0008_v5squash.py
new file mode 100644
index 00000000..d696443f
--- /dev/null
+++ b/allianceauth/timerboard/migrations/0008_v5squash.py
@@ -0,0 +1,55 @@
+# Generated by Django 5.1.6 on 2025-03-04 01:27
+
+from django.conf import settings
+from django.db import migrations, models
+
+
+def create_permissions(apps, schema_editor) -> None:
+ # Remnant of AAv0
+ User = apps.get_model('auth', 'User')
+ ContentType = apps.get_model('contenttypes', 'ContentType')
+ Permission = apps.get_model('auth', 'Permission')
+ ct = ContentType.objects.get_for_model(User)
+ Permission.objects.get_or_create(codename="timer_management", content_type=ct, name="timer_management")
+ Permission.objects.get_or_create(codename="timer_view", content_type=ct, name="timer_view")
+
+
+def reverse(apps, schema_editor) -> None:
+ pass
+
+
+class Migration(migrations.Migration):
+
+ replaces = [('timerboard', '0001_initial'), ('timerboard', '0002_make_strings_more_stringy'), ('timerboard', '0003_on_delete'), ('timerboard', '0004_timer_type'), ('timerboard', '0005_alter_timer_planet_moon'), ('timerboard', '0006_alter_timer_objective_alter_timer_structure_and_more'), ('timerboard', '0007_alter_timer_structure')]
+
+ initial = True
+
+ dependencies = [
+ migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+ ('eveonline', '0019_v5squash'),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='Timer',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('details', models.CharField(default='', max_length=254)),
+ ('system', models.CharField(default='', max_length=254)),
+ ('planet_moon', models.CharField(blank=True, default='', max_length=254)),
+ ('structure', models.CharField(choices=[('POCO', 'POCO'), ('Orbital Skyhook', 'Orbital Skyhook'), ('I-HUB', 'Sovereignty Hub'), ('TCU', 'TCU'), ('POS[S]', 'POS [S]'), ('POS[M]', 'POS [M]'), ('POS[L]', 'POS [L]'), ('Astrahus', 'Astrahus'), ('Fortizar', 'Fortizar'), ('Keepstar', 'Keepstar'), ('Raitaru', 'Raitaru'), ('Azbel', 'Azbel'), ('Sotiyo', 'Sotiyo'), ('Athanor', 'Athanor'), ('Tatara', 'Tatara'), ('Pharolux Cyno Beacon', 'Cyno Beacon'), ('Tenebrex Cyno Jammer', 'Cyno Jammer'), ('Ansiblex Jump Gate', 'Ansiblex Jump Gate'), ('Mercenary Den', 'Mercenary Den'), ('Moon Mining Cycle', 'Moon Mining Cycle'), ('Metenox Moon Drill', 'Metenox Moon Drill'), ('Other', 'Other')], default='Other', max_length=254)),
+ ('objective', models.CharField(choices=[('Friendly', 'Friendly'), ('Hostile', 'Hostile'), ('Neutral', 'Neutral')], default='Neutral', max_length=254)),
+ ('eve_time', models.DateTimeField()),
+ ('important', models.BooleanField(default=False)),
+ ('corp_timer', models.BooleanField(default=False)),
+ ('eve_character', models.ForeignKey(null=True, on_delete=models.deletion.SET_NULL, to='eveonline.evecharacter')),
+ ('eve_corp', models.ForeignKey(on_delete=models.deletion.CASCADE, to='eveonline.evecorporationinfo')),
+ ('user', models.ForeignKey(null=True, on_delete=models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL)),
+ ('timer_type', models.CharField(choices=[('UNSPECIFIED', 'Not Specified'), ('SHIELD', 'Shield'), ('ARMOR', 'Armor'), ('HULL', 'Hull'), ('FINAL', 'Final'), ('ANCHORING', 'Anchoring'), ('UNANCHORING', 'Unanchoring'), ('ABANDONED', 'Abandoned')], default='UNSPECIFIED', max_length=254)),
+ ],
+ options={
+ 'ordering': ['eve_time'],
+ },
+ ),
+ migrations.RunPython(create_permissions, reverse)
+ ]
diff --git a/allianceauth/timerboard/models.py b/allianceauth/timerboard/models.py
index 74a15c70..c1703bdd 100644
--- a/allianceauth/timerboard/models.py
+++ b/allianceauth/timerboard/models.py
@@ -73,6 +73,12 @@ class Timer(models.Model):
class Meta:
ordering = ['eve_time']
+ # Intentionally Commented out
+ # AAv0 has these in the Auth_ Content Type
+ # permissions = (
+ # ('timer_view', 'Can view Timerboard Timers'),
+ # ('timer_management', 'Can Manage Timerboard timers'))
+ # default_permissions = ()
def __str__(self) -> str:
- return str(self.system) + ' ' + str(self.details)
+ return f"{self.system} {self.details}"
diff --git a/docs/features/apps/srp.md b/docs/features/apps/srp.md
index e76ebf97..53940410 100644
--- a/docs/features/apps/srp.md
+++ b/docs/features/apps/srp.md
@@ -40,10 +40,10 @@ To use and administer this feature, users will require some of the following.
+----------------------+------------------+------------------------------------------------------------+
| Permission | Admin Site | Auth Site |
+======================+==================+============================================================+
-| auth.access_srp | None | Can create an SRP request from a fleet |
+| srp.access_srp | None | Can create an SRP request from a fleet |
+----------------------+------------------+------------------------------------------------------------+
| auth.srp_management | None | Can Approve and Deny SRP requests, Can create an SRP Fleet |
+----------------------+------------------+------------------------------------------------------------+
-| srp.add_srpfleetmain | Can Add Model | Can Create an SRP Fleet |
+| srp.add_srpfleetmain | None | Can Create an SRP Fleet |
+----------------------+------------------+------------------------------------------------------------+
```