heccin squash

This commit is contained in:
Joel Falknau 2025-03-05 11:48:43 +10:00
parent 389b958ca7
commit 5d4df417c2
No known key found for this signature in database
63 changed files with 758 additions and 721 deletions

View File

@ -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 = [
('authentication', '0025_v5squash'),
]
operations = [
migrations.AlterField(
model_name='userprofile',
name='theme',
field=models.CharField(blank=True, default='', help_text='Bootstrap 5 Themes from https://bootswatch.com/ or Community Apps', max_length=200, verbose_name='Theme'),
),
]

View File

@ -15,24 +15,30 @@ 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 = StateManager()
class Meta:
ordering = ['-priority']
ordering = ["-priority"]
def __str__(self):
def __str__(self) -> str:
return self.name
def available_to_character(self, character):
@ -48,11 +54,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():
@ -60,76 +66,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)
# 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(
_("Theme"),
max_length=200,
blank=True,
help_text="Bootstrap 5 Themes from https://bootswatch.com/ or Community Apps"
default="",
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
@ -137,34 +125,32 @@ 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')
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 = CharacterOwnershipManager()
class Meta:
default_permissions = ('change', 'delete')
ordering = ['user', 'character__character_name']
def __str__(self):
default_permissions = ("change", "delete")
ordering = ["user", "character__character_name"]
def __str__(self) -> str:
return f"{self.user}: {self.character}"
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):
def __str__(self) -> str:
return f"{self.user}: {self.character} on {self.created}"

View File

@ -34,6 +34,7 @@ class CorpStats(models.Model):
last_update = models.DateTimeField(auto_now=True)
objects = CorpStatsManager()
class Meta:
permissions = (
('view_corp_corpstats', 'Can view corp stats of their corporation.'),
@ -43,12 +44,10 @@ class CorpStats(models.Model):
verbose_name = "corp stats"
verbose_name_plural = "corp stats"
def __str__(self):
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 +100,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 +120,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 +133,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:
@ -154,11 +153,11 @@ class CorpMember(models.Model):
unique_together = ('corpstats', 'character_id')
ordering = ['character_name']
def __str__(self):
def __str__(self) -> str:
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 +178,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)

View File

@ -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)

View File

@ -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'),
),
]

View File

@ -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

View File

@ -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 01:45
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,15 +28,18 @@ 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)),
('alliance_managed_groups', 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')),
('corp_managed_groups', 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')),
('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')),
('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,
@ -45,27 +49,12 @@ class Migration(migrations.Migration):
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')),
('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='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'),
),
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'),
),
]

View File

@ -81,23 +81,23 @@ class AutogroupsConfig(models.Model):
objects = AutogroupsConfigManager()
def __str__(self):
return 'States: ' + (' '.join(list(self.states.all().values_list('name', flat=True))) if self.pk else str(None))
def __str__(self) -> str:
return f"States: {' '.join(self.states.all().values_list('name', flat=True)) if self.pk else '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)
@ -235,9 +235,10 @@ class ManagedGroup(models.Model):
class Meta:
abstract = True
def __str__(self):
def __str__(self) -> str:
return f"Managed Group: {self.group.name}"
class ManagedCorpGroup(ManagedGroup):
corp = models.ForeignKey(EveCorporationInfo, on_delete=models.CASCADE)

View File

@ -20,14 +20,14 @@ class Migration(migrations.Migration):
name='alliance_ticker',
field=models.CharField(blank=True, default='', max_length=5),
),
migrations.AlterField(
model_name='evecharacter',
name='faction_id',
field=models.PositiveIntegerField(blank=True, default=None, null=True),
),
migrations.AlterField(
model_name='evecharacter',
name='faction_name',
field=models.CharField(blank=True, default='', max_length=254),
),
migrations.AlterField(
model_name='evecharacter',
name='faction_id',
field=models.PositiveIntegerField(blank=True, default=None, null=True),
),
]

View File

