editorconfig applied

This commit is contained in:
Peter Pfeufer 2021-05-17 11:42:28 +02:00
parent bad36a69e8
commit e6a4cea4de
No known key found for this signature in database
GPG Key ID: 6051D2C6AD4EBC27
99 changed files with 522 additions and 600 deletions

View File

@ -10,7 +10,7 @@ charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.{yaml,yml}]
[*.{yaml,yml,less}]
indent_size = 2
[*.md]
@ -19,3 +19,6 @@ indent_size = 2
# Makefiles always use tabs for indentation
[Makefile]
indent_style = tab
[*.bat]
indent_style = tab

View File

@ -13,10 +13,16 @@ repos:
- id: check-yaml
- id: fix-byte-order-marker
- id: trailing-whitespace
exclude: \.(min\.css|min\.js|po|mo)$
exclude: \.(min\.css|min\.js|mo)$
- id: end-of-file-fixer
exclude: \.(min\.css|min\.js|po|mo)$
exclude: \.(min\.css|min\.js|mo)$
- id: mixed-line-ending
args: [ '--fix=lf' ]
- id: fix-encoding-pragma
args: [ '--remove' ]
- repo: https://github.com/editorconfig-checker/editorconfig-checker.python
rev: 2.3.5
hooks:
- id: editorconfig-checker
exclude: ^(LICENSE|allianceauth/static/css/themes/bootstrap-locals.less)

View File

@ -23,8 +23,7 @@ class CharacterOwnershipManager(Manager):
def create_by_token(self, token):
if not EveCharacter.objects.filter(character_id=token.character_id).exists():
EveCharacter.objects.create_character(token.character_id)
return self.create(character=EveCharacter.objects.get(character_id=token.character_id), user=token.user,
owner_hash=token.character_owner_hash)
return self.create(character=EveCharacter.objects.get(character_id=token.character_id), user=token.user, owner_hash=token.character_owner_hash)
class StateQuerySet(QuerySet):

View File

@ -106,8 +106,8 @@ def populate_ownerships(apps, schema_editor):
EveCharacter = apps.get_model('eveonline', 'EveCharacter')
unique_character_owners = [t['character_id'] for t in
Token.objects.all().values('character_id').annotate(n=models.Count('user')) if
t['n'] == 1 and EveCharacter.objects.filter(character_id=t['character_id']).exists()]
Token.objects.all().values('character_id').annotate(n=models.Count('user')) if
t['n'] == 1 and EveCharacter.objects.filter(character_id=t['character_id']).exists()]
tokens = Token.objects.filter(character_id__in=unique_character_owners)
for c_id in unique_character_owners:
@ -170,8 +170,7 @@ def recreate_authservicesinfo(apps, schema_editor):
# repopulate main characters
for profile in UserProfile.objects.exclude(main_character__isnull=True).select_related('user', 'main_character'):
AuthServicesInfo.objects.update_or_create(user=profile.user,
defaults={'main_char_id': profile.main_character.character_id})
AuthServicesInfo.objects.update_or_create(user=profile.user, defaults={'main_char_id': profile.main_character.character_id})
# repopulate states we understand
for profile in UserProfile.objects.exclude(state__name='Guest').filter(

View File

@ -14,15 +14,11 @@ logger = logging.getLogger(__name__)
class State(models.Model):
name = models.CharField(max_length=20, 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_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.")
public = models.BooleanField(default=False, help_text="Make this state available to any character.")
objects = StateManager()

View File

@ -75,8 +75,7 @@ def create_required_models(sender, instance, created, *args, **kwargs):
@receiver(post_save, sender=Token)
def record_character_ownership(sender, instance, created, *args, **kwargs):
if created:
logger.debug('New token for {0} character {1} saved. Evaluating ownership.'.format(instance.user,
instance.character_name))
logger.debug('New token for {0} character {1} saved. Evaluating ownership.'.format(instance.user, instance.character_name))
if instance.user:
query = Q(owner_hash=instance.character_owner_hash) & Q(user=instance.user)
else:
@ -85,18 +84,14 @@ def record_character_ownership(sender, instance, created, *args, **kwargs):
CharacterOwnership.objects.filter(character__character_id=instance.character_id).exclude(query).delete()
# create character if needed
if EveCharacter.objects.filter(character_id=instance.character_id).exists() is False:
logger.debug('Token is for a new character. Creating model for {0} ({1})'.format(instance.character_name,
instance.character_id))
logger.debug('Token is for a new character. Creating model for {0} ({1})'.format(instance.character_name, instance.character_id))
EveCharacter.objects.create_character(instance.character_id)
char = EveCharacter.objects.get(character_id=instance.character_id)
# check if we need to create ownership
if instance.user and not CharacterOwnership.objects.filter(
character__character_id=instance.character_id).exists():
logger.debug("Character {0} is not yet owned. Assigning ownership to {1}".format(instance.character_name,
instance.user))
CharacterOwnership.objects.update_or_create(character=char,
defaults={'owner_hash': instance.character_owner_hash,
'user': instance.user})
logger.debug("Character {0} is not yet owned. Assigning ownership to {1}".format(instance.character_name, instance.user))
CharacterOwnership.objects.update_or_create(character=char, defaults={'owner_hash': instance.character_owner_hash, 'user': instance.user})
@receiver(pre_delete, sender=CharacterOwnership)

View File

@ -138,7 +138,7 @@ class TestAuthenticate(TestCase):
def test_iterate_username(self):
t = Token(character_id=self.unclaimed_character.character_id,
character_name=self.unclaimed_character.character_name, character_owner_hash='3')
character_name=self.unclaimed_character.character_name, character_owner_hash='3')
username = StateBackend().authenticate(token=t).username
t.character_owner_hash = '4'
username_1 = StateBackend().authenticate(token=t).username

View File

@ -80,11 +80,11 @@ class StateTestCase(TestCase):
def setUpTestData(cls):
cls.user = AuthUtils.create_user('test_user', disconnect_signals=True)
AuthUtils.add_main_character(cls.user, 'Test Character', '1', corp_id='1', alliance_id='1',
corp_name='Test Corp', alliance_name='Test Alliance')
corp_name='Test Corp', alliance_name='Test Alliance')
cls.guest_state = get_guest_state()
cls.test_character = EveCharacter.objects.get(character_id='1')
cls.test_corporation = EveCorporationInfo.objects.create(corporation_id='1', corporation_name='Test Corp',
corporation_ticker='TEST', member_count=1)
corporation_ticker='TEST', member_count=1)
cls.test_alliance = EveAllianceInfo.objects.create(alliance_id='1', alliance_name='Test Alliance',
alliance_ticker='TEST', executor_corp_id='1')
cls.member_state = State.objects.create(
@ -215,7 +215,7 @@ class CharacterOwnershipCheckTestCase(TestCase):
def setUpTestData(cls):
cls.user = AuthUtils.create_user('test_user', disconnect_signals=True)
AuthUtils.add_main_character(cls.user, 'Test Character', '1', corp_id='1', alliance_id='1',
corp_name='Test Corp', alliance_name='Test Alliance')
corp_name='Test Corp', alliance_name='Test Alliance')
cls.character = EveCharacter.objects.get(character_id=1)
cls.token = Token.objects.create(
user=cls.user,

View File

@ -186,7 +186,7 @@ class ActivationView(BaseActivationView):
def validate_key(self, activation_key):
try:
dump = signing.loads(activation_key, salt=REGISTRATION_SALT,
max_age=settings.ACCOUNT_ACTIVATION_DAYS * 86400)
max_age=settings.ACCOUNT_ACTIVATION_DAYS * 86400)
return dump
except signing.BadSignature:
return None

View File

@ -6,11 +6,13 @@ from allianceauth.corputils import urls
class CorpStats(MenuItemHook):
def __init__(self):
MenuItemHook.__init__(self,
_('Corporation Stats'),
'fas fa-share-alt fa-fw',
'corputils:view',
navactive=['corputils:'])
MenuItemHook.__init__(
self,
_('Corporation Stats'),
'fas fa-share-alt fa-fw',
'corputils:view',
navactive=['corputils:']
)
def render(self, request):
if request.user.has_perm('corputils.view_corp_corpstats') or request.user.has_perm(

View File

@ -12,8 +12,7 @@ def convert_json_to_members(apps, schema_editor):
for cs in CorpStats.objects.all():
members = json.loads(cs._members)
CorpMember.objects.bulk_create(
[CorpMember(corpstats=cs, character_id=member_id, character_name=member_name) for member_id, member_name in
members.items()]
[CorpMember(corpstats=cs, character_id=member_id, character_name=member_name) for member_id, member_name in members.items()]
)

View File

@ -6,8 +6,7 @@ from bravado.exception import HTTPForbidden
from django.db import models
from esi.errors import TokenError
from esi.models import Token
from allianceauth.eveonline.models import EveCorporationInfo, EveCharacter,\
EveAllianceInfo
from allianceauth.eveonline.models import EveCorporationInfo, EveCharacter, EveAllianceInfo
from allianceauth.notifications import notify
from allianceauth.corputils.managers import CorpStatsManager
@ -49,8 +48,7 @@ class CorpStats(models.Model):
def update(self):
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)
assert c.Character.get_characters_character_id(character_id=self.token.character_id).result()['corporation_id'] == int(self.corp.corporation_id)
member_ids = c.Corporation.get_corporations_corporation_id_members(
corporation_id=self.corp.corporation_id).result()
@ -58,18 +56,15 @@ class CorpStats(models.Model):
# the swagger spec doesn't have a maxItems count
# manual testing says we can do over 350, but let's not risk it
member_id_chunks = [member_ids[i:i + 255] for i in range(0, len(member_ids), 255)]
member_name_chunks = [c.Universe.post_universe_names(ids=id_chunk).result() for id_chunk in
member_id_chunks]
member_name_chunks = [c.Universe.post_universe_names(ids=id_chunk).result() for id_chunk in member_id_chunks]
member_list = {}
for name_chunk in member_name_chunks:
member_list.update({m['id']: m['name'] for m in name_chunk})
# bulk create new member models
missing_members = [m_id for m_id in member_ids if
not CorpMember.objects.filter(corpstats=self, character_id=m_id).exists()]
missing_members = [m_id for m_id in member_ids if not CorpMember.objects.filter(corpstats=self, character_id=m_id).exists()]
CorpMember.objects.bulk_create(
[CorpMember(character_id=m_id, character_name=member_list[m_id], corpstats=self) for m_id in
missing_members])
[CorpMember(character_id=m_id, character_name=member_list[m_id], corpstats=self) for m_id in missing_members])
# purge old members
self.members.exclude(character_id__in=member_ids).delete()
@ -80,21 +75,22 @@ class CorpStats(models.Model):
except TokenError as e:
logger.warning("%s failed to update: %s" % (self, e))
if self.token.user:
notify(self.token.user, "%s failed to update with your ESI token." % self,
message="Your token has expired or is no longer valid. Please add a new one to create a new CorpStats.",
level="error")
notify(
self.token.user, "%s failed to update with your ESI token." % self,
message="Your token has expired or is no longer valid. Please add a new one to create a new CorpStats.",
level="error")
self.delete()
except HTTPForbidden as e:
logger.warning("%s failed to update: %s" % (self, e))
if self.token.user:
notify(self.token.user, "%s failed to update with your ESI token." % self,
message="%s: %s" % (e.status_code, e.message), level="error")
notify(self.token.user, "%s failed to update with your ESI token." % self, message="%s: %s" % (e.status_code, e.message), level="error")
self.delete()
except AssertionError:
logger.warning("%s token character no longer in corp." % self)
if self.token.user:
notify(self.token.user, "%s cannot update with your ESI token." % self,
message="%s cannot update with your ESI token as you have left corp." % self, level="error")
notify(
self.token.user, "%s cannot update with your ESI token." % self,
message="%s cannot update with your ESI token as you have left corp." % self, level="error")
self.delete()
@property
@ -127,9 +123,7 @@ class CorpStats(models.Model):
@property
def mains(self):
return self.members.filter(pk__in=[m.pk for m in self.members.all() if
m.main_character and int(m.main_character.character_id) == int(
m.character_id)])
return self.members.filter(pk__in=[m.pk for m in self.members.all() if m.main_character and int(m.main_character.character_id) == int(m.character_id)])
def visible_to(self, user):
return CorpStats.objects.filter(pk=self.pk).visible_to(user).exists()

View File

@ -58,8 +58,7 @@
{% for id, main in mains.items %}
<tr>
<td class="text-center" style="vertical-align:middle">
<div class="thumbnail"
style="border: 0 none; box-shadow: none; background: transparent;">
<div class="thumbnail" style="border: 0 none; box-shadow: none; background: transparent;">
<img src="{{ main.main.portrait_url_64 }}" class="img-circle">
<div class="caption text-center">
{{ main.main }}
@ -88,8 +87,7 @@
<td class="text-center" style="width:30%">{{ alt.corporation_name }}</td>
<td class="text-center" style="width:30%">{{ alt.alliance_name }}</td>
<td class="text-center" style="width:5%">
<a href="https://zkillboard.com/character/{{ alt.character_id }}/"
class="label label-danger" target="_blank">
<a href="https://zkillboard.com/character/{{ alt.character_id }}/" class="label label-danger" target="_blank">
{% trans "Killboard" %}
</a>
</td>
@ -123,10 +121,9 @@
<tr>
<td><img src="{{ member.portrait_url }}" class="img-circle"></td>
<td class="text-center">{{ member }}</td>
<td class="text-center"><a
href="https://zkillboard.com/character/{{ member.character_id }}/"
class="label label-danger"
target="_blank">{% trans "Killboard" %}</a></td>
<td class="text-center">
<a href="https://zkillboard.com/character/{{ member.character_id }}/" class="label label-danger" target="_blank">{% trans "Killboard" %}</a>
</td>
<td class="text-center">{{ member.character_ownership.user.profile.main_character.character_name }}</td>
<td class="text-center">{{ member.character_ownership.user.profile.main_character.corporation_name }}</td>
<td class="text-center">{{ member.character_ownership.user.profile.main_character.alliance_name }}</td>
@ -136,10 +133,9 @@
<tr class="danger">
<td><img src="{{ member.portrait_url }}" class="img-circle"></td>
<td class="text-center">{{ member.character_name }}</td>
<td class="text-center"><a
href="https://zkillboard.com/character/{{ member.character_id }}/"
class="label label-danger"
target="_blank">{% trans "Killboard" %}</a></td>
<td class="text-center">
<a href="https://zkillboard.com/character/{{ member.character_id }}/" class="label label-danger" target="_blank">{% trans "Killboard" %}</a>
</td>
<td class="text-center"></td>
<td class="text-center"></td>
<td class="text-center"></td>
@ -167,9 +163,7 @@
<td><img src="{{ member.portrait_url }}" class="img-circle"></td>
<td class="text-center">{{ member.character_name }}</td>
<td class="text-center">
<a href="https://zkillboard.com/character/{{ member.character_id }}/"
class="label label-danger"
target="_blank">
<a href="https://zkillboard.com/character/{{ member.character_id }}/" class="label label-danger" target="_blank">
{% trans "Killboard" %}
</a>
</td>

