V5 Squash

This commit is contained in:
Ariel Rin 2025-07-07 02:51:11 +00:00
parent 6ab2af79eb
commit 99f43029df
70 changed files with 1588 additions and 642 deletions

View File

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

View File

@ -17,6 +17,7 @@ class AnalyticsIdentifier(SingletonModel):
class Meta:
verbose_name = "Analytics Identifier"
class AnalyticsTokens(models.Model):
class Analytics_Type(models.TextChoices):

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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.<br>Used for groups such as Members, Corp_*, Alliance_* etc.<br><b>Overrides Hidden and Open options when selected.</b>')),
('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.<br>If the group is not open users will need their request manually approved.')),
('description', models.TextField(blank=True, help_text='Short description <i>(max. 512 characters)</i> 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 <code>auth.group_management</code> permission to allow a user to manage all groups.<br>', 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.<br>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 <code>auth.group_management</code> permission to allow a user to manage all groups.<br>', 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.<br>', 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)
]

View File

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

View File

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

View File

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

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

@ -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. <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="",
@ -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

View File

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

View File

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

View File

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

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

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

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

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

View File

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

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

View File

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

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

View File

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

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

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: 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"),

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

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

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

View File

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

View File

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

View File

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

View File

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