@ -1,7 +1,6 @@
# Generated by Django 5.1.6 on 2025-03-04 03:06
# Generated by Django 5.1.6 on 2025-03-05 01:03
import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
@ -12,7 +11,7 @@ class Migration(migrations.Migration):
initial = True
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('auth', '__first__'),
]
operations = [
@ -29,25 +28,6 @@ class Migration(migrations.Migration):
'indexes': [models.Index(fields=['executor_corp_id'], name='eveonline_e_executo_7f3280_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')],
},
),
migrations.CreateModel(
name='EveFactionInfo',
fields=[
@ -71,4 +51,23 @@ class Migration(migrations.Migration):
'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)),
('alliance_ticker', models.CharField(blank=True, default='', max_length=5)),
('faction_id', models.PositiveIntegerField(blank=True, default=None, null=True)),
('faction_name', models.CharField(blank=True, default='', max_length=254)),
],
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')],
},
),
]

View File

@ -32,7 +32,7 @@ class EveFactionInfo(models.Model):
provider = providers.provider
def __str__(self):
def __str__(self) -> str:
return self.faction_name
@staticmethod
@ -80,9 +80,11 @@ class EveAllianceInfo(models.Model):
class Meta:
indexes = [models.Index(fields=['executor_corp_id',])]
def __str__(self):
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():
@ -101,8 +103,6 @@ class EveAllianceInfo(models.Model):
self.save()
return self
@staticmethod
def generic_logo_url(
alliance_id: int, size: int = _DEFAULT_IMAGE_SIZE
@ -152,8 +152,10 @@ class EveCorporationInfo(models.Model):
class Meta:
indexes = [models.Index(fields=['ceo_id',]),]
def __str__(self):
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)
@ -166,8 +168,6 @@ class EveCorporationInfo(models.Model):
self.save()
return self
@staticmethod
def generic_logo_url(
corporation_id: int, size: int = _DEFAULT_IMAGE_SIZE
@ -226,7 +226,7 @@ class EveCharacter(models.Model):
models.Index(fields=['faction_id',]),
]
def __str__(self):
def __str__(self) -> str:
return self.character_name
@property

View File

@ -1,5 +1,6 @@
import logging
import os
from typing import Literal
from bravado.exception import HTTPError, HTTPNotFound, HTTPUnprocessableEntity
from jsonschema.exceptions import RefResolutionError
@ -36,7 +37,7 @@ class ObjectNotFound(Exception):
self.id = obj_id
self.type = type_name
def __str__(self):
def __str__(self) -> str:
return f'{self.type} with ID {self.id} not found.'
@ -46,13 +47,13 @@ class Entity:
self.id = id
self.name = name
def __str__(self):
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):
@ -206,7 +207,7 @@ class EveSwaggerProvider(EveProvider):
)
return self._client
def __str__(self):
def __str__(self) -> Literal['esi']:
return 'esi'
def get_alliance(self, alliance_id: int) -> Alliance:

View File

@ -13,7 +13,7 @@ class BravadoResponseStub:
self.headers = headers if headers else {}
self.raw_bytes = raw_bytes
def __str__(self):
def __str__(self) -> str:
return f"{self.status_code} {self.reason}"

View File

@ -13,7 +13,7 @@ class Fatlink(models.Model):
hash = models.CharField(max_length=254, unique=True)
creator = models.ForeignKey(User, on_delete=models.SET(get_sentinel_user))
def __str__(self):
def __str__(self) -> str:
return self.fleet
@ -26,7 +26,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):
def __str__(self) -> str:
return f"Fat-link for {self.character.character_name}"

View File

@ -15,7 +15,7 @@ class GroupRequest(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
group = models.ForeignKey(Group, on_delete=models.CASCADE)
def __str__(self):
def __str__(self) -> str:
return self.user.username + ":" + self.group.name
@property
@ -50,10 +50,10 @@ class RequestLog(models.Model):
request_actor = models.ForeignKey(User, on_delete=models.CASCADE)
date = models.DateTimeField(auto_now_add=True)
def __str__(self):
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):
@ -182,7 +182,7 @@ class AuthGroup(models.Model):
)
default_permissions = ()
def __str__(self):
def __str__(self) -> str:
return self.group.name
def group_request_approvers(self) -> set[User]:

View File