View File

@ -96,7 +96,7 @@ def corpstats_view(request, corp_id=None):
character_ownership__user__profile__main_character__corporation_id=corpstats.corp.corporation_id)
linked_chars = linked_chars.select_related('character_ownership',
'character_ownership__user__profile__main_character') \
'character_ownership__user__profile__main_character') \
.prefetch_related('character_ownership__user__character_ownerships') \
.prefetch_related('character_ownership__user__character_ownerships__character')

View File

@ -31,8 +31,8 @@ class AutogroupsConfigAdmin(admin.ModelAdmin):
def get_actions(self, request):
actions = super(AutogroupsConfigAdmin, self).get_actions(request)
actions['sync_user_groups'] = (sync_user_groups,
'sync_user_groups',
'Sync all users groups for this Autogroup Config')
'sync_user_groups',
'Sync all users groups for this Autogroup Config')
return actions

View File

@ -57,25 +57,21 @@ class AutogroupsConfig(models.Model):
states = models.ManyToManyField(State, related_name='autogroups')
corp_groups = models.BooleanField(default=False,
help_text="Setting this to false will delete all the created groups.")
corp_groups = models.BooleanField(default=False, help_text="Setting this to false will delete all the created groups.")
corp_group_prefix = models.CharField(max_length=50, default='Corp ', blank=True)
corp_name_source = models.CharField(max_length=20, choices=NAME_OPTIONS, default=OPT_NAME)
alliance_groups = models.BooleanField(default=False,
help_text="Setting this to false will delete all the created groups.")
alliance_groups = models.BooleanField(default=False, help_text="Setting this to false will delete all the created groups.")
alliance_group_prefix = models.CharField(max_length=50, default='Alliance ', blank=True)
alliance_name_source = models.CharField(max_length=20, choices=NAME_OPTIONS, default=OPT_NAME)
corp_managed_groups = models.ManyToManyField(
Group, through='ManagedCorpGroup', related_name='corp_managed_config',
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.')
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.')
alliance_managed_groups = models.ManyToManyField(
Group, through='ManagedAllianceGroup', related_name='alliance_managed_config',
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.')
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.')
replace_spaces = models.BooleanField(default=False)
replace_spaces_with = models.CharField(

View File

@ -91,9 +91,7 @@ class EveCorporationInfo(models.Model):
provider = EveCorporationProviderManager()
class Meta:
indexes = [
models.Index(fields=['ceo_id',]),
]
indexes = [models.Index(fields=['ceo_id',]),]
def update_corporation(self, corp: providers.Corporation = None):
if corp is None:
@ -157,11 +155,11 @@ class EveCharacter(models.Model):
class Meta:
indexes = [
models.Index(fields=['corporation_id',]),
models.Index(fields=['alliance_id',]),
models.Index(fields=['corporation_name',]),
models.Index(fields=['alliance_name',]),
]
models.Index(fields=['corporation_id',]),
models.Index(fields=['alliance_id',]),
models.Index(fields=['corporation_name',]),
models.Index(fields=['alliance_name',]),
]
@property
def alliance(self) -> Union[EveAllianceInfo, None]:

View File

@ -5,5 +5,4 @@ from django.utils.translation import ugettext_lazy as _
class FatlinkForm(forms.Form):
fleet = forms.CharField(label=_("Fleet Name"), max_length=50)
duration = forms.IntegerField(label=_("Duration of fat-link"), required=True, initial=30, min_value=1,
max_value=2147483647, help_text=_('minutes'))
duration = forms.IntegerField(label=_("Duration of fat-link"), required=True, initial=30, min_value=1, max_value=2147483647, help_text=_('minutes'))

View File

@ -12,7 +12,7 @@
<div class="panel-heading">{{ character_name }}</div>
<div class="panel-body">
<div class="col-lg-2 col-sm-2">
<img class="ra-avatar img-responsive" src="{{ character_portrait_url }}">
<img class="ra-avatar img-responsive" src="{{ character_portrait_url }}">
</div>
<div class="col-lg-10 col-sm-2">
<div class="alert alert-danger" role="alert">{% trans "Character not registered!" %}</div>

View File

@ -23,7 +23,7 @@
<th class="col-md-2 text-center">{% trans "Characters" %}</th>
<th class="col-md-2 text-center">{% trans "Fats" %}</th>
<th class="col-md-2 text-center">{% trans "Average fats" %}
<i class="glyphicon glyphicon-question-sign" rel="tooltip" title="Fats ÷ Characters"></i>
<i class="glyphicon glyphicon-question-sign" rel="tooltip" title="Fats ÷ Characters"></i>
</th>
</tr>
{% for memberStat in fatStats %}

View File

@ -24,7 +24,7 @@
<th class="col-md-2 text-center">{% trans "Members" %}</th>
<th class="col-md-2 text-center">{% trans "Fats" %}</th>
<th class="col-md-2 text-center">{% trans "Average fats" %}
<i class="glyphicon glyphicon-question-sign" rel="tooltip" title="Fats ÷ Characters"></i>
<i class="glyphicon glyphicon-question-sign" rel="tooltip" title="Fats ÷ Characters"></i>
</th>
</tr>
{% for corpStat in fatStats %}

View File

@ -135,8 +135,7 @@ def fatlink_statistics_corp_view(request, corpid, year=None, month=None):
stat_list.sort(key=lambda stat: stat.mainchar.character_name)
stat_list.sort(key=lambda stat: (stat.n_fats, stat.avg_fat), reverse=True)
context = {'fatStats': stat_list, 'month': start_of_month.strftime("%B"), 'year': year,
'previous_month': start_of_previous_month, 'corpid': corpid}
context = {'fatStats': stat_list, 'month': start_of_month.strftime("%B"), 'year': year, 'previous_month': start_of_previous_month, 'corpid': corpid}
if datetime.datetime.now() > start_of_next_month:
context.update({'next_month': start_of_next_month})
@ -163,16 +162,14 @@ def fatlink_statistics_view(request, year=datetime.date.today().year, month=date
for fat in fats_in_span.exclude(character__corporation_id__in=fat_stats):
if EveCorporationInfo.objects.filter(corporation_id=fat.character.corporation_id).exists():
fat_stats[fat.character.corporation_id] = CorpStat(fat.character.corporation_id, start_of_month,
start_of_next_month)
fat_stats[fat.character.corporation_id] = CorpStat(fat.character.corporation_id, start_of_month, start_of_next_month)
# collect and sort stats
stat_list = [fat_stats[x] for x in fat_stats]
stat_list.sort(key=lambda stat: stat.corp.corporation_name)
stat_list.sort(key=lambda stat: (stat.n_fats, stat.avg_fat), reverse=True)
context = {'fatStats': stat_list, 'month': start_of_month.strftime("%B"), 'year': year,
'previous_month': start_of_previous_month}
context = {'fatStats': stat_list, 'month': start_of_month.strftime("%B"), 'year': year, 'previous_month': start_of_previous_month}
if datetime.datetime.now() > start_of_next_month:
context.update({'next_month': start_of_next_month})
@ -199,8 +196,7 @@ def fatlink_personal_statistics_view(request, year=datetime.date.today().year):
monthlystats = [(i + 1, datetime.date(year, i + 1, 1).strftime("%h"), monthlystats[i]) for i in range(12)]
if datetime.datetime.now() > datetime.datetime(year + 1, 1, 1):
context = {'user': user, 'monthlystats': monthlystats, 'year': year, 'previous_year': year - 1,
'next_year': year + 1}
context = {'user': user, 'monthlystats': monthlystats, 'year': year, 'previous_year': year - 1, 'next_year': year + 1}
else:
context = {'user': user, 'monthlystats': monthlystats, 'year': year, 'previous_year': year - 1}
@ -229,9 +225,11 @@ def fatlink_monthly_personal_statistics_view(request, year, month, char_id=None)
for fat in personal_fats:
ship_statistics[fat.shiptype] = ship_statistics.setdefault(fat.shiptype, 0) + 1
n_fats += 1
context = {'user': user, 'shipStats': sorted(ship_statistics.items()), 'month': start_of_month.strftime("%h"),
'year': year, 'n_fats': n_fats, 'char_id': char_id, 'previous_month': start_of_previous_month,
'next_month': start_of_next_month}
context = {
'user': user, 'shipStats': sorted(ship_statistics.items()), 'month': start_of_month.strftime("%h"),
'year': year, 'n_fats': n_fats, 'char_id': char_id, 'previous_month': start_of_previous_month,
'next_month': start_of_next_month
}
created_fats = Fatlink.objects.filter(creator=user).filter(fatdatetime__gte=start_of_month).filter(
fatdatetime__lt=start_of_next_month)
@ -257,8 +255,7 @@ def click_fatlink_view(request, token, fat_hash=None):
location = c.Location.get_characters_character_id_location(character_id=token.character_id).result()
ship = c.Location.get_characters_character_id_ship(character_id=token.character_id).result()
location['solar_system_name'] = \
c.Universe.get_universe_systems_system_id(system_id=location['solar_system_id']).result()[
'name']
c.Universe.get_universe_systems_system_id(system_id=location['solar_system_id']).result()['name']
if location['station_id']:
location['station_name'] = \
c.Universe.get_universe_stations_station_id(station_id=location['station_id']).result()['name']

View File

@ -45,7 +45,7 @@ class GroupManager:
@staticmethod
def get_group_leaders_groups(user: User):
return Group.objects.select_related('authgroup').filter(authgroup__group_leaders__in=[user]) | \
Group.objects.select_related('authgroup').filter(authgroup__group_leader_groups__in=user.groups.all())
Group.objects.select_related('authgroup').filter(authgroup__group_leader_groups__in=user.groups.all())
@staticmethod
def joinable_group(group: Group, state: State) -> bool:

View File

@ -60,8 +60,7 @@ def reverse_group_models(apps, schema_editor):
pass
if len(group.authgroup.description):
GroupDescription.objects.update_or_create(group=group,
defaults={'description': group.authgroup.description})
GroupDescription.objects.update_or_create(group=group, defaults={'description': group.authgroup.description})
class Migration(migrations.Migration):
@ -76,8 +75,7 @@ class Migration(migrations.Migration):
migrations.CreateModel(
name='AuthGroup',
fields=[
('group', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, primary_key=True,
serialize=False, to='auth.Group')),
('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.')),

View File

@ -79,33 +79,32 @@ class AuthGroup(models.Model):
group = models.OneToOneField(Group, on_delete=models.CASCADE, primary_key=True)
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.")
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.")
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.")
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.")
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 leaders have management access to this group
group_leaders = models.ManyToManyField(User, related_name='leads_groups', blank=True,
help_text="Group leaders can process group requests for this group "
"specifically. Use the auth.group_management permission to allow "
"a user to manage all groups.")
help_text="Group leaders can process group requests for this group "
"specifically. Use the auth.group_management permission to allow "
"a user to manage all groups.")
# allow groups to be *group leads*
group_leader_groups = models.ManyToManyField(Group, related_name='leads_group_groups', blank=True,
help_text="Group leaders can process group requests for this group "
"specifically. Use the auth.group_management permission to allow "
"a user to manage all groups.")
help_text="Group leaders can process group requests for this group "
"specifically. Use the auth.group_management permission to allow "
"a user to manage all groups.")
states = models.ManyToManyField(State, related_name='valid_states', blank=True,
help_text="States listed here will have the ability to join this group provided "
"they have the proper permissions.")
"they have the proper permissions.")
description = models.TextField(max_length=512, blank=True, help_text="Short description <i>(max. 512 characters)</i> of the group shown to users.")

View File

