mirror of
https://gitlab.com/allianceauth/allianceauth.git
synced 2025-07-08 20:10:17 +02:00
Merge branch 'v5-squash' into 'v5.x'
V5 Squash See merge request allianceauth/allianceauth!1697
This commit is contained in:
commit
35551b611b
56
allianceauth/analytics/migrations/0011_v5squash.py
Normal file
56
allianceauth/analytics/migrations/0011_v5squash.py
Normal 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
|
||||
),
|
||||
]
|
@ -17,6 +17,7 @@ class AnalyticsIdentifier(SingletonModel):
|
||||
class Meta:
|
||||
verbose_name = "Analytics Identifier"
|
||||
|
||||
|
||||
class AnalyticsTokens(models.Model):
|
||||
|
||||
class Analytics_Type(models.TextChoices):
|
||||
|
124
allianceauth/authentication/migrations/0025_v5squash.py
Normal file
124
allianceauth/authentication/migrations/0025_v5squash.py
Normal 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),
|
||||
|
||||
]
|
@ -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}"
|
||||
|
52
allianceauth/corputils/migrations/0006_v5squash.py
Normal file
52
allianceauth/corputils/migrations/0006_v5squash.py
Normal 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')},
|
||||
},
|
||||
),
|
||||
]
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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'),
|
||||
),
|
||||
]
|
@ -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
|
||||
|
@ -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'),
|
||||
),
|
||||
]
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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),
|
||||
),
|
||||
]
|
73
allianceauth/eveonline/migrations/0019_v5squash.py
Normal file
73
allianceauth/eveonline/migrations/0019_v5squash.py
Normal 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')],
|
||||
},
|
||||
),
|
||||
]
|
@ -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()
|
||||
|
@ -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):
|
||||
|
@ -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)
|
||||
]
|
@ -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}"
|
||||
|
102
allianceauth/groupmanagement/migrations/0020_v5squash.py
Normal file
102
allianceauth/groupmanagement/migrations/0020_v5squash.py
Normal 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)
|
||||
]
|
@ -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 = ()
|
||||
|
||||
|
100
allianceauth/hrapplications/migrations/0008_v5squash.py
Normal file
100
allianceauth/hrapplications/migrations/0008_v5squash.py
Normal 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)
|
||||
|
||||
]
|
@ -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)
|
||||
|
@ -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),
|
||||
),
|
||||
]
|
@ -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
|
||||
|
46
allianceauth/notifications/migrations/0006_v5squash.py
Normal file
46
allianceauth/notifications/migrations/0006_v5squash.py
Normal 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)
|
||||
]
|
@ -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)
|
||||
|
67
allianceauth/optimer/migrations/0005_v5squash.py
Normal file
67
allianceauth/optimer/migrations/0005_v5squash.py
Normal 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)
|
||||
]
|
@ -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
|
||||
|
@ -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}"
|
||||
|
@ -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 = [
|
||||
|
29
allianceauth/services/migrations/0004_v5squash.py
Normal file
29
allianceauth/services/migrations/0004_v5squash.py
Normal 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')),
|
||||
],
|
||||
),
|
||||
]
|
@ -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'),),
|
||||
},
|
||||
),
|
||||
]
|
@ -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
|
||||
|
@ -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}"
|
||||
|
||||
|
||||
|
@ -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'),),
|
||||
},
|
||||
),
|
||||
]
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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'),),
|
||||
},
|
||||
),
|
||||
]
|
@ -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
|
||||
|
@ -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',
|
||||
},
|
||||
),
|
||||
]
|
@ -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',
|
||||
|
@ -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,
|
||||
),
|
||||
]
|
@ -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),
|
||||
),
|
||||
]
|
@ -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),
|
||||
),
|
||||
]
|
@ -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),
|
||||
),
|
||||
]
|
@ -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),
|
||||
]
|
@ -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),
|
||||
),
|
||||
]
|
@ -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),
|
||||
)
|
||||
]
|
@ -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,
|
||||
),
|
||||
]
|
@ -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'),
|
||||
),
|
||||
]
|
@ -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),
|
||||
),
|
||||
]
|
@ -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'),
|
||||
),
|
||||
]
|
@ -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')),
|
||||
},
|
||||
),
|
||||
]
|
@ -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,9 +128,9 @@ 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):
|
||||
@ -142,7 +139,7 @@ class MumbleUser(AbstractServiceModel):
|
||||
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"),
|
||||
|
@ -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)
|
||||
]
|
@ -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
|
||||
|
@ -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'),),
|
||||
},
|
||||
),
|
||||
]
|
@ -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
|
||||
|
@ -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'),),
|
||||
},
|
||||
),
|
||||
]
|
@ -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
|
||||
|
@ -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')),
|
||||
],
|
||||
),
|
||||
]
|
@ -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
|
||||
|
@ -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 = {
|
||||
|
@ -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'),),
|
||||
},
|
||||
),
|
||||
]
|
@ -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
|
||||
|
@ -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'))},
|
||||
),
|
||||
]
|
66
allianceauth/srp/migrations/0006_v5squash.py
Normal file
66
allianceauth/srp/migrations/0006_v5squash.py
Normal 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)
|
||||
]
|
@ -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}"
|
||||
|
55
allianceauth/timerboard/migrations/0008_v5squash.py
Normal file
55
allianceauth/timerboard/migrations/0008_v5squash.py
Normal 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)
|
||||
]
|
@ -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}"
|
||||
|
@ -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 |
|
||||
+----------------------+------------------+------------------------------------------------------------+
|
||||
```
|
||||
|
Loading…
x
Reference in New Issue
Block a user