@ -13,7 +13,7 @@ class ApplicationQuestion(models.Model):
help_text = models.CharField(max_length=254, blank=True)
multi_select = models.BooleanField(default=False)
def __str__(self):
def __str__(self) -> str:
return "Question: " + self.title
@ -21,7 +21,7 @@ class ApplicationChoice(models.Model):
question = models.ForeignKey(ApplicationQuestion,on_delete=models.CASCADE,related_name="choices")
choice_text = models.CharField(max_length=200, verbose_name='Choice')
def __str__(self):
def __str__(self) -> str:
return self.choice_text
@ -29,7 +29,7 @@ class ApplicationForm(models.Model):
questions = SortedManyToManyField(ApplicationQuestion)
corp = models.OneToOneField(EveCorporationInfo, on_delete=models.CASCADE)
def __str__(self):
def __str__(self) -> str:
return str(self.corp)
@ -43,14 +43,13 @@ class Application(models.Model):
objects = ApplicationManager()
class Meta:
permissions = (
('approve_application', 'Can approve applications'), ('reject_application', 'Can reject applications'),
('view_apis', 'Can view applicant APIs'),)
unique_together = ('form', 'user')
def __str__(self):
def __str__(self) -> str:
return str(self.user) + " Application To " + str(self.form)
@property
@ -75,19 +74,19 @@ 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):
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)
text = models.TextField()
created = models.DateTimeField(auto_now_add=True)
def __str__(self):
def __str__(self) -> str:
return str(self.user) + " comment on " + str(self.application)

View File

@ -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),
),
]

View File

@ -40,10 +40,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
@ -53,7 +50,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
@ -62,10 +59,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. <code>fa-solid fa-house</code>"
),
help_text=_("Font Awesome classes to show as icon on menu, " "e.g. <code>fa-solid fa-house</code>"),
)
url = models.TextField(
default="",
@ -78,7 +72,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)
@ -124,14 +118,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

View File

@ -61,12 +61,12 @@ class Notification(models.Model):
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)

View File

@ -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):
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,13 @@ 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 = ()
def __str__(self):
def __str__(self) -> str:
return self.operation_name

View File

@ -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}"

View File