@ -78,8 +78,7 @@ def group_membership_audit(request, group_id):
# Check its a joinable group i.e. not corp or internal
# And the user has permission to manage it
if not GroupManager.check_internal_group(group) or not GroupManager.can_manage_group(request.user, group):
logger.warning("User %s attempted to view the membership of group %s but permission was denied" %
(request.user, group_id))
logger.warning("User %s attempted to view the membership of group %s but permission was denied" % (request.user, group_id))
raise PermissionDenied
except ObjectDoesNotExist:
@ -140,15 +139,13 @@ def group_membership_list(request, group_id):
@login_required
@user_passes_test(GroupManager.can_manage_groups)
def group_membership_remove(request, group_id, user_id):
logger.debug("group_membership_remove called by user %s for group id %s on user id %s" %
(request.user, group_id, user_id))
logger.debug("group_membership_remove called by user %s for group id %s on user id %s" % (request.user, group_id, user_id))
group = get_object_or_404(Group, id=group_id)
try:
# Check its a joinable group i.e. not corp or internal
# And the user has permission to manage it
if not GroupManager.check_internal_group(group) or not GroupManager.can_manage_group(request.user, group):
logger.warning("User %s attempted to remove a user from group %s but permission was denied" % (request.user,
group_id))
logger.warning("User %s attempted to remove a user from group %s but permission was denied" % (request.user, group_id))
raise PermissionDenied
try:
@ -189,13 +186,12 @@ def group_accept_request(request, group_request_id):
logger.info("User %s accepted group request from user %s to group %s" % (
request.user, group_request.user, group_request.group.name))
notify(group_request.user, "Group Application Accepted", level="success",
message="Your application to %s has been accepted." % group_request.group)
message="Your application to %s has been accepted." % group_request.group)
messages.success(request,
_('Accepted application from %(mainchar)s to %(group)s.') % {"mainchar": group_request.main_char, "group": group_request.group})
_('Accepted application from %(mainchar)s to %(group)s.') % {"mainchar": group_request.main_char, "group": group_request.group})
except PermissionDenied as p:
logger.warning("User %s attempted to accept group join request %s but permission was denied" %
(request.user, group_request_id))
logger.warning("User %s attempted to accept group join request %s but permission was denied" % (request.user, group_request_id))
raise p
except:
messages.error(request, _('An unhandled error occurred while processing the application from %(mainchar)s to %(group)s.') % {"mainchar": group_request.main_char, "group": group_request.group})
@ -221,14 +217,12 @@ def group_reject_request(request, group_request_id):
log = RequestLog(request_type=group_request.leave_request,group=group_request.group,request_info=group_request.__str__(),action=0,request_actor=request.user)
log.save()
group_request.delete()
notify(group_request.user, "Group Application Rejected", level="danger",
message="Your application to %s has been rejected." % group_request.group)
notify(group_request.user, "Group Application Rejected", level="danger", message="Your application to %s has been rejected." % group_request.group)
messages.success(request,
_('Rejected application from %(mainchar)s to %(group)s.') % {"mainchar": group_request.main_char, "group": group_request.group})
_('Rejected application from %(mainchar)s to %(group)s.') % {"mainchar": group_request.main_char, "group": group_request.group})
except PermissionDenied as p:
logger.warning("User %s attempted to reject group join request %s but permission was denied" %
(request.user, group_request_id))
logger.warning("User %s attempted to reject group join request %s but permission was denied" % (request.user, group_request_id))
raise p
except:
messages.error(request, _('An unhandled error occurred while processing the application from %(mainchar)s to %(group)s.') % {"mainchar": group_request.main_char, "group": group_request.group})
@ -258,12 +252,11 @@ def group_leave_accept_request(request, group_request_id):
logger.info("User %s accepted group leave request from user %s to group %s" % (
request.user, group_request.user, group_request.group.name))
notify(group_request.user, "Group Leave Request Accepted", level="success",
message="Your request to leave %s has been accepted." % group_request.group)
message="Your request to leave %s has been accepted." % group_request.group)
messages.success(request,
_('Accepted application from %(mainchar)s to leave %(group)s.') % {"mainchar": group_request.main_char, "group": group_request.group})
_('Accepted application from %(mainchar)s to leave %(group)s.') % {"mainchar": group_request.main_char, "group": group_request.group})
except PermissionDenied as p:
logger.warning("User %s attempted to accept group leave request %s but permission was denied" %
(request.user, group_request_id))
logger.warning("User %s attempted to accept group leave request %s but permission was denied" % (request.user, group_request_id))
raise p
except:
messages.error(request, _('An unhandled error occurred while processing the application from %(mainchar)s to leave %(group)s.') % {
@ -291,13 +284,11 @@ def group_leave_reject_request(request, group_request_id):
group_request.delete()
logger.info("User %s rejected group leave request from user %s for group %s" % (
request.user, group_request.user, group_request.group.name))
notify(group_request.user, "Group Leave Request Rejected", level="danger",
message="Your request to leave %s has been rejected." % group_request.group)
notify(group_request.user, "Group Leave Request Rejected", level="danger", message="Your request to leave %s has been rejected." % group_request.group)
messages.success(request, _('Rejected application from %(mainchar)s to leave %(group)s.') % {
"mainchar": group_request.main_char, "group": group_request.group})
except PermissionDenied as p:
logger.warning("User %s attempted to reject group leave request %s but permission was denied" %
(request.user, group_request_id))
logger.warning("User %s attempted to reject group leave request %s but permission was denied" % (request.user, group_request_id))
raise p
except:
messages.error(request, _('An unhandled error occurred while processing the application from %(mainchar)s to leave %(group)s.') % {
@ -337,20 +328,17 @@ def group_request_add(request, group_id):
group = Group.objects.get(id=group_id)
state = request.user.profile.state
if not GroupManager.joinable_group(group, state):
logger.warning("User %s attempted to join group id %s but it is not a joinable group" %
(request.user, group_id))
logger.warning("User %s attempted to join group id %s but it is not a joinable group" % (request.user, group_id))
messages.warning(request, _("You cannot join that group"))
return redirect('groupmanagement:groups')
if group in request.user.groups.all():
# User is already a member of this group.
logger.warning("User %s attempted to join group id %s but they are already a member." %
(request.user, group_id))
logger.warning("User %s attempted to join group id %s but they are already a member." % (request.user, group_id))
messages.warning(request, _("You are already a member of that group."))
return redirect('groupmanagement:groups')
if not request.user.has_perm('groupmanagement.request_groups') and not group.authgroup.public:
# Does not have the required permission, trying to join a non-public group
logger.warning("User %s attempted to join group id %s but it is not a public group" %
(request.user, group_id))
logger.warning("User %s attempted to join group id %s but it is not a public group" % (request.user, group_id))
messages.warning(request, _("You cannot join that group"))
return redirect('groupmanagement:groups')
if group.authgroup.open:
@ -381,13 +369,11 @@ def group_request_leave(request, group_id):
logger.debug("group_request_leave called by user %s for group id %s" % (request.user, group_id))
group = Group.objects.get(id=group_id)
if not GroupManager.check_internal_group(group):
logger.warning("User %s attempted to leave group id %s but it is not a joinable group" %
(request.user, group_id))
logger.warning("User %s attempted to leave group id %s but it is not a joinable group" % (request.user, group_id))
messages.warning(request, _("You cannot leave that group"))
return redirect('groupmanagement:groups')
if group not in request.user.groups.all():
logger.debug("User %s attempted to leave group id %s but they are not a member" %
(request.user, group_id))
logger.debug("User %s attempted to leave group id %s but they are not a member" % (request.user, group_id))
messages.warning(request, _("You are not a member of that group"))
return redirect('groupmanagement:groups')
if group.authgroup.open:

View File

@ -5,16 +5,16 @@ All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of Torchbox nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
3. Neither the name of Torchbox nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED

View File

@ -9,11 +9,12 @@ from .models import Application
class ApplicationsMenu(MenuItemHook):
def __init__(self):
MenuItemHook.__init__(self,
_('Applications'),
'far fa-file fa-fw',
'hrapplications:index',
navactive=['hrapplications:'])
MenuItemHook.__init__(
self,
_('Applications'),
'far fa-file fa-fw',
'hrapplications:index',
navactive=['hrapplications:'])
def render(self, request):
app_count = Application.objects.pending_requests_count_for_user(request.user)

View File

@ -42,14 +42,12 @@
{% endif %}
</td>
<td class="text-center">
<a href="{% url 'hrapplications:personal_view' personal_app.id %}"
class="btn btn-primary">
<a href="{% url 'hrapplications:personal_view' personal_app.id %}" class="btn btn-primary">
<span class="glyphicon glyphicon-eye-open"></span>
</a>
{% if personal_app.approved == None %}
<a href="{% url 'hrapplications:personal_removal' personal_app.id %}"
class="btn btn-danger">
<a href="{% url 'hrapplications:personal_removal' personal_app.id %}" class="btn btn-danger">
<span class="glyphicon glyphicon-remove"></span>
</a>
{% endif %}
@ -105,8 +103,7 @@
{% endif %}
</td>
<td class="text-center">
<a href="{% url 'hrapplications:view' app.id %}"
class="btn btn-primary">
<a href="{% url 'hrapplications:view' app.id %}" class="btn btn-primary">
<span class="glyphicon glyphicon-eye-open"></span>
</a>
</td>
@ -150,13 +147,11 @@
{% endif %}
</td>
<td class="text-center">
<a href="{% url 'hrapplications:view' app.id %}"
class="btn btn-primary">
<a href="{% url 'hrapplications:view' app.id %}" class="btn btn-primary">
<span class="glyphicon glyphicon-eye-open"></span>
</a>
{% if perms.hrapplications.delete_application %}
<a href="{% url 'hrapplications:remove' app.id %}"
class="btn btn-danger">
<a href="{% url 'hrapplications:remove' app.id %}" class="btn btn-danger">
<span class="glyphicon glyphicon-remove"></span>
</a>
{% endif %}
@ -175,18 +170,15 @@
{% if perms.auth.human_resources %}
<!-- Modal -->
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel"
aria-hidden="true">
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">&times;</span><span
class="sr-only">{% trans "Close" %}</span></button>
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">&times;</span><span class="sr-only">{% trans "Close" %}</span></button>
<h4 class="modal-title" id="myModalLabel">{% trans "Application Search" %}</h4>
</div>
<div class="modal-body">
<form class="form-signin" role="form"
action={% url 'hrapplications:search' %} method="POST">
<form class="form-signin" role="form" action={% url 'hrapplications:search' %} method="POST">
{% csrf_token %}
{{ search_form|bootstrap }}
<br/>

View File

@ -56,18 +56,15 @@
{% if perms.auth.human_resources %}
<!-- Modal -->
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel"
aria-hidden="true">
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">&times;</span><span
class="sr-only">{% trans "Close" %}</span></button>
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">&times;</span><span class="sr-only">{% trans "Close" %}</span></button>
<h4 class="modal-title" id="myModalLabel">{% trans "Application Search" %}</h4>
</div>
<div class="modal-body">
<form class="form-signin" role="form"
action={% url 'hrapplications:search' %} method="POST">
<form class="form-signin" role="form" action={% url 'hrapplications:search' %} method="POST">
{% csrf_token %}
{{ search_form|bootstrap }}
<br/>

View File

@ -49,8 +49,7 @@
{% for char in app.characters %}
<tr>
<td class="text-center">
<img class="ra-avatar img-responsive img-circle"
src="{{ char.portrait_url_32 }}">
<img class="ra-avatar img-responsive img-circle" src="{{ char.portrait_url_32 }}">
</td>
<td class="text-center">{{ char.character_name }}</td>
<td class="text-center">{{ char.corporation_name }}</td>
@ -77,25 +76,20 @@
{% if app.approved == None %}
{% if app.reviewer == user %}
{% if perms.hrapplications.approve_application %}
<a href="{% url 'hrapplications:approve' app.id %}"
class="btn btn-success">{% trans "Approve" %}</a>
<a href="{% url 'hrapplications:approve' app.id %}" class="btn btn-success">{% trans "Approve" %}</a>
{% endif %}
{% if perms.hrapplications.reject_application %}
<a href="{% url 'hrapplications:reject' app.id %}"
class="btn btn-danger">{% trans "Reject" %}</a>
<a href="{% url 'hrapplications:reject' app.id %}" class="btn btn-danger">{% trans "Reject" %}</a>
{% endif %}
{% if perms.hrapplications.delete_application %}
<a href="{% url 'hrapplications:remove' app.id %}"
class="btn btn-danger">{% trans "Delete" %}</a>
<a href="{% url 'hrapplications:remove' app.id %}" class="btn btn-danger">{% trans "Delete" %}</a>
{% endif %}
{% elif not app.reviewer %}
<a href="{% url 'hrapplications:mark_in_progress' app.id %}"
class="btn btn-warning">{% trans "Mark in Progress" %}</a>
<a href="{% url 'hrapplications:mark_in_progress' app.id %}" class="btn btn-warning">{% trans "Mark in Progress" %}</a>
{% endif %}
{% endif %}
{% if perms.hrapplications.add_applicationcomment %}
<button type="button" class="btn btn-primary" data-toggle="modal"
data-target="#myModal">{% trans "Comment" %}</button>
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#myModal">{% trans "Comment" %}</button>
{% endif %}
</div>
</div>
@ -104,15 +98,12 @@
<div class="panel panel-default">
<div class="panel-heading" role="tab" id="headingThree">
<h4 class="panel-title">
<a class="collapsed" data-toggle="collapse" data-parent="#accordion"
href="#collapseThree" aria-expanded="false"
aria-controls="collapseThree">
<a class="collapsed" data-toggle="collapse" data-parent="#accordion" href="#collapseThree" aria-expanded="false" aria-controls="collapseThree">
{% trans 'Comments' %} ({{ comments.count }})
</a>
</h4>
</div>
<div id="collapseThree" class="panel-collapse collapse" role="tabpanel"
aria-labelledby="headingThree">
<div id="collapseThree" class="panel-collapse collapse" role="tabpanel" aria-labelledby="headingThree">
<div class="panel-body">
{% for comment in comments %}
<div class="panel panel-default">
@ -136,8 +127,7 @@
</div>
</div>
{% if perms.hrapplications.add_applicationcomment %}
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel"
aria-hidden="true">
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">

View File

@ -63,15 +63,13 @@ def hr_application_create_view(request, form_id=None):
application.save()
for question in app_form.questions.all():
response = ApplicationResponse(question=question, application=application)
response.answer = "\n".join(request.POST.getlist(str(question.pk),
""))
response.answer = "\n".join(request.POST.getlist(str(question.pk), ""))
response.save()
logger.info("%s created %s" % (request.user, application))
return redirect('hrapplications:personal_view', application.id)
else:
questions = app_form.questions.all()
return render(request, 'hrapplications/create.html',
context={'questions': questions, 'corp': app_form.corp})
return render(request, 'hrapplications/create.html', context={'questions': questions, 'corp': app_form.corp})
else:
choices = []
for app_form in ApplicationForm.objects.all():
@ -171,8 +169,7 @@ def hr_application_approve(request, app_id):
logger.info("User %s approving %s" % (request.user, app))
app.approved = True
app.save()
notify(app.user, "Application Accepted", message="Your application to %s has been approved." % app.form.corp,
level="success")
notify(app.user, "Application Accepted", message="Your application to %s has been approved." % app.form.corp, level="success")
else:
logger.warn("User %s not authorized to approve %s" % (request.user, app))
return redirect('hrapplications:index')
@ -188,8 +185,7 @@ def hr_application_reject(request, app_id):
logger.info("User %s rejecting %s" % (request.user, app))
app.approved = False
app.save()
notify(app.user, "Application Rejected", message="Your application to %s has been rejected." % app.form.corp,
level="danger")
notify(app.user, "Application Rejected", message="Your application to %s has been rejected." % app.form.corp, level="danger")
else:
logger.warn("User %s not authorized to reject %s" % (request.user, app))
return redirect('hrapplications:index')
@ -248,8 +244,7 @@ def hr_application_mark_in_progress(request, app_id):
app.reviewer = request.user
app.reviewer_character = request.user.profile.main_character
app.save()
notify(app.user, "Application In Progress",
message="Your application to %s is being reviewed by %s" % (app.form.corp, app.reviewer_str))
notify(app.user, "Application In Progress", message="Your application to %s is being reviewed by %s" % (app.form.corp, app.reviewer_str))
else:
logger.warn(
"User %s unable to mark %s in progress: already being reviewed by %s" % (request.user, app, app.reviewer))

View File

@ -18,10 +18,8 @@
<li><a data-toggle="pill" href="#read">{% trans "Read" %} <b>({{ read|length }})</b></a>
</li>
<div class="pull-right">
<a href="{% url 'notifications:mark_all_read' %}"
class="btn btn-primary">{% trans "Mark All Read" %}</a>
<a href="{% url 'notifications:delete_all_read' %}"
class="btn btn-danger">{% trans "Delete All Read" %}</a>
<a href="{% url 'notifications:mark_all_read' %}" class="btn btn-primary">{% trans "Mark All Read" %}</a>
<a href="{% url 'notifications:delete_all_read' %}" class="btn btn-danger">{% trans "Delete All Read" %}</a>
</div>
</ul>
</div>
@ -41,12 +39,10 @@
<td class="text-center">{{ notif.timestamp }}</td>
<td class="text-center">{{ notif.title }}</td>
<td class="text-center">
<a href="{% url 'notifications:view' notif.id %}"
class="btn btn-success" title="View">
<a href="{% url 'notifications:view' notif.id %}" class="btn btn-success" title="View">
<span class="glyphicon glyphicon-eye-open"></span>
</a>
<a href="{% url 'notifications:remove' notif.id %}"
class="btn btn-danger" title="Remove">
<a href="{% url 'notifications:remove' notif.id %}" class="btn btn-danger" title="Remove">
<span class="glyphicon glyphicon-remove"></span>
</a>
</td>
@ -73,12 +69,10 @@
<td class="text-center">{{ notif.timestamp }}</td>
<td class="text-center">{{ notif.title }}</td>
<td class="text-center">
<a href="{% url 'notifications:view' notif.id %}"
class="btn btn-success" title="View">
<a href="{% url 'notifications:view' notif.id %}" class="btn btn-success" title="View">
<span class="glyphicon glyphicon-eye-open"></span>
</a>
<a href="{% url 'notifications:remove' notif.id %}"
class="btn btn-danger" title="remove">
<a href="{% url 'notifications:remove' notif.id %}" class="btn btn-danger" title="remove">
<span class="glyphicon glyphicon-remove"></span>
</a>
</td>

View File

@ -6,10 +6,12 @@ from . import urls
class OpTimerboardMenu(MenuItemHook):
def __init__(self):
MenuItemHook.__init__(self, _('Fleet Operations'),
'fas fa-exclamation fa-fw',
'optimer:view',
navactive=['optimer:'])
MenuItemHook.__init__(
self, _('Fleet Operations'),
'fas fa-exclamation fa-fw',
'optimer:view',
navactive=['optimer:']
)
def render(self, request):
if request.user.has_perm('auth.optimer_view'):

View File

@ -2,7 +2,7 @@
{% load evelinks %}
{% block content %}
<div class="table-responsive">
<div class="table-responsive">
<table class="table">
<thead>
<tr>

View File

@ -6,12 +6,14 @@ from allianceauth.services.hooks import MenuItemHook, UrlHook
class PermissionsTool(MenuItemHook):
def __init__(self):
MenuItemHook.__init__(self,
'Permissions Audit',
'fas fa-id-card fa-fw',
'permissions_tool:overview',
order=400,
navactive=['permissions_tool:'])
MenuItemHook.__init__(
self,
'Permissions Audit',
'fas fa-id-card fa-fw',
'permissions_tool:overview',
order=400,
navactive=['permissions_tool:']
)
def render(self, request):
if request.user.has_perm('permissions_tool.audit_permissions'):

View File

@ -40,8 +40,7 @@ class PermissionsToolViewsTestCase(WebTest):
response_content = response.content.decode('utf-8')
self.assertInHTML('<li><a class="active" href="/permissions/overview/">'
'<i class="fas fa-id-card fa-fw"></i> Permissions Audit</a></li>', response_content)
self.assertInHTML('<li><a class="active" href="/permissions/overview/"><i class="fas fa-id-card fa-fw"></i> Permissions Audit</a></li>', response_content)
def test_permissions_overview(self):
self.app.set_user(self.member)

View File

@ -47,7 +47,7 @@ def permissions_audit(request, app_label, model, codename):
try:
perm = Permission.objects\
.prefetch_related('group_set', 'user_set', 'state_set',
'state_set__userprofile_set', 'group_set__user_set', 'state_set__userprofile_set__user')\
'state_set__userprofile_set', 'group_set__user_set', 'state_set__userprofile_set__user')\
.get(content_type__app_label=app_label, content_type__model=model, codename=codename)
except Permission.DoesNotExist:
raise Http404

View File

@ -130,8 +130,10 @@ AUTH_PASSWORD_VALIDATORS = [
},
]
AUTHENTICATION_BACKENDS = ['allianceauth.authentication.backends.StateBackend',
'django.contrib.auth.backends.ModelBackend']
AUTHENTICATION_BACKENDS = [
'allianceauth.authentication.backends.StateBackend',
'django.contrib.auth.backends.ModelBackend'
]
# Internationalization
# https://docs.djangoproject.com/en/1.10/topics/i18n/

View File

@ -72,8 +72,7 @@ class BaseCreatePasswordServiceAccountView(BaseServiceView, ServiceCredentialsVi
messages.error(request, _("That service account already exists"))
return redirect(self.index_redirect)
return render(request, self.template_name,
context={'credentials': svc_obj.credentials, 'service': self.service_name, 'view': self})
return render(request, self.template_name, context={'credentials': svc_obj.credentials, 'service': self.service_name, 'view': self})
class ServicesCRUDMixin(SingleObjectMixin):
@ -112,5 +111,4 @@ class BaseResetPasswordServiceAccountView(ServicesCRUDMixin, BaseServiceView, Se
def get(self, request):
svc_obj = self.get_object()
svc_obj.reset_password()
return render(request, self.template_name,
context={'credentials': svc_obj.credentials, 'service': self.service_name, 'view': self})
return render(request, self.template_name, context={'credentials': svc_obj.credentials, 'service': self.service_name, 'view': self})

View File

@ -7,10 +7,12 @@ from .hooks import ServicesHook
class Services(MenuItemHook):
def __init__(self):
MenuItemHook.__init__(self,
_('Services'),
'fas fa-cogs fa-fw',
'services:services', 100)
MenuItemHook.__init__(
self,
_('Services'),
'fas fa-cogs fa-fw',
'services:services', 100
)
def render(self, request):
for svc in ServicesHook.get_services():

View File

@ -12,10 +12,8 @@ class FleetFormatterForm(forms.Form):
formup_time = forms.CharField(label=_('Formup Time:'), required=True)
expected_duration = forms.CharField(label=_('Expected Duration:'), required=True)
purpose = forms.CharField(label=_('Purpose:'), required=True)
reimbursable = forms.ChoiceField(label=_('Reimbursable?*'), choices=[(_('Yes'), _('Yes')), (_('No'), _('No'))],
required=True)
important = forms.ChoiceField(label=_('Important?*'), choices=[(_('Yes'), _('Yes')), (_('No'), _('No'))],
required=True)
reimbursable = forms.ChoiceField(label=_('Reimbursable?*'), choices=[(_('Yes'), _('Yes')), (_('No'), _('No'))], required=True)
important = forms.ChoiceField(label=_('Important?*'), choices=[(_('Yes'), _('Yes')), (_('No'), _('No'))], required=True)
comments = forms.CharField(label=_('Comments'), widget=forms.Textarea, required=False)

View File

@ -181,8 +181,7 @@ class NameFormatter:
main_char = getattr(self.user.profile, 'main_character', None)
format_data = {
'character_name': getattr(main_char, 'character_name',
self.user.username if self._default_to_username else None),
'character_name': getattr(main_char, 'character_name', self.user.username if self._default_to_username else None),
'character_id': getattr(main_char, 'character_id', None),
'corp_ticker': getattr(main_char, 'corporation_ticker', None),
'corp_name': getattr(main_char, 'corporation_name', None),

View File

@ -125,8 +125,7 @@ class DiscourseManager:
@staticmethod
def __suspend_user(username):
u_id = DiscourseManager.__user_name_to_id(username)
return providers.discourse.client.suspend(u_id, DiscourseManager.SUSPEND_DAYS,
DiscourseManager.SUSPEND_REASON)
return providers.discourse.client.suspend(u_id, DiscourseManager.SUSPEND_DAYS, DiscourseManager.SUSPEND_REASON)
@staticmethod
def __unsuspend(username):

View File

@ -14,7 +14,7 @@ TABLE_PREFIX = getattr(settings, 'IPS4_TABLE_PREFIX', '')
class Ips4Manager:
SQL_ADD_USER = r"INSERT INTO %score_members (name, email, members_pass_hash, members_pass_salt, " \
r"member_group_id) VALUES (%%s, %%s, %%s, %%s, %%s)" % TABLE_PREFIX
r"member_group_id) VALUES (%%s, %%s, %%s, %%s, %%s)" % TABLE_PREFIX
SQL_GET_ID = r"SELECT member_id FROM %score_members WHERE name = %%s" % TABLE_PREFIX
SQL_UPDATE_PASSWORD = r"UPDATE %score_members SET members_pass_hash = %%s, members_pass_salt = %%s WHERE name = %%s" % TABLE_PREFIX
SQL_DEL_USER = r"DELETE FROM %score_members WHERE member_id = %%s" % TABLE_PREFIX

View File

@ -33,8 +33,7 @@ def activate_ips4(request):
'username': result[0],
'password': result[1],
}
return render(request, 'services/service_credentials.html',
context={'credentials': credentials, 'service': 'IPSuite4'})
return render(request, 'services/service_credentials.html', context={'credentials': credentials, 'service': 'IPSuite4'})
else:
logger.error("Unsuccessful attempt to activate IPS4 for user %s" % request.user)
messages.error(request, _('An error occurred while processing your IPSuite4 account.'))
@ -55,8 +54,7 @@ def reset_ips4_password(request):
'username': request.user.ips4.username,
'password': result,
}
return render(request, 'services/service_credentials.html',
context={'credentials': credentials, 'service': 'IPSuite4'})
return render(request, 'services/service_credentials.html', context={'credentials': credentials, 'service': 'IPSuite4'})
logger.error("Unsuccessful attempt to reset IPS4 password for user %s" % request.user)
messages.error(request, _('An error occurred while processing your IPSuite4 account.'))

View File

@ -25,8 +25,7 @@ class MumbleHooksTestCase(TestCase):
def setUp(self):
self.member = 'member_user'
member = AuthUtils.create_member(self.member)
AuthUtils.add_main_character(member, 'auth_member', '12345', corp_id='111', corp_name='Test Corporation',
corp_ticker='TESTR')
AuthUtils.add_main_character(member, 'auth_member', '12345', corp_id='111', corp_name='Test Corporation', corp_ticker='TESTR')
member = User.objects.get(pk=member.pk)
MumbleUser.objects.create(user=member)
self.none_user = 'none_user'
@ -123,8 +122,7 @@ class MumbleViewsTestCase(TestCase):
self.member = AuthUtils.create_member('auth_member')
self.member.email = 'auth_member@example.com'
self.member.save()
AuthUtils.add_main_character(self.member, 'auth_member', '12345', corp_id='111', corp_name='Test Corporation',
corp_ticker='TESTR')
AuthUtils.add_main_character(self.member, 'auth_member', '12345', corp_id='111', corp_name='Test Corporation', corp_ticker='TESTR')
self.member = User.objects.get(pk=self.member.pk)
add_permissions()

View File

@ -74,10 +74,12 @@ def register_service():
class JabberBroadcast(MenuItemHook):
def __init__(self):
MenuItemHook.__init__(self,
_('Jabber Broadcast'),
'fas fa-bullhorn fa-fw',
'openfire:broadcast')
MenuItemHook.__init__(
self,
_('Jabber Broadcast'),
'fas fa-bullhorn fa-fw',
'openfire:broadcast'
)
def render(self, request):
if request.user.has_perm('auth.jabber_broadcast') or request.user.has_perm('auth.jabber_broadcast_all'):
@ -87,10 +89,12 @@ class JabberBroadcast(MenuItemHook):
class FleetBroadcastFormatter(MenuItemHook):
def __init__(self):
MenuItemHook.__init__(self,
_('Fleet Broadcast Formatter'),
'fas fa-space-shuttle fa-fw',
'services:fleet_format_tool')
MenuItemHook.__init__(
self,
_('Fleet Broadcast Formatter'),
'fas fa-space-shuttle fa-fw',
'services:fleet_format_tool'
)
def render(self, request):
if request.user.has_perm('auth.jabber_broadcast') or request.user.has_perm('auth.jabber_broadcast_all'):

View File

@ -208,8 +208,8 @@ class PingBot(sleekxmpp.ClientXMPP):
self.get_roster()
self.send_message(mto=self.recipient,
mbody=self.msg,
mtype='chat')
mbody=self.msg,
mtype='chat')
self.message_sent = True
# Using wait=True ensures that the send queue will be
# emptied before ending the session.

View File

@ -16,8 +16,7 @@
{% if success %}
<div class="alert alert-success" role="alert">{% trans "Broadcast Sent!!" %}</div>
{% endif %}
<form class="form-signin" role="form" action="" method="POST"
onsubmit="submitbutton.disabled = true; return true;">
<form class="form-signin" role="form" action="" method="POST" onsubmit="submitbutton.disabled = true; return true;">
{% csrf_token %}
{{ form|bootstrap }}
<br/>

View File

@ -37,8 +37,7 @@ def activate_jabber(request):
'username': info[0],
'password': info[1],
}
return render(request, 'services/service_credentials.html',
context={'credentials': credentials, 'service': 'Jabber'})
return render(request, 'services/service_credentials.html', context={'credentials': credentials, 'service': 'Jabber'})
else:
logger.error("Unsuccessful attempt to activate jabber for user %s" % request.user)
messages.error(request, _('An error occurred while processing your jabber account.'))
@ -72,8 +71,7 @@ def reset_jabber_password(request):
'username': request.user.openfire.username,
'password': result,
}
return render(request, 'services/service_credentials.html',
context={'credentials': credentials, 'service': 'Jabber'})
return render(request, 'services/service_credentials.html', context={'credentials': credentials, 'service': 'Jabber'})
logger.error("Unsuccessful attempt to reset jabber for user %s" % request.user)
messages.error(request, _('An error occurred while processing your jabber account.'))
return redirect("services:services")
@ -100,18 +98,16 @@ def jabber_broadcast_view(request):
logger.debug("Processing jabber broadcast for user %s with main character %s" % (request.user, main_char))
try:
if main_char is not None:
message_to_send = form.cleaned_data[
'message'] + "\n##### SENT BY: " + "[" + main_char.corporation_ticker + "]" + \
main_char.character_name + " TO: " + \
form.cleaned_data['group'] + " WHEN: " + datetime.datetime.utcnow().strftime(
"%Y-%m-%d %H:%M:%S") + " #####\n##### Replies are NOT monitored #####\n"
message_to_send = form.cleaned_data['message'] + "\n##### SENT BY: " + "[" + main_char.corporation_ticker + "]" + \
main_char.character_name + " TO: " + \
form.cleaned_data['group'] + " WHEN: " + datetime.datetime.utcnow().strftime(
"%Y-%m-%d %H:%M:%S") + " #####\n##### Replies are NOT monitored #####\n"
group_to_send = form.cleaned_data['group']
else:
message_to_send = form.cleaned_data[
'message'] + "\n##### SENT BY: " + "No character but can send pings?" + " TO: " + \
form.cleaned_data['group'] + " WHEN: " + datetime.datetime.utcnow().strftime(
"%Y-%m-%d %H:%M:%S") + " #####\n##### Replies are NOT monitored #####\n"
message_to_send = form.cleaned_data['message'] + "\n##### SENT BY: " + "No character but can send pings?" + " TO: " + \
form.cleaned_data['group'] + " WHEN: " + datetime.datetime.utcnow().strftime(
"%Y-%m-%d %H:%M:%S") + " #####\n##### Replies are NOT monitored #####\n"
group_to_send = form.cleaned_data['group']
OpenfireManager.send_broadcast_message(group_to_send, message_to_send)

View File

@ -19,9 +19,9 @@ TABLE_PREFIX = getattr(settings, 'PHPBB3_TABLE_PREFIX', 'phpbb_')
class Phpbb3Manager:
SQL_ADD_USER = r"INSERT INTO %susers (username, username_clean, " \
r"user_password, user_email, group_id, user_regdate, user_permissions, " \
r"user_sig, user_lang) VALUES (%%s, %%s, %%s, %%s, %%s, %%s, %%s, %%s, 'en')" % TABLE_PREFIX
SQL_ADD_USER = r"INSERT INTO %susers (username, username_clean, " \
r"user_password, user_email, group_id, user_regdate, user_permissions, " \
r"user_sig, user_lang) VALUES (%%s, %%s, %%s, %%s, %%s, %%s, %%s, %%s, 'en')" % TABLE_PREFIX
SQL_DEL_USER = r"DELETE FROM %susers where username = %%s" % TABLE_PREFIX
@ -42,10 +42,10 @@ class Phpbb3Manager:
SQL_GET_ALL_GROUPS = r"SELECT group_id, group_name FROM %sgroups" % TABLE_PREFIX
SQL_GET_USER_GROUPS = r"SELECT %(prefix)sgroups.group_name FROM %(prefix)sgroups , %(prefix)suser_group WHERE " \
r"%(prefix)suser_group.group_id = %(prefix)sgroups.group_id AND user_id=%%s" % {'prefix': TABLE_PREFIX}
r"%(prefix)suser_group.group_id = %(prefix)sgroups.group_id AND user_id=%%s" % {'prefix': TABLE_PREFIX}
SQL_ADD_USER_AVATAR = r"UPDATE %susers SET user_avatar_type=2, user_avatar_width=64, user_avatar_height=64, " \
"user_avatar=%%s WHERE user_id = %%s" % TABLE_PREFIX
"user_avatar=%%s WHERE user_id = %%s" % TABLE_PREFIX
SQL_CLEAR_USER_PERMISSIONS = r"UPDATE %susers SET user_permissions = '' WHERE user_id = %%s" % TABLE_PREFIX