@ -119,7 +119,7 @@ class ServicesHook:
"""
return ''
def __str__(self):
def __str__(self) -> str:
return self.name or 'Unknown Service Module'
class Urls:

View File

@ -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 = [

View File

@ -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')),
],
),
]

View File

@ -26,7 +26,7 @@ class NameFormatConfig(models.Model):
"formatter for each state for each service."
)
def __str__(self):
def __str__(self) -> str:
return '{}: {}'.format(
self.service_name, ', '.join([str(x) for x in self.states.all()])
)

View File

@ -0,0 +1,32 @@
# 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={
'permissions': (('access_discord', 'Can access the Discord service'),),
},
),
]

View File

@ -25,45 +25,28 @@ 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 = DiscordUserManager()
class Meta:
permissions = (
("access_discord", "Can access the Discord service"),
)
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
@ -80,15 +63,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:
@ -104,27 +83,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:
@ -135,23 +109,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
@ -168,37 +137,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

View File

@ -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}"

View File

@ -0,0 +1,30 @@
# 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={
'permissions': (('access_discourse', 'Can access the Discourse service'),),
},
),
]

View File

@ -3,18 +3,11 @@ 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"),
)
permissions = (("access_discourse", "Can access the Discourse service"),)
def __str__(self):
def __str__(self) -> str:
return self.user.username

View File

@ -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

View File

@ -0,0 +1,35 @@
# 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
# Functions from the following migrations need manual copying.
# Move them and any dependencies into this file, then update the
# RunPython operations to refer to the local versions:
# allianceauth.services.modules.ips4.migrations.0002_service_permissions
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={
'permissions': (('access_ips4', 'Can access the IPS4 service'),),
},
),
]

View File

@ -3,18 +3,12 @@ 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"),
)
permissions = (("access_ips4", "Can access the IPS4 service"),)
def __str__(self):
def __str__(self) -> str:
return self.username

View File

@ -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',
},
),
]

View File

@ -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',

View File

@ -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,
),
]

View File

@ -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),
),
]

View File

@ -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),
),
]

View File

@ -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),
),
]

View File

@ -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),
]

View File

@ -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),
),
]

View File

@ -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),
)
]

View File

@ -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,
),
]

View File

@ -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'),
),
]

View File

@ -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),
),
]

View File

@ -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'),
),
]

View File

@ -0,0 +1,38 @@
# 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={
'permissions': (('access_mumble', 'Can access the Mumble service'), ('view_connection_history', 'Can access the connection history of the Mumble service')),
},
),
]

View File

@ -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 = 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()

View File

@ -0,0 +1,34 @@
# 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
# Functions from the following migrations need manual copying.
# Move them and any dependencies into this file, then update the
# RunPython operations to refer to the local versions:
# allianceauth.services.modules.openfire.migrations.0002_service_permissions
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={
'permissions': (('access_openfire', 'Can access the Openfire service'),),
},
),
]

View File

@ -2,17 +2,11 @@ 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:
permissions = (
("access_openfire", "Can access the Openfire service"),
)
def __str__(self):
permissions = (("access_openfire", "Can access the Openfire service"),)
def __str__(self) -> str:
return self.username

View File

@ -0,0 +1,34 @@
# 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
# Functions from the following migrations need manual copying.
# Move them and any dependencies into this file, then update the
# RunPython operations to refer to the local versions:
# allianceauth.services.modules.phpbb3.migrations.0002_service_permissions
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={
'permissions': (('access_phpbb3', 'Can access the phpBB3 service'),),
},
),
]

View File

@ -2,16 +2,11 @@ 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"),
)
permissions = (("access_phpbb3", "Can access the phpBB3 service"),)
def __str__(self) -> str:
return self.username

View File

@ -0,0 +1,35 @@
# 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
# Functions from the following migrations need manual copying.
# Move them and any dependencies into this file, then update the
# RunPython operations to refer to the local versions:
# allianceauth.services.modules.smf.migrations.0002_service_permissions
# allianceauth.services.modules.smf.migrations.0003_set_smf_displayed_names
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={
'permissions': (('access_smf', 'Can access the SMF service'),),
},
),
]

View File

@ -2,16 +2,11 @@ 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"),
)
permissions = (("access_smf", "Can access the SMF service"),)
def __str__(self) -> str:
return self.username

View File

@ -0,0 +1,72 @@
# 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={
'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')),
],
),
]

View File

@ -5,17 +5,12 @@ 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"),
)
permissions = (("access_teamspeak3", "Can access the Teamspeak3 service"),)
def __str__(self) -> str:
return self.uid
@ -26,7 +21,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 +32,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 +43,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

View File

@ -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 = {

View File

@ -0,0 +1,34 @@
# 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
# Functions from the following migrations need manual copying.
# Move them and any dependencies into this file, then update the
# RunPython operations to refer to the local versions:
# allianceauth.services.modules.xenforo.migrations.0002_service_permissions
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={
'permissions': (('access_xenforo', 'Can access the XenForo service'),),
},
),
]

View File

@ -2,17 +2,11 @@ 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"),
)
permissions = (("access_xenforo", "Can access the XenForo service"),)
def __str__(self):
def __str__(self) -> str:
return self.username

View File

@ -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'))},
),
]

View File

@ -1,31 +1,17 @@
# Generated by Django 5.1.6 on 2025-03-04 01:26
# Generated by Django 5.1.6 on 2025-03-05 01:07
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):
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):
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')]
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 = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('eveonline', '0019_v5squash'),
]
@ -43,7 +29,8 @@ class Migration(migrations.Migration):
('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'),),
'permissions': (('access_srp', 'Can access SRP module'), ('add_srpfleetmain', 'Can access SRP module')),
'default_permissions': (),
},
),
migrations.CreateModel(
@ -62,6 +49,4 @@ class Migration(migrations.Migration):
('srp_fleet_main', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='srp.srpfleetmain')),
],
),
migrations.RunPython(create_permissions, reverse)
]

View File

@ -15,31 +15,31 @@ class SrpFleetMain(models.Model):
class Meta:
permissions = (
('access_srp', 'Can access SRP module'),
('add_srpfleetmain', 'Can access SRP module'),
("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):
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="")
@ -53,5 +53,5 @@ class SrpUserRequest(models.Model):
srp_ship_name = models.CharField(max_length=254, default="")
post_time = models.DateTimeField(default=timezone.now)
def __str__(self):
return self.character.character_name + ' SRP request for ' + self.srp_ship_name
def __str__(self) -> str:
return f"{self.character.character_name} SRP request for {self.srp_ship_name}"

View File

@ -80,4 +80,4 @@ class Timer(models.Model):
# default_permissions = ()
def __str__(self) -> str:
return str(self.system) + ' ' + str(self.details)
return f"{self.system} {self.details}"