View File

@ -36,8 +36,7 @@ def activate_forum(request):
'username': result[0],
'password': result[1],
}
return render(request, 'services/service_credentials.html',
context={'credentials': credentials, 'service': 'Forum'})
return render(request, 'services/service_credentials.html', context={'credentials': credentials, 'service': 'Forum'})
else:
logger.error("Unsuccessful attempt to activate forum for user %s" % request.user)
messages.error(request, _('An error occurred while processing your forum account.'))
@ -73,8 +72,7 @@ def reset_forum_password(request):
'username': request.user.phpbb3.username,
'password': result,
}
return render(request, 'services/service_credentials.html',
context={'credentials': credentials, 'service': 'Forum'})
return render(request, 'services/service_credentials.html', context={'credentials': credentials, 'service': 'Forum'})
logger.error("Unsuccessful attempt to reset forum password for user %s" % request.user)
messages.error(request, _('An error occurred while processing your forum account.'))

View File

@ -21,8 +21,8 @@ class SmfManager:
pass
SQL_ADD_USER = r"INSERT INTO %smembers (member_name, passwd, email_address, date_registered, real_name," \
r" buddy_list, message_labels, openid_uri, signature, ignore_boards) " \
r"VALUES (%%s, %%s, %%s, %%s, %%s, 0, 0, 0, 0, 0)" % TABLE_PREFIX
r" buddy_list, message_labels, openid_uri, signature, ignore_boards) " \
r"VALUES (%%s, %%s, %%s, %%s, %%s, 0, 0, 0, 0, 0)" % TABLE_PREFIX
SQL_DEL_USER = r"DELETE FROM %smembers where member_name = %%s" % TABLE_PREFIX
@ -159,7 +159,7 @@ class SmfManager:
else:
try:
cursor.execute(cls.SQL_ADD_USER,
[username_clean, passwd, email_address, register_date, username_clean])
[username_clean, passwd, email_address, register_date, username_clean])
cls.add_avatar(username_clean, characterid)
logger.info("Added smf member_name %s" % username_clean)
cls.update_groups(username_clean, groups)

View File

@ -23,8 +23,7 @@ def activate_smf(request):
# Valid now we get the main characters
character = request.user.profile.main_character
logger.debug("Adding smf user for user %s with main character %s" % (request.user, character))
result = SmfManager.add_user(SmfTasks.get_username(request.user), request.user.email, ['Member'],
character.character_id)
result = SmfManager.add_user(SmfTasks.get_username(request.user), request.user.email, ['Member'], character.character_id)
# if empty we failed
if result[0] != "":
SmfUser.objects.update_or_create(user=request.user, defaults={'username': result[0]})
@ -36,8 +35,7 @@ def activate_smf(request):
'username': result[0],
'password': result[1],
}
return render(request, 'services/service_credentials.html',
context={'credentials': credentials, 'service': 'SMF'})
return render(request, 'services/service_credentials.html', context={'credentials': credentials, 'service': 'SMF'})
else:
logger.error("Unsuccessful attempt to activate smf for user %s" % request.user)
messages.error(request, _('An error occurred while processing your SMF account.'))
@ -74,8 +72,7 @@ def reset_smf_password(request):
'username': request.user.smf.username,
'password': result,
}
return render(request, 'services/service_credentials.html',
context={'credentials': credentials, 'service': 'SMF'})
return render(request, 'services/service_credentials.html', context={'credentials': credentials, 'service': 'SMF'})
logger.error("Unsuccessful attempt to reset smf password for user %s" % request.user)
messages.error(request, _('An error occurred while processing your SMF account.'))
return redirect("services:services")
@ -93,8 +90,7 @@ def set_smf_password(request):
if form.is_valid() and SmfTasks.has_account(request.user) and character is not None:
password = form.cleaned_data['password']
logger.debug("Form contains password of length %s" % len(password))
result = SmfManager.update_user_password(request.user.smf.username, character.character_id,
password=password)
result = SmfManager.update_user_password(request.user.smf.username, character.character_id, password=password)
if result != "":
logger.info("Successfully set smf password for user %s" % request.user)
messages.success(request, _('Set SMF password.'))

View File

@ -85,14 +85,14 @@ class Teamspeak3Manager:
self.__group_cache = None
sgid = ret['keys']['sgid']
self.server.send_command('servergroupaddperm',
{'sgid': sgid, 'permsid': 'i_group_needed_modify_power', 'permvalue': 75,
'permnegated': 0, 'permskip': 0})
{'sgid': sgid, 'permsid': 'i_group_needed_modify_power', 'permvalue': 75,
'permnegated': 0, 'permskip': 0})
self.server.send_command('servergroupaddperm',
{'sgid': sgid, 'permsid': 'i_group_needed_member_add_power', 'permvalue': 100,
'permnegated': 0, 'permskip': 0})
{'sgid': sgid, 'permsid': 'i_group_needed_member_add_power', 'permvalue': 100,
'permnegated': 0, 'permskip': 0})
self.server.send_command('servergroupaddperm',
{'sgid': sgid, 'permsid': 'i_group_needed_member_remove_power', 'permvalue': 100,
'permnegated': 0, 'permskip': 0})
{'sgid': sgid, 'permsid': 'i_group_needed_member_remove_power', 'permvalue': 100,
'permnegated': 0, 'permskip': 0})
logger.info("Created group on TS3 server with name %s and id %s" % (groupname, sgid))
return sgid
@ -142,7 +142,7 @@ class Teamspeak3Manager:
if groupid not in user_groups.values():
logger.debug("User does not have group already. Issuing command to add.")
self.server.send_command('servergroupaddclient',
{'sgid': str(groupid), 'cldbid': uid})
{'sgid': str(groupid), 'cldbid': uid})
logger.info("Added user id %s to group id %s on TS3 server." % (uid, groupid))
def _remove_user_from_group(self, uid, groupid):
@ -152,7 +152,7 @@ class Teamspeak3Manager:
if str(groupid) in user_groups.values():
logger.debug("User is in group. Issuing command to remove.")
self.server.send_command('servergroupdelclient',
{'sgid': str(groupid), 'cldbid': uid})
{'sgid': str(groupid), 'cldbid': uid})
logger.info("Removed user id %s from group id %s on TS3 server." % (uid, groupid))
def _sync_ts_group_db(self):
@ -190,7 +190,7 @@ class Teamspeak3Manager:
state = user.profile.state.name
if state not in server_groups:
self._create_group(state)
self._create_group(state)
state_group_id = self._group_id_by_name(state)

View File

@ -11,16 +11,18 @@ class ConnectionError:
return 'Error connecting to host %s port %s' % (self.ip, self.port)
ts3_escape = {'/': r"\/",
' ': r'\s',
'|': r'\p',
"\a": r'\a',
"\b": r'\b',
"\f": r'\f',
"\n": r'\n',
"\r": r'\r',
"\t": r'\t',
"\v": r'\v'}
ts3_escape = {
'/': r"\/",
' ': r'\s',
'|': r'\p',
"\a": r'\a',
"\b": r'\b',
"\f": r'\f',
"\n": r'\n',
"\r": r'\r',
"\t": r'\t',
"\v": r'\v'
}
class TS3Proto:

View File

@ -55,8 +55,7 @@ def verify_teamspeak3(request):
form = TeamspeakJoinForm(initial={'username': request.user.teamspeak3.uid})
context = {
'form': form,
'authinfo': {'teamspeak3_uid': request.user.teamspeak3.uid,
'teamspeak3_perm_key': request.user.teamspeak3.perm_key},
'authinfo': {'teamspeak3_uid': request.user.teamspeak3.uid, 'teamspeak3_perm_key': request.user.teamspeak3.perm_key},
'public_url': settings.TEAMSPEAK3_PUBLIC_URL,
}
return render(request, 'services/teamspeak3/teamspeakjoin.html', context=context)

View File

@ -33,7 +33,7 @@ def activate_xenforo_forum(request):
'password': result['password'],
}
return render(request, 'services/service_credentials.html',
context={'credentials': credentials, 'service': 'XenForo'})
context={'credentials': credentials, 'service': 'XenForo'})
else:
logger.error("Unsuccessful attempt to activate xenforo for user %s" % request.user)
@ -68,7 +68,7 @@ def reset_xenforo_password(request):
'password': result['password'],
}
return render(request, 'services/service_credentials.html',
context={'credentials': credentials, 'service': 'XenForo'})
context={'credentials': credentials, 'service': 'XenForo'})
logger.error("Unsuccessful attempt to reset XenForo password for user %s" % request.user)
messages.error(request, _('An error occurred while processing your XenForo account.'))
return redirect("services:services")

View File

@ -75,8 +75,7 @@ def m2m_changed_group_permissions(sender, instance, action, pk_set, *args, **kwa
continue
for svc in ServicesHook.get_services():
if svc.access_perm == path_perm:
logger.debug("Permissions changed for group {} on "
"service {}, re-validating services for groups users".format(instance, svc))
logger.debug("Permissions changed for group {} on service {}, re-validating services for groups users".format(instance, svc))
def validate_all_groups_users_for_service():
logger.debug("Performing validation for service {}".format(svc))
@ -108,8 +107,7 @@ def m2m_changed_state_permissions(sender, instance, action, pk_set, *args, **kwa
continue
for svc in ServicesHook.get_services():
if svc.access_perm == path_perm:
logger.debug("Permissions changed for state {} on "
"service {}, re-validating services for state users".format(instance, svc))
logger.debug("Permissions changed for state {} on service {}, re-validating services for state users".format(instance, svc))
def validate_all_state_users_for_service():
logger.debug("Performing validation for service {}".format(svc))
@ -200,8 +198,8 @@ def process_main_character_update(sender, instance, *args, **kwargs):
)
old_instance = EveCharacter.objects.get(pk=instance.pk)
if not instance.character_name == old_instance.character_name or \
not instance.corporation_name == old_instance.corporation_name or \
not instance.alliance_name == old_instance.alliance_name:
not instance.corporation_name == old_instance.corporation_name or \
not instance.alliance_name == old_instance.alliance_name:
logger.info("syncing service nickname for user {0}".format(instance.userprofile.user))
for svc in ServicesHook.get_services():

View File

@ -11,8 +11,7 @@
<div class="container-fluid">
<div class="col-md-4 col-md-offset-4">
<div class="row">
<form class="form-signin" role="form" action="" method="POST"
onsubmit="submitbutton.disabled = true; return true;">
<form class="form-signin" role="form" action="" method="POST" onsubmit="submitbutton.disabled = true; return true;">
{% csrf_token %}
{{ form|bootstrap }}
<br/>

View File

@ -9,10 +9,12 @@ from .managers import SRPManager
class SrpMenu(MenuItemHook):
def __init__(self):
MenuItemHook.__init__(self, _('Ship Replacement'),
'far fa-money-bill-alt fa-fw',
'srp:management',
navactive=['srp:'])
MenuItemHook.__init__(
self, _('Ship Replacement'),
'far fa-money-bill-alt fa-fw',
'srp:management',
navactive=['srp:']
)
def render(self, request):
if request.user.has_perm('srp.access_srp'):

View File

@ -8,42 +8,42 @@
{% block extra_css %}
{% include 'bundles/datatables-css.html' %}
{% include 'bundles/x-editable.css.html' %}
<link href="{% static 'css/checkbox.css' %}" rel="stylesheet" type="text/css">
<style>
.copy-text-fa-icon:hover {
cursor: pointer;
}
.radio label, .checkbox label {
padding-left: 10px;
}
.editable {
width:150px;
text-align: center;
}
.editableform .form-control {
width: 95%;
text-align: center;
margin-left: 10px;
}
<link href="{% static 'css/checkbox.css' %}" rel="stylesheet" type="text/css">
<style>
.copy-text-fa-icon:hover {
cursor: pointer;
}
.radio label, .checkbox label {
padding-left: 10px;
}
.editable {
width:150px;
text-align: center;
}
.editableform .form-control {
width: 95%;
text-align: center;
margin-left: 10px;
}
.editable-input {
width: 95%;
}
.radio, .checkbox {
margin-top: 0px;
margin-bottom: 0px;
}
.editable-error-block {
white-space: nowrap;
}
.editable-click, a.editable-click, a.editable-click:hover {
border-bottom: none;
}
.tooltip-inner {
white-space:pre;
max-width: none;
}
</style>
.editable-input {
width: 95%;
}
.radio, .checkbox {
margin-top: 0px;
margin-bottom: 0px;
}
.editable-error-block {
white-space: nowrap;
}
.editable-click, a.editable-click, a.editable-click:hover {
border-bottom: none;
}
.tooltip-inner {
white-space:pre;
max-width: none;
}
</style>
{% endblock extra_css %}
{% block content %}

View File

@ -53,8 +53,8 @@ def srp_fleet_view(request, fleet_id):
except SrpFleetMain.DoesNotExist:
raise Http404
context = {"fleet_id": fleet_id, "fleet_status": fleet_main.fleet_srp_status,
"srpfleetrequests": fleet_main.srpuserrequest_set.select_related('character'),
"totalcost": fleet_main.total_cost}
"srpfleetrequests": fleet_main.srpuserrequest_set.select_related('character'),
"totalcost": fleet_main.total_cost}
return render(request, 'srp/data.html', context=context)
@ -137,7 +137,7 @@ def srp_fleet_mark_completed(request, fleet_id):
srpfleetmain.save()
logger.info("Marked SRP Fleet %s as completed by user %s" % (srpfleetmain.fleet_name, request.user))
messages.success(request,
_('Marked SRP fleet %(fleetname)s as completed.') % {"fleetname": srpfleetmain.fleet_name})
_('Marked SRP fleet %(fleetname)s as completed.') % {"fleetname": srpfleetmain.fleet_name})
return redirect("srp:fleet", fleet_id)
@ -150,7 +150,7 @@ def srp_fleet_mark_uncompleted(request, fleet_id):
srpfleetmain.save()
logger.info("Marked SRP Fleet %s as incomplete for user %s" % (fleet_id, request.user))
messages.success(request,
_('Marked SRP fleet %(fleetname)s as incomplete.') % {"fleetname": srpfleetmain.fleet_name})
_('Marked SRP fleet %(fleetname)s as incomplete.') % {"fleetname": srpfleetmain.fleet_name})
return redirect("srp:fleet", fleet_id)
@ -162,7 +162,7 @@ def srp_request_view(request, fleet_srp):
if SrpFleetMain.objects.filter(fleet_srp_code=fleet_srp).exists() is False:
logger.error("Unable to locate SRP Fleet using code %s for user %s" % (fleet_srp, request.user))
messages.error(request,
_('Unable to locate SRP code with ID %(srpfleetid)s') % {"srpfleetid": fleet_srp})
_('Unable to locate SRP code with ID %(srpfleetid)s') % {"srpfleetid": fleet_srp})
return redirect("srp:management")
if request.method == 'POST':
@ -172,7 +172,7 @@ def srp_request_view(request, fleet_srp):
if form.is_valid():
if SrpUserRequest.objects.filter(killboard_link=form.cleaned_data['killboard_link']).exists():
messages.error(request,
_("This Killboard link has already been posted."))
_("This Killboard link has already been posted."))
return redirect("srp:management")
character = request.user.profile.main_character
@ -193,8 +193,7 @@ def srp_request_view(request, fleet_srp):
request.user, srp_request.killboard_link))
# THIS SHOULD BE IN FORM VALIDATION
messages.error(request,
_(
"Your SRP request Killmail link is invalid. Please make sure you are using zKillboard."))
_("Your SRP request Killmail link is invalid. Please make sure you are using zKillboard."))
return redirect("srp:management")
if request.user.character_ownerships.filter(character__character_id=str(victim_id)).exists():
@ -205,13 +204,12 @@ def srp_request_view(request, fleet_srp):
logger.info("Created SRP Request on behalf of user %s for fleet name %s" % (
request.user, srp_fleet_main.fleet_name))
messages.success(request,
_('Submitted SRP request for your %(ship)s.') % {"ship": srp_request.srp_ship_name})
_('Submitted SRP request for your %(ship)s.') % {"ship": srp_request.srp_ship_name})
return redirect("srp:management")
else:
messages.error(request,
_(
"Character %(charid)s does not belong to your Auth account. Please add the API key for this character and try again")
% {"charid": victim_id})
_("Character %(charid)s does not belong to your Auth account. Please add the API key for this character and try again")
% {"charid": victim_id})
return redirect("srp:management")
else:
logger.debug("Returning blank SrpFleetUserRequestForm")
@ -330,7 +328,7 @@ def srp_request_update_amount(request, fleet_srp_request_id):
if SrpUserRequest.objects.filter(id=fleet_srp_request_id).exists() is False:
logger.error("Unable to locate SRP request id %s for user %s" % (fleet_srp_request_id, request.user))
messages.error(request,
_('Unable to locate SRP request with ID %(requestid)s') % {"requestid": fleet_srp_request_id})
_('Unable to locate SRP request with ID %(requestid)s') % {"requestid": fleet_srp_request_id})
return redirect("srp:management")
srp_request = SrpUserRequest.objects.get(id=fleet_srp_request_id)
@ -354,7 +352,7 @@ def srp_fleet_edit_view(request, fleet_id):
srpfleetmain.save()
logger.info("User %s edited SRP Fleet %s" % (request.user, srpfleetmain.fleet_name))
messages.success(request,
_('Saved changes to SRP fleet %(fleetname)s') % {"fleetname": srpfleetmain.fleet_name})
_('Saved changes to SRP fleet %(fleetname)s') % {"fleetname": srpfleetmain.fleet_name})
return redirect("srp:management")
else:
logger.debug("Returning blank SrpFleetMainUpdateForm")

View File

@ -112,12 +112,12 @@ ul.list-group.list-group-horizontal > li.list-group-item {
display: -ms-flexbox;
display: flex;
flex-wrap: wrap;
}
}
.row.vertical-flexbox-row2 > [class*='col-'] {
.row.vertical-flexbox-row2 > [class*='col-'] {
display: flex;
flex-direction: column;
}
}
}
/* Extra Small devices (Phones, <768px) */

View File

@ -85,8 +85,8 @@
progress-bar-success
{% endif %}
" role="progressbar" aria-valuenow="{% widthratio task_queue_length 500 100 %}"
aria-valuemin="0" aria-valuemax="100"
style="width: {% widthratio task_queue_length 500 100 %}%;">
aria-valuemin="0" aria-valuemax="100"
style="width: {% widthratio task_queue_length 500 100 %}%;">
</div>
</div>
{% if task_queue_length < 0 %}

View File

@ -6,8 +6,7 @@
<div class="collapse navbar-collapse auth-menus-collapse auth-side-navbar-collapse">
<ul class="nav nav-pills nav-stacked gray-icon-color" id="side-menu">
<li>
<a class="{% navactive request 'authentication:dashboard' %}"
href="{% url 'authentication:dashboard' %}">
<a class="{% navactive request 'authentication:dashboard' %}" href="{% url 'authentication:dashboard' %}">
<i class="fas fa-tachometer-alt fa-fw"></i> {% trans "Dashboard" %}
</a>
</li>
@ -18,7 +17,6 @@
</li>
{% menu_items %}
</ul>
</div>
</div>

View File

@ -5,10 +5,10 @@
<div class="container-fluid">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target=".auth-menus-collapse">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand">
<img src="{% static 'icons/favicon-32x32.png' %}" style="display: inline-block;" height="32" width="32"/>

View File

@ -142,7 +142,7 @@ class AuthUtils:
@classmethod
def add_main_character(cls, user, name, character_id, corp_id=2345, corp_name='', corp_ticker='', alliance_id=None,
alliance_name=''):
alliance_name=''):
if alliance_id:
try:
alliance_id = int(alliance_id)
@ -279,7 +279,7 @@ class BaseViewTestCase(TestCase):
self.member.email = 'auth_member@example.com'
self.member.save()
AuthUtils.add_main_character(self.member, 'auth_member', '12345', corp_id='111', corp_name='Test Corporation',
corp_ticker='TESTR')
corp_ticker='TESTR')
def login(self):
token = Token.objects.create(character_id='12345', character_name='auth_member', character_owner_hash='1', user=self.member, access_token='1')

View File

@ -34,15 +34,13 @@ class NavhelperTemplateTagTests(TestCase):
def test_navactive(self):
self._navactive_common('active', '')
with self.settings(NAVHELPER_ACTIVE_CLASS='my-active-class',
NAVHELPER_NOT_ACTIVE_CLASS='my-not-active-class'):
with self.settings(NAVHELPER_ACTIVE_CLASS='my-active-class', NAVHELPER_NOT_ACTIVE_CLASS='my-not-active-class'):
self._navactive_common('my-active-class', 'my-not-active-class')
def test_renavactive(self):
self._renavactive_common('active', '')
with self.settings(NAVHELPER_ACTIVE_CLASS='my-active-class',
NAVHELPER_NOT_ACTIVE_CLASS='my-not-active-class'):
with self.settings(NAVHELPER_ACTIVE_CLASS='my-active-class', NAVHELPER_NOT_ACTIVE_CLASS='my-not-active-class'):
self._renavactive_common('my-active-class', 'my-not-active-class')
def _navactive_common(self, active, not_active):

View File

@ -6,10 +6,12 @@ from . import urls
class TimerboardMenu(MenuItemHook):
def __init__(self):
MenuItemHook.__init__(self, 'Structure Timers',
'far fa-clock fa-fw',
'timerboard:view',
navactive=['timerboard:'])
MenuItemHook.__init__(
self, 'Structure Timers',
'far fa-clock fa-fw',
'timerboard:view',
navactive=['timerboard:']
)
def render(self, request):
if request.user.has_perm('auth.timer_view'):

View File

@ -33,27 +33,27 @@ class TimerForm(forms.ModelForm):
super(TimerForm, self).__init__(*args, **kwargs)
structure_choices = [('POCO', 'POCO'),
('I-HUB', 'I-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', 'Pharolux Cyno Beacon'),
('Tenebrex Cyno Jammer', 'Tenebrex Cyno Jammer'),
('Ansiblex Jump Gate', 'Ansiblex Jump Gate'),
('Moon Mining Cycle', 'Moon Mining Cycle'),
(_('Other'), _('Other'))]
('I-HUB', 'I-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', 'Pharolux Cyno Beacon'),
('Tenebrex Cyno Jammer', 'Tenebrex Cyno Jammer'),
('Ansiblex Jump Gate', 'Ansiblex Jump Gate'),
('Moon Mining Cycle', 'Moon Mining Cycle'),
(_('Other'), _('Other'))]
objective_choices = [('Friendly', _('Friendly')),
('Hostile', _('Hostile')),
('Neutral', _('Neutral'))]
('Hostile', _('Hostile')),
('Neutral', _('Neutral'))]
details = forms.CharField(max_length=254, required=True, label=_('Details'))
system = forms.CharField(max_length=254, required=True, label=_("System"))
@ -64,7 +64,7 @@ class TimerForm(forms.ModelForm):
hours_left = forms.IntegerField(required=True, label=_("Hours Remaining"),
validators=[MinValueValidator(0), MaxValueValidator(23)])
minutes_left = forms.IntegerField(required=True, label=_("Minutes Remaining"),
validators=[MinValueValidator(0), MaxValueValidator(59)])
validators=[MinValueValidator(0), MaxValueValidator(59)])
important = forms.BooleanField(label=_("Important"), required=False)
corp_timer = forms.BooleanField(label=_("Corp-Restricted"), required=False)
@ -75,10 +75,10 @@ class TimerForm(forms.ModelForm):
character = self.user.profile.main_character
corporation = character.corporation
logger.debug("Determined timer save request on behalf "
"of character {} corporation {}".format(character, corporation))
"of character {} corporation {}".format(character, corporation))
# calculate future time
future_time = datetime.timedelta(days=self.cleaned_data['days_left'], hours=self.cleaned_data['hours_left'],
minutes=self.cleaned_data['minutes_left'])
minutes=self.cleaned_data['minutes_left'])
current_time = timezone.now()
eve_time = current_time + future_time
logger.debug(

View File

@ -18,9 +18,9 @@ class TimerboardViewsTestCase(WebTest):
def setUp(self):
corp = EveCorporationInfo.objects.create(corporation_id='2345', corporation_name='test corp',
corporation_ticker='testc', member_count=24)
corporation_ticker='testc', member_count=24)
other_corp = EveCorporationInfo.objects.create(corporation_id='9345', corporation_name='other test corp',
corporation_ticker='testd', member_count=1)
corporation_ticker='testd', member_count=1)
self.user = AuthUtils.create_user('test_user')
AuthUtils.add_main_character(self.user, 'test character', '1234', '2345', 'test corp', 'testc')
self.user = User.objects.get_by_natural_key('test_user')

View File

@ -71,8 +71,7 @@ class AddTimerView(TimerManagementView, AddUpdateMixin, CreateView):
result = super(AddTimerView, self).form_valid(form)
timer = self.object
logger.info("Created new timer in {} at {} by user {}".format(timer.system, timer.eve_time, self.request.user))
messages.success(self.request, _('Added new timer in %(system)s at %(time)s.') % {"system": timer.system,
"time": timer.eve_time})
messages.success(self.request, _('Added new timer in %(system)s at %(time)s.') % {"system": timer.system, "time": timer.eve_time})
return result

View File

@ -142,8 +142,7 @@ latex_elements = {
# (source start file, target name, title,
# author, documentclass [howto, manual, or own class]).
latex_documents = [
(master_doc, 'AllianceAuth.tex', u'Alliance Auth Documentation',
u'R4stl1n', 'manual'),
(master_doc, 'AllianceAuth.tex', u'Alliance Auth Documentation', u'R4stl1n', 'manual'),
]
@ -153,7 +152,7 @@ latex_documents = [
# (source start file, name, description, authors, manual section).
man_pages = [
(master_doc, 'allianceauth', u'Alliance Auth Documentation',
[author], 1)
[author], 1)
]
# -- Options for autodoc -------------------------------------------------
@ -167,8 +166,8 @@ add_module_names = False
# dir menu entry, description, category)
texinfo_documents = [
(master_doc, 'AllianceAuth', u'Alliance Auth Documentation',
author, 'AllianceAuth', 'An auth system for EVE Online to help in-game organizations manage online service access.',
'Miscellaneous'),
author, 'AllianceAuth', 'An auth system for EVE Online to help in-game organizations manage online service access.',
'Miscellaneous'),
]
def setup(app):

View File

@ -4,7 +4,7 @@ It is possible to customize your **Alliance Auth** instance.
```eval_rst
.. warning::
Keep in mind that you may need to update some of your customizations manually after new Auth releases (e.g. when replacing templates).
Keep in mind that you may need to update some of your customizations manually after new Auth releases (e.g. when replacing templates).
```
## Site name

View File

@ -1,8 +1,8 @@
# Alliance Auth documentation
The documentation for Alliance Auth uses [Sphinx](http://www.sphinx-doc.org/) to build documentation. When a new commit
to specific branches is made (master, primarily), the repository is automatically pulled, docs built and deployed on
[readthedocs.org](https://readthedocs.org/).
to specific branches is made (master, primarily), the repository is automatically pulled, docs built and deployed on
[readthedocs.org](https://readthedocs.org/).
Documentation was migrated from the GitHub wiki pages and into the repository to allow documentation changes to be

View File

@ -21,18 +21,18 @@ Typically a service will contain 5 key components:
The architecture looks something like this:
urls -------▶ Views
▲ |
| |
| ▼
ServiceHook ----▶ Tasks ----▶ Manager
|
|
AllianceAuth
▲ |
| |
| ▼
ServiceHook ----▶ Tasks ----▶ Manager
|
|
AllianceAuth
Where:
Module --▶ Dependency/Import
Module --▶ Dependency/Import
While this is the typical structure of the existing services modules, there is no enforcement of this structure and you are, effectively, free to create whatever architecture may be necessary. A service module need not even communicate with an external service, for example, if similar triggers such as validate_user, delete_user are required for a module it may be convenient to masquerade as a service. Ideally though, using the common structure improves the maintainability for other developers.

View File

@ -42,9 +42,9 @@ This is a great feature to signal the user, that he has some open issues to take
```eval_rst
.. hint::
Here is how to stay consistent with the Auth design philosophy for using this feature:
1. Use it to display open items that the current user can close by himself only. Do not use it for items, that the user has no control over.
2. If there are currently no open items, do not show a badge at all.
Here is how to stay consistent with the Auth design philosophy for using this feature:
1. Use it to display open items that the current user can close by himself only. Do not use it for items, that the user has no control over.
2. If there are currently no open items, do not show a badge at all.
```
To use it set count the `render()` function of your subclass in accordance to the current user. Here is an example:

View File

@ -8,7 +8,7 @@ In addition all tools described in this guide are open source or free software.
```eval_rst
.. hint::
This guide is meant for development purposes only and not for installing AA in a production environment. For production installation please see chapter **Installation**.
This guide is meant for development purposes only and not for installing AA in a production environment. For production installation please see chapter **Installation**.
```
## Overview
@ -27,7 +27,7 @@ We will use the build-in Django development webserver, so we don't need to setup
```eval_rst
.. note::
This setup works with both WSL 1 and WSL 2. However, due to the significantly better performance we recommend WSL 2.
This setup works with both WSL 1 and WSL 2. However, due to the significantly better performance we recommend WSL 2.
```
## Requirement
@ -75,13 +75,13 @@ For AA we want to develop with Python 3.6, because that provides the maximum com
```eval_rst
.. hint::
To check your system's Python 3 version you can enter: ``python3 --version``
To check your system's Python 3 version you can enter: ``python3 --version``
```
```eval_rst
.. note::
Should your Ubuntu come with a newer version of Python we recommend to still setup your dev environment with the oldest Python 3 version supported by AA, e.g Python 3.6
You an check out this `page <https://askubuntu.com/questions/682869/how-do-i-install-a-different-python-version-using-apt-get/1195153>`_ on how to install additional Python versions on Ubuntu.
Should your Ubuntu come with a newer version of Python we recommend to still setup your dev environment with the oldest Python 3 version supported by AA, e.g Python 3.6
You an check out this `page <https://askubuntu.com/questions/682869/how-do-i-install-a-different-python-version-using-apt-get/1195153>`_ on how to install additional Python versions on Ubuntu.
```
Use the following command to install Python 3 with all required libraries with the default version:
@ -100,7 +100,7 @@ sudo apt-get install mysql-server mysql-client libmysqlclient-dev
```eval_rst
.. note::
We chose to use MySQL instead of MariaDB, because the standard version of MariaDB that comes with this Ubuntu distribution will not work with AA.
We chose to use MySQL instead of MariaDB, because the standard version of MariaDB that comes with this Ubuntu distribution will not work with AA.
```
We need to apply a permission fix to mysql or you will get a warning with every startup:
@ -150,14 +150,14 @@ sudo redis-server --daemonize yes
```eval_rst
.. note::
WSL does not have an init.d service, so it will not automatically start your services such as MySQL and Redis when you boot your Windows machine. For convenience we recommend putting the commands for starting these services in a bash script. Here is an example: ::
WSL does not have an init.d service, so it will not automatically start your services such as MySQL and Redis when you boot your Windows machine. For convenience we recommend putting the commands for starting these services in a bash script. Here is an example: ::
#/bin/bash
# start services for AA dev
sudo service mysql start
sudo redis-server --daemonize yes
#/bin/bash
# start services for AA dev
sudo service mysql start
sudo redis-server --daemonize yes
In addition it is possible to configure Windows to automatically start WSL services, but that procedure goes beyond the scopes of this guide.
In addition it is possible to configure Windows to automatically start WSL services, but that procedure goes beyond the scopes of this guide.
```
### Setup dev folder on WSL
@ -299,15 +299,15 @@ Once running you can access your auth site on the browser under `http://localhos
```eval_rst
.. hint::
You can start your AA server directly from a terminal window in VSC or with a VSC debug config (see chapter about debugging for details).
You can start your AA server directly from a terminal window in VSC or with a VSC debug config (see chapter about debugging for details).
```
```eval_rst
.. note::
**Debug vs. Non-Debug mode**
Usually it is best to run your dev AA instance in debug mode, so you get all the detailed error messages that helps a lot for finding errors. But there might be cases where you want to test features that do not exist in debug mode (e.g. error pages) or just want to see how your app behaves in non-debug / production mode.
**Debug vs. Non-Debug mode**
Usually it is best to run your dev AA instance in debug mode, so you get all the detailed error messages that helps a lot for finding errors. But there might be cases where you want to test features that do not exist in debug mode (e.g. error pages) or just want to see how your app behaves in non-debug / production mode.
When you turn off debug mode you will see a problem though: Your pages will not render correctly. The reason is that Django will stop serving your static files in production mode and expect you to serve them from a real web server. Luckily, there is an option that forces Django to continue serving your static files directly even when not in debug mode. Just start your server with the following option: ``python manage.py runserver --insecure``
When you turn off debug mode you will see a problem though: Your pages will not render correctly. The reason is that Django will stop serving your static files in production mode and expect you to serve them from a real web server. Luckily, there is an option that forces Django to continue serving your static files directly even when not in debug mode. Just start your server with the following option: ``python manage.py runserver --insecure``
```
### Celery

View File

@ -16,7 +16,7 @@ As a rule of thumb we therefore recommend to use celery tasks for every process
```eval_rst
.. note::
Another solution for dealing with long response time in particular when loading pages is to load parts of a page asynchronously, for example with AJAX.
Another solution for dealing with long response time in particular when loading pages is to load parts of a page asynchronously, for example with AJAX.
```
### Recurrence
@ -108,11 +108,11 @@ The list of task signatures is then converted to a chain and started asynchronou
```eval_rst
.. hint::
In our example we use ``si()``, which is a shortcut for "immutable signatures" and prevents us from having to deal with result sharing between tasks.
In our example we use ``si()``, which is a shortcut for "immutable signatures" and prevents us from having to deal with result sharing between tasks.
For more information on signature and work flows see the official documentation on `Canvas <https://docs.celeryproject.org/en/latest/userguide/canvas.html>`_.
For more information on signature and work flows see the official documentation on `Canvas <https://docs.celeryproject.org/en/latest/userguide/canvas.html>`_.
In this context please note that Alliance Auth currently only supports chaining, because all other variants require a so called results back, which Alliance Auth does not have.
In this context please note that Alliance Auth currently only supports chaining, because all other variants require a so called results back, which Alliance Auth does not have.
```
## How can I define periodic tasks for my app?
@ -152,14 +152,14 @@ In Alliance Auth we have defined task priorities from 0 - 9 as follows:
```eval_rst
.. warning::
Please make sure to use task priorities with care and especially do not use higher priorities without a good reason. All apps including Alliance Auth share the same task queues, so using higher task priorities excessively can potentially prevent more important tasks (of other apps) from completing on time.
Please make sure to use task priorities with care and especially do not use higher priorities without a good reason. All apps including Alliance Auth share the same task queues, so using higher task priorities excessively can potentially prevent more important tasks (of other apps) from completing on time.
You also want to make sure to run use lower priorities if you have a large amount of tasks or long running tasks, which are not super urgent. (e.g. the regular update of all Eve characters from ESI runs with priority 7)
You also want to make sure to run use lower priorities if you have a large amount of tasks or long running tasks, which are not super urgent. (e.g. the regular update of all Eve characters from ESI runs with priority 7)
```
```eval_rst
.. hint::
If no priority is specified all tasks will be started with the default priority, which is 5.
If no priority is specified all tasks will be started with the default priority, which is 5.
```
To run a task with a different priority you need to specify it when starting it.
@ -172,7 +172,7 @@ example.apply_async(priority=3)
```eval_rst
.. hint::
For defining a priority to tasks you can not use the convenient shortcut ``delay()``, but instead need to start a task with ``apply_async()``, which also requires you to pass parameters to your task function differently. Please check out the `official docs <https://docs.celeryproject.org/en/stable/reference/celery.app.task.html#celery.app.task.Task.apply_async>`_ for details.
For defining a priority to tasks you can not use the convenient shortcut ``delay()``, but instead need to start a task with ``apply_async()``, which also requires you to pass parameters to your task function differently. Please check out the `official docs <https://docs.celeryproject.org/en/stable/reference/celery.app.task.html#celery.app.task.Task.apply_async>`_ for details.
```
## What special features should I be aware of?

View File

@ -32,7 +32,7 @@ CELERYBEAT_SCHEDULE['discord.update_all_usernames'] = {
```eval_rst
.. note::
You will have to add most the values for these settings, e.g. your Discord server ID (aka guild ID), later in the setup process.
You will have to add most the values for these settings, e.g. your Discord server ID (aka guild ID), later in the setup process.
```
### Creating a Server
@ -47,7 +47,7 @@ Update your auth project's settings file, inputting the server ID as `DISCORD_GU
```eval_rst
.. note::
If you already have a Discord server skip the creation step, but be sure to retrieve the server ID
If you already have a Discord server skip the creation step, but be sure to retrieve the server ID
```
### Registering an Application
@ -115,7 +115,7 @@ Name Description
```eval_rst
.. note::
Depending on how many users you have, running these tasks can take considerable time to finish. You can calculate roughly 1 sec per user for all tasks, except update_all, which needs roughly 3 secs per user.
Depending on how many users you have, running these tasks can take considerable time to finish. You can calculate roughly 1 sec per user for all tasks, except update_all, which needs roughly 3 secs per user.
```
## Settings

View File

@ -4,17 +4,17 @@ Mumble is a free voice chat server. While not as flashy as TeamSpeak, it has all
```eval_rst
.. note::
Note that this guide assumes that you have installed Auth with the official :doc:`/installation/allianceauth` guide under ``/home/allianceserver`` and that it is called ``myauth``. Accordingly it assumes that you have a service user called ``allianceserver`` that is used to run all Auth services under supervisor.
Note that this guide assumes that you have installed Auth with the official :doc:`/installation/allianceauth` guide under ``/home/allianceserver`` and that it is called ``myauth``. Accordingly it assumes that you have a service user called ``allianceserver`` that is used to run all Auth services under supervisor.
```
```eval_rst
.. note::
Same as the official installation guide this guide is assuming you are performing all steps as ``root`` user.
Same as the official installation guide this guide is assuming you are performing all steps as ``root`` user.
```
```eval_rst
.. warning::
This guide is currently for Ubuntu only.
This guide is currently for Ubuntu only.
```
## Installations

View File

@ -1,6 +1,6 @@
# Openfire
Openfire is a Jabber (XMPP) server.
Openfire is a Jabber (XMPP) server.
## Prepare Your Settings

View File

@ -74,7 +74,7 @@ Nginx: `chown -R nginx:nginx /var/www/forums`
```eval_rst
.. tip::
Nginx: Some distributions use the ``www-data:www-data`` user:group instead of ``nginx:nginx``. If you run into problems with permissions try it instead.
Nginx: Some distributions use the ``www-data:www-data`` user:group instead of ``nginx:nginx``. If you run into problems with permissions try it instead.
..
```

View File

@ -11,8 +11,8 @@ SMF requires PHP installed in your web server. Apache has `mod_php`, NGINX requi
## Prepare Your Settings
In your auth project's settings file, do the following:
- Add `'allianceauth.services.modules.smf',` to your `INSTALLED_APPS` list
- Append the following to the bottom of the settings file:
- Add `'allianceauth.services.modules.smf',` to your `INSTALLED_APPS` list
- Append the following to the bottom of the settings file:
```python
# SMF Configuration
@ -36,15 +36,19 @@ Using your browser, you can download the latest version of SMF to your desktop c
Download using wget, replacing the URL with the URL for the package you just retrieved
wget https://download.simplemachines.org/index.php?thanks;filename=smf_2-0-15_install.zip
```shell
wget https://download.simplemachines.org/index.php?thanks;filename=smf_2-0-15_install.zip
```
This needs to be unpackaged. Unzip it, replacing the file name with that of the file you just downloaded
unzip smf_2-0-15_install.zip
```shell
unzip smf_2-0-15_install.zip
````
Now we need to move this to our web directory. Usually `/var/www/forums`.
mv smf /var/www/forums
```shell
mv smf /var/www/forums
````
The web server needs read/write permission to this folder
@ -53,18 +57,22 @@ Nginx: `chown -R nginx:nginx /var/www/forums`
```eval_rst
.. tip::
Nginx: Some distributions use the ``www-data:www-data`` user:group instead of ``nginx:nginx``. If you run into problems with permissions try it instead.
Nginx: Some distributions use the ``www-data:www-data`` user:group instead of ``nginx:nginx``. If you run into problems with permissions try it instead.
..
```
### Database Preparation
SMF needs a database. Create one:
```shell
mysql -u root -p
```
mysql -u root -p
create database alliance_smf;
grant all privileges on alliance_smf . * to 'allianceserver'@'localhost';
exit;
```mysql
create database alliance_smf;
grant all privileges on alliance_smf . * to 'allianceserver'@'localhost';
exit;
```
Enter the database information into the `DATABASES['smf']` section of your auth project's settings file.
@ -73,33 +81,34 @@ Enter the database information into the `DATABASES['smf']` section of your auth
Your web server needs to be configured to serve SMF.
A minimal Apache config might look like:
<VirtualHost *:80>
ServerName forums.example.com
DocumentRoot /var/www/forums
<Directory "/var/www/forums">
DirectoryIndex index.php
</Directory>
</VirtualHost>
```apache
<VirtualHost *:80>
ServerName forums.example.com
DocumentRoot /var/www/forums
<Directory "/var/www/forums">
DirectoryIndex index.php
</Directory>
</VirtualHost>
````
A minimal Nginx config might look like:
```nginx
server {
listen 80;
server_name forums.example.com;
root /var/www/forums;
index index.php;
access_log /var/logs/forums.access.log;
server {
listen 80;
server_name forums.example.com;
root /var/www/forums;
index index.php;
access_log /var/logs/forums.access.log;
location ~ \.php$ {
try_files $uri =404;
fastcgi_pass unix:/tmp/php.socket;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
location ~ \.php$ {
try_files $uri =404;
fastcgi_pass unix:/tmp/php.socket;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
````
Enter the web address to your forums into the `SMF_URL` setting in your auth project's settings file.
### Web Install

View File

@ -4,12 +4,12 @@ This document describes how to install **Alliance Auth** from scratch.
```eval_rst
.. tip::
If you are uncomfortable with Linux permissions follow the steps below as the root user.
If you are uncomfortable with Linux permissions follow the steps below as the root user.
```
```eval_rst
.. note::
There are additional installation steps for activating services and apps that come with **Alliance Auth**. Please see the page for the respective service or apps in chapter :doc:`/features/index` for details.
There are additional installation steps for activating services and apps that come with **Alliance Auth**. Please see the page for the respective service or apps in chapter :doc:`/features/index` for details.
```
## Dependencies
@ -20,7 +20,7 @@ Alliance Auth can be installed on any Unix like operating system. Dependencies a
```eval_rst
.. hint::
CentOS: A few packages are included in a non-default repository. Add it and update the package lists. ::
CentOS: A few packages are included in a non-default repository. Add it and update the package lists. ::
yum -y install https://centos7.iuscommunity.org/ius-release.rpm
yum update
@ -48,9 +48,9 @@ It's recommended to use a database service instead of SQLite. Many options are a
```eval_rst
.. warning::
Many Ubuntu distributions come with an older version of Maria DB, which is not compatible with **Alliance Auth**. You need Maria DB 10.3 or higher!
Many Ubuntu distributions come with an older version of Maria DB, which is not compatible with **Alliance Auth**. You need Maria DB 10.3 or higher!
For instructions on how To install a newer version of Maria DB on Ubuntu visit this page: `MariaDB Repositories <https://downloads.mariadb.org/mariadb/repositories/#distro=Ubuntu&mirror=osuosl>`_.
For instructions on how To install a newer version of Maria DB on Ubuntu visit this page: `MariaDB Repositories <https://downloads.mariadb.org/mariadb/repositories/#distro=Ubuntu&mirror=osuosl>`_.
```
Ubuntu:
@ -67,7 +67,7 @@ yum install mariadb-server mariadb-devel mariadb-shared mariadb
```eval_rst
.. note::
If you don't plan on running the database on the same server as auth you still need to install the libmysqlclient-dev package on Ubuntu or mariadb-devel package on CentOS.
If you don't plan on running the database on the same server as auth you still need to install the libmysqlclient-dev package on Ubuntu or mariadb-devel package on CentOS.
```
### Redis and Other Tools
@ -88,7 +88,7 @@ yum install gcc gcc-c++ unzip git redis curl bzip2-devel
```eval_rst
.. important::
CentOS: Make sure Redis is running before continuing. ::
CentOS: Make sure Redis is running before continuing. ::
systemctl enable redis.service
systemctl start redis.service
@ -112,11 +112,11 @@ mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql -u root -p mysql
```eval_rst
.. note::
You may see errors when you add the timezone tables. To make sure that they were correctly added run the following commands and check for the ``time_zone`` tables::
You may see errors when you add the timezone tables. To make sure that they were correctly added run the following commands and check for the ``time_zone`` tables::
mysql -u root -p
use mysql;
show tables;
mysql -u root -p
use mysql;
show tables;
```
Close the SQL shell and secure your database server with this command:
@ -153,12 +153,12 @@ python3 -m venv /home/allianceserver/venv/auth/
```eval_rst
.. warning::
The python3 command may not be available on all installations. Try a specific version such as ``python3.6`` if this is the case.
The python3 command may not be available on all installations. Try a specific version such as ``python3.6`` if this is the case.
```
```eval_rst
.. tip::
A virtual environment provides support for creating a lightweight "copy" of Python with their own site directories. Each virtual environment has its own Python binary (allowing creation of environments with various Python versions) and can have its own independent set of installed Python packages in its site directories. You can read more about virtual environments on the Python_ docs.
A virtual environment provides support for creating a lightweight "copy" of Python with their own site directories. Each virtual environment has its own Python binary (allowing creation of environments with various Python versions) and can have its own independent set of installed Python packages in its site directories. You can read more about virtual environments on the Python_ docs.
.. _Python: https://docs.python.org/3/library/venv.html
```
@ -170,7 +170,7 @@ source /home/allianceserver/venv/auth/bin/activate
```eval_rst
.. hint::
Each time you come to do maintenance on your Alliance Auth installation, you should activate your virtual environment first. When finished, deactivate it with the ``deactivate`` command.
Each time you come to do maintenance on your Alliance Auth installation, you should activate your virtual environment first. When finished, deactivate it with the ``deactivate`` command.
```
### Eve Online SSO
@ -258,7 +258,7 @@ The default configuration is good enough for most installations. Additional info
```eval_rst
.. note::
Many package managers will install Supervisor 3 by default, which requires Python 2.
Many package managers will install Supervisor 3 by default, which requires Python 2.
```
Ubuntu:
@ -295,9 +295,9 @@ You can check the status of the processes with `supervisorctl status`. Logs from
```eval_rst
.. note::
Any time the code or your settings change you'll need to restart Gunicorn and Celery. ::
Any time the code or your settings change you'll need to restart Gunicorn and Celery. ::
supervisorctl restart myauth:
supervisorctl restart myauth:
```
## Webserver

View File

@ -8,7 +8,7 @@ Check out the full [Gunicorn docs](http://docs.gunicorn.org/en/latest/index.html
```eval_rst
.. note::
The page contains additional steps on how to setup and configure Gunicorn that are not required for users who decide to stick with the default Gunicorn configuration as described in the main installation guide for AA.
The page contains additional steps on how to setup and configure Gunicorn that are not required for users who decide to stick with the default Gunicorn configuration as described in the main installation guide for AA.
```
## Setting up Gunicorn

View File

@ -35,8 +35,8 @@ Nginx needs to be able to read the folder containing your auth project's static
```eval_rst
.. tip::
Some specific distros may use www-data:www-data instead of nginx:nginx, causing static files (images, stylesheets etc) not to appear. You can confirm what user Nginx will run under by checking either its base config file `/etc/nginx/nginx.conf` for the "user" setting, or once Nginx has started `ps aux | grep nginx`.
Adjust your chown commands to the correct user if needed.
Some specific distros may use www-data:www-data instead of nginx:nginx, causing static files (images, stylesheets etc) not to appear. You can confirm what user Nginx will run under by checking either its base config file `/etc/nginx/nginx.conf` for the "user" setting, or once Nginx has started `ps aux | grep nginx`.
Adjust your chown commands to the correct user if needed.
..
```

View File

@ -4,12 +4,12 @@ This guide describes how to upgrade an existing Alliance Auth (AA) installation
```eval_rst
.. hint::
In accordance with the installation guide we will assume you perform all actions as root. If you are not running as root you need to add ``sudo`` to some commands.
In accordance with the installation guide we will assume you perform all actions as root. If you are not running as root you need to add ``sudo`` to some commands.
```
```eval_rst
.. note::
This guide will upgrade the software components only but not change any data or configuration.
This guide will upgrade the software components only but not change any data or configuration.
```
## Install a new Python version
@ -18,7 +18,7 @@ To run AA with a newer Python 3 version than your system's default you need to i
```eval_rst
.. note::
For stability and performance we currently recommend to run AA with Python 3.7. It has proven to be the fastest and most stable version in use currently.
For stability and performance we currently recommend to run AA with Python 3.7. It has proven to be the fastest and most stable version in use currently.
```
To install other Python versions than those included with your distribution, you need to add a new installation repository. Then you can install the specific Python 3 to your system.
@ -27,7 +27,7 @@ Ubuntu 1604 1804:
```eval_rst
.. note::
Ubuntu 2004 ships with Python 3.8, No updates required.
Ubuntu 2004 ships with Python 3.8, No updates required.
```
```bash
@ -156,12 +156,12 @@ At this point we recommend creating a list of the additional packages that you n
```eval_rst
.. hint::
While `requirements.txt` will contain a complete list of your packages, it will also contain many packages that are automatically installed as dependencies and don't need be manually reinstalled.
While `requirements.txt` will contain a complete list of your packages, it will also contain many packages that are automatically installed as dependencies and don't need be manually reinstalled.
```
```eval_rst
.. note::
Some guide on the Internet will suggest to use use the requirements.txt file to recreate a venv. This is indeed possible, but only works if all packages can be installed from PyPI. Since most community apps are installed directly from repos this guide will not follow that approach.
Some guide on the Internet will suggest to use use the requirements.txt file to recreate a venv. This is indeed possible, but only works if all packages can be installed from PyPI. Since most community apps are installed directly from repos this guide will not follow that approach.
```
Leave the venv and shutdown all AA services:

View File

@ -2,12 +2,12 @@
```eval_rst
.. hint::
Most tunings will require a change to your supervisor configuration in your `supervisor.conf` file. Note that you need to restart the supervisor daemon in order for any changes to take effect. And before restarting the daemon you may want to make sure your supervisors stop gracefully:(Ubuntu):
Most tunings will require a change to your supervisor configuration in your `supervisor.conf` file. Note that you need to restart the supervisor daemon in order for any changes to take effect. And before restarting the daemon you may want to make sure your supervisors stop gracefully:(Ubuntu):
::
::
supervisor stop myauth:
systemctl supervisor restart
supervisor stop myauth:
systemctl supervisor restart
```
## Task Logging
@ -51,17 +51,17 @@ command=/home/allianceserver/venv/auth/bin/celery -A myauth worker --max-memory-
```eval_rst
.. hint::
The 256 MB limit is just an example and should be adjusted to your system configuration. We would suggest to not go below 128MB though, since new workers start with around 80 MB already. Also take into consideration that this value is per worker and that you properly have more than one worker running in your system (if your workers run as processes, which is the default).
The 256 MB limit is just an example and should be adjusted to your system configuration. We would suggest to not go below 128MB though, since new workers start with around 80 MB already. Also take into consideration that this value is per worker and that you properly have more than one worker running in your system (if your workers run as processes, which is the default).
```
```eval_rst
.. warning::
The ``max-memory-per-child`` parameter only works when workers run as processes (which is the default). It does not work for threads.
The ``max-memory-per-child`` parameter only works when workers run as processes (which is the default). It does not work for threads.
```
```eval_rst
.. note::
Alternatively, you can also limit the number of runs per worker until a restart is performed with the worker parameter ``max-tasks-per-child``. This can also protect against memory leaks if you set the threshold is low enough. However, it is less precise since than using ``max-memory-per-child``.
Alternatively, you can also limit the number of runs per worker until a restart is performed with the worker parameter ``max-tasks-per-child``. This can also protect against memory leaks if you set the threshold is low enough. However, it is less precise since than using ``max-memory-per-child``.
```
See also the [official Celery documentation](https://docs.celeryproject.org/en/stable/userguide/workers.html#max-memory-per-child-setting) for more information about these two worker parameters.
@ -109,11 +109,11 @@ The recommended number of workers is one per core, which is what you get automat
```eval_rst
.. hint::
The optimal number will hugely depend on your individual system configuration and you may want to experiment with different settings to find the optimal. One way to generate task load and verify your configuration is to run a model update with the following command:
The optimal number will hugely depend on your individual system configuration and you may want to experiment with different settings to find the optimal. One way to generate task load and verify your configuration is to run a model update with the following command:
::
celery -A myauth call allianceauth.eveonline.tasks.run_model_update
celery -A myauth call allianceauth.eveonline.tasks.run_model_update
```
@ -125,7 +125,7 @@ Alliance Auth tasks are primarily I/O bound (most tasks are fetching data from E
```eval_rst
.. warning::
One important feature that no longer works with threads is the worker parameter ``--max-memory-per-child`` that protects against memory leaks. But you can alternatively use supervisor_ to monitor and restart your workers.
One important feature that no longer works with threads is the worker parameter ``--max-memory-per-child`` that protects against memory leaks. But you can alternatively use supervisor_ to monitor and restart your workers.
```
See also the also [this guide](https://www.distributedpython.com/2018/10/26/celery-execution-pool/) on more information about how to configure the execution pool for workers.
@ -156,5 +156,5 @@ Make sure to restart supervisor to activate the changes.
```eval_rst
.. hint::
The optimal number of concurrent workers will be different for every system and we recommend experimenting with different figures to find the optimal for your system. Note, that the example of 10 threads is conservative and should work even with smaller systems.
The optimal number of concurrent workers will be different for every system and we recommend experimenting with different figures to find the optimal for your system. Note, that the example of 10 threads is conservative and should work even with smaller systems.
```

View File

@ -4,7 +4,7 @@ The official installation guide will install a stable version of Alliance Auth t
```eval_rst
.. warning::
Tuning usually has benefits and costs and should only be performed by experienced Linux administrators who understand the impact of tuning decisions on to their system.
Tuning usually has benefits and costs and should only be performed by experienced Linux administrators who understand the impact of tuning decisions on to their system.
```
```eval_rst