mirror of
https://gitlab.com/allianceauth/allianceauth.git
synced 2026-02-04 14:16:21 +01:00
Compare commits
23 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5250432ce3 | ||
|
|
53d6e973eb | ||
|
|
c9bdd62d53 | ||
|
|
7eb98af528 | ||
|
|
385e3e21b3 | ||
|
|
127ec63d76 | ||
|
|
4988b5f260 | ||
|
|
f28a50f92c | ||
|
|
e8efe8e609 | ||
|
|
d7e7457bc5 | ||
|
|
daff927811 | ||
|
|
8861ec0a61 | ||
|
|
bd4321f61a | ||
|
|
d831482fe0 | ||
|
|
73f262ce4b | ||
|
|
f63434adc3 | ||
|
|
32e0621b0a | ||
|
|
78e05b84e9 | ||
|
|
76ebd21163 | ||
|
|
38aaf545c6 | ||
|
|
527d7ef671 | ||
|
|
e54b80e061 | ||
|
|
27f95a8b2c |
18
README.md
18
README.md
@@ -11,32 +11,34 @@
|
||||
|
||||
An auth system for EVE Online to help in-game organizations manage online service access.
|
||||
|
||||
## Contens
|
||||
## Content
|
||||
|
||||
- [Overview](#overview)
|
||||
- [Documentation](http://allianceauth.rtfd.io)
|
||||
- [Support](#support)
|
||||
- [Release Notes](https://gitlab.com/allianceauth/allianceauth/-/releases)
|
||||
- [Devloper Team](#developer-team)
|
||||
- [Developer Team](#developer-team)
|
||||
- [Contributing](#contributing)
|
||||
|
||||
## Overview
|
||||
|
||||
Alliance Auth (AA) is a web application that helps Eve Online organizations efficiently manage access to their applications and services.
|
||||
Alliance Auth (AA) is a web site that helps Eve Online organizations efficiently manage access to applications and services.
|
||||
|
||||
Main features:
|
||||
|
||||
- Automatically grants or revokes user access to external applications / services (e.g. Discord, Mumble) and web apps (e.g. SRP requests) based on the user's current membership to [in-game organizations](https://allianceauth.readthedocs.io/en/latest/features/states/) and [groups](https://allianceauth.readthedocs.io/en/latest/features/groups/)
|
||||
- Automatically grants or revokes user access to external services (e.g. Discord, Mumble) and web apps (e.g. SRP requests) based on the user's current membership to [in-game organizations](https://allianceauth.readthedocs.io/en/latest/features/core/states/) and [groups](https://allianceauth.readthedocs.io/en/latest/features/core/groups/)
|
||||
|
||||
- Provides a central web site where users can directly access web apps (e.g. SRP requests, Fleet Schedule) and manage their access to external services and groups.
|
||||
|
||||
- Includes a set of connectors (called ["services"](https://allianceauth.readthedocs.io/en/latest/installation/services/)) for integrating access management with many popular external applications / services like Discord, Mumble, Teamspeak 3, SMF and others
|
||||
- Includes a set of connectors (called ["services"](https://allianceauth.readthedocs.io/en/latest/features/services/)) for integrating access management with many popular external applications / services like Discord, Mumble, Teamspeak 3, SMF and others
|
||||
|
||||
- Includes a set of web apps called ["plug-in apps"](https://allianceauth.readthedocs.io/en/latest/features/) which add many useful functions: fleet schedule, timer board, SRP request management, fleet activity tracker and character application management
|
||||
- Includes a set of web [apps](https://allianceauth.readthedocs.io/en/latest/features/apps/) which add many useful functions, e.g.: fleet schedule, timer board, SRP request management, fleet activity tracker
|
||||
|
||||
- Can be easily extended with new services and plugin-apps. Many additional services and plugin-apps are provided by the community and can be found here: [Community Creations](https://gitlab.com/allianceauth/community-creations)
|
||||
- Can be easily extended with additional services and apps. Many are provided by the community and can be found here: [Community Creations](https://gitlab.com/allianceauth/community-creations)
|
||||
|
||||
For further details about AA - including an installation guide and a full list of included services and plugin apps - please see the [offical documentation](http://allianceauth.rtfd.io).
|
||||
- Chinese :cn:, English :us:, German :de: and Spanish :es: localization
|
||||
|
||||
For further details about AA - including an installation guide and a full list of included services and plugin apps - please see the [official documentation](http://allianceauth.rtfd.io).
|
||||
|
||||
## Screenshot
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# This will make sure the app is always imported when
|
||||
# Django starts so that shared_task will use this app.
|
||||
|
||||
__version__ = '2.6.2'
|
||||
__version__ = '2.6.3'
|
||||
NAME = 'Alliance Auth v%s' % __version__
|
||||
default_app_config = 'allianceauth.apps.AllianceAuthConfig'
|
||||
|
||||
@@ -506,7 +506,7 @@ class BaseOwnershipAdmin(admin.ModelAdmin):
|
||||
'character',
|
||||
)
|
||||
search_fields = (
|
||||
'user__user',
|
||||
'user__username',
|
||||
'character__character_name',
|
||||
'character__corporation_name',
|
||||
'character__alliance_name'
|
||||
|
||||
@@ -2,10 +2,17 @@ from django.urls import reverse
|
||||
|
||||
|
||||
def get_admin_change_view_url(obj: object) -> str:
|
||||
"""returns URL to admin change view for given object"""
|
||||
return reverse(
|
||||
'admin:{}_{}_change'.format(
|
||||
obj._meta.app_label,
|
||||
type(obj).__name__.lower()
|
||||
obj._meta.app_label, type(obj).__name__.lower()
|
||||
),
|
||||
args=(obj.pk,)
|
||||
)
|
||||
|
||||
def get_admin_search_url(ModelClass: type) -> str:
|
||||
"""returns URL to search URL for model of given object"""
|
||||
return '{}{}/'.format(
|
||||
reverse('admin:app_list', args=(ModelClass._meta.app_label,)),
|
||||
ModelClass.__name__.lower()
|
||||
)
|
||||
@@ -1,3 +1,4 @@
|
||||
from urllib.parse import quote
|
||||
from unittest.mock import patch
|
||||
|
||||
from django.conf import settings
|
||||
@@ -6,8 +7,9 @@ from django.contrib.admin.sites import AdminSite
|
||||
from django.contrib.auth.models import User as BaseUser, Group
|
||||
from django.test import TestCase, RequestFactory, Client
|
||||
|
||||
from allianceauth.authentication.models import CharacterOwnership, State, \
|
||||
OwnershipRecord
|
||||
from allianceauth.authentication.models import (
|
||||
CharacterOwnership, State, OwnershipRecord
|
||||
)
|
||||
from allianceauth.eveonline.models import (
|
||||
EveCharacter, EveCorporationInfo, EveAllianceInfo
|
||||
)
|
||||
@@ -28,7 +30,7 @@ from ..admin import (
|
||||
user_username,
|
||||
update_main_character_model
|
||||
)
|
||||
from . import get_admin_change_view_url
|
||||
from . import get_admin_change_view_url, get_admin_search_url
|
||||
|
||||
if 'allianceauth.eveonline.autogroups' in settings.INSTALLED_APPS:
|
||||
_has_auto_groups = True
|
||||
@@ -175,6 +177,17 @@ def create_test_data():
|
||||
return user_1, user_2, user_3, group_1, group_2
|
||||
|
||||
|
||||
def make_generic_search_request(ModelClass: type, search_term: str):
|
||||
User.objects.create_superuser(
|
||||
username='superuser', password='secret', email='admin@example.com'
|
||||
)
|
||||
c = Client()
|
||||
c.login(username='superuser', password='secret')
|
||||
return c.get(
|
||||
'%s?q=%s' % (get_admin_search_url(ModelClass), quote(search_term))
|
||||
)
|
||||
|
||||
|
||||
class TestCharacterOwnershipAdmin(TestCase):
|
||||
|
||||
@classmethod
|
||||
@@ -197,6 +210,14 @@ class TestCharacterOwnershipAdmin(TestCase):
|
||||
response = c.get(get_admin_change_view_url(ownership))
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
def test_search_works(self):
|
||||
obj = CharacterOwnership.objects\
|
||||
.filter(user=self.user_1)\
|
||||
.first()
|
||||
response = make_generic_search_request(type(obj), obj.user.username)
|
||||
expected = 200
|
||||
self.assertEqual(response.status_code, expected)
|
||||
|
||||
|
||||
class TestOwnershipRecordAdmin(TestCase):
|
||||
|
||||
@@ -222,6 +243,12 @@ class TestOwnershipRecordAdmin(TestCase):
|
||||
response = c.get(get_admin_change_view_url(ownership_record))
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
def test_search_works(self):
|
||||
obj = OwnershipRecord.objects.first()
|
||||
response = make_generic_search_request(type(obj), obj.user.username)
|
||||
expected = 200
|
||||
self.assertEqual(response.status_code, expected)
|
||||
|
||||
|
||||
class TestStateAdmin(TestCase):
|
||||
|
||||
@@ -250,6 +277,11 @@ class TestStateAdmin(TestCase):
|
||||
response = c.get(get_admin_change_view_url(member_state))
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
def test_search_works(self):
|
||||
obj = State.objects.first()
|
||||
response = make_generic_search_request(type(obj), obj.name)
|
||||
expected = 200
|
||||
self.assertEqual(response.status_code, expected)
|
||||
|
||||
class TestUserAdmin(TestCase):
|
||||
|
||||
@@ -541,3 +573,9 @@ class TestUserAdmin(TestCase):
|
||||
c.login(username='superuser', password='secret')
|
||||
response = c.get(get_admin_change_view_url(self.user_1))
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
def test_search_works(self):
|
||||
obj = User.objects.first()
|
||||
response = make_generic_search_request(type(obj), obj.username)
|
||||
expected = 200
|
||||
self.assertEqual(response.status_code, expected)
|
||||
@@ -8,7 +8,7 @@ from django.contrib.auth.models import User
|
||||
from django.core import signing
|
||||
from django.urls import reverse
|
||||
from django.shortcuts import redirect, render
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from allianceauth.eveonline.models import EveCharacter
|
||||
from esi.decorators import token_required
|
||||
@@ -69,7 +69,10 @@ def main_character_change(request, token):
|
||||
if not CharacterOwnership.objects.filter(character__character_id=token.character_id).exists():
|
||||
co = CharacterOwnership.objects.create_by_token(token)
|
||||
else:
|
||||
messages.error(request, 'Cannot change main character to %(char)s: character owned by a different account.' % ({'char': token.character_name}))
|
||||
messages.error(
|
||||
request,
|
||||
_('Cannot change main character to %(char)s: character owned by a different account.') % ({'char': token.character_name})
|
||||
)
|
||||
co = None
|
||||
if co:
|
||||
request.user.profile.main_character = co.character
|
||||
|
||||
@@ -7,6 +7,7 @@ from .models import EveCorporationInfo
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
TASK_PRIORITY = 7
|
||||
|
||||
@shared_task
|
||||
def update_corp(corp_id):
|
||||
@@ -27,11 +28,12 @@ def update_character(character_id):
|
||||
def run_model_update():
|
||||
# update existing corp models
|
||||
for corp in EveCorporationInfo.objects.all().values('corporation_id'):
|
||||
update_corp.delay(corp['corporation_id'])
|
||||
update_corp.apply_async(args=[corp['corporation_id']], priority=TASK_PRIORITY)
|
||||
|
||||
# update existing alliance models
|
||||
for alliance in EveAllianceInfo.objects.all().values('alliance_id'):
|
||||
update_alliance.delay(alliance['alliance_id'])
|
||||
update_alliance.apply_async(args=[alliance['alliance_id']], priority=TASK_PRIORITY)
|
||||
|
||||
#update existing character models
|
||||
for character in EveCharacter.objects.all().values('character_id'):
|
||||
update_character.delay(character['character_id'])
|
||||
update_character.apply_async(args=[character['character_id']], priority=TASK_PRIORITY)
|
||||
|
||||
@@ -80,28 +80,28 @@ class TestTasks(TestCase):
|
||||
character_name='character.name',
|
||||
corporation_id='character.corp.id',
|
||||
corporation_name='character.corp.name',
|
||||
corporation_ticker='character.corp.ticker',
|
||||
corporation_ticker='c.c.t', # max 5 chars
|
||||
alliance_id='character.alliance.id',
|
||||
alliance_name='character.alliance.name',
|
||||
)
|
||||
|
||||
run_model_update()
|
||||
|
||||
self.assertEqual(mock_update_corp.delay.call_count, 1)
|
||||
self.assertEqual(mock_update_corp.apply_async.call_count, 1)
|
||||
self.assertEqual(
|
||||
int(mock_update_corp.delay.call_args[0][0]),
|
||||
int(mock_update_corp.apply_async.call_args[1]['args'][0]),
|
||||
2345
|
||||
)
|
||||
|
||||
self.assertEqual(mock_update_alliance.delay.call_count, 1)
|
||||
self.assertEqual(mock_update_alliance.apply_async.call_count, 1)
|
||||
self.assertEqual(
|
||||
int(mock_update_alliance.delay.call_args[0][0]),
|
||||
int(mock_update_alliance.apply_async.call_args[1]['args'][0]),
|
||||
3456
|
||||
)
|
||||
|
||||
self.assertEqual(mock_update_character.delay.call_count, 1)
|
||||
self.assertEqual(mock_update_character.apply_async.call_count, 1)
|
||||
self.assertEqual(
|
||||
int(mock_update_character.delay.call_args[0][0]),
|
||||
int(mock_update_character.apply_async.call_args[1]['args'][0]),
|
||||
1234
|
||||
)
|
||||
|
||||
|
||||
@@ -1,27 +1,53 @@
|
||||
from django.contrib.auth.models import Group
|
||||
from django.db.models import Q
|
||||
import logging
|
||||
|
||||
from django.contrib.auth.models import Group, User
|
||||
from django.db.models import Q, QuerySet
|
||||
|
||||
from allianceauth.authentication.models import State
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class GroupManager:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def get_joinable_groups_for_user(
|
||||
cls, user: User, include_hidden = True
|
||||
) -> QuerySet:
|
||||
"""get groups a user could join incl. groups already joined"""
|
||||
groups_qs = cls.get_joinable_groups(user.profile.state)
|
||||
|
||||
if not user.has_perm('groupmanagement.request_groups'):
|
||||
groups_qs = groups_qs.filter(authgroup__public=True)
|
||||
|
||||
if not include_hidden:
|
||||
groups_qs = groups_qs.filter(authgroup__hidden=False)
|
||||
|
||||
return groups_qs
|
||||
|
||||
@staticmethod
|
||||
def get_joinable_groups(state):
|
||||
return Group.objects.select_related('authgroup').exclude(authgroup__internal=True)\
|
||||
def get_joinable_groups(state: State) -> QuerySet:
|
||||
"""get groups that can be joined by user with given state"""
|
||||
return Group.objects\
|
||||
.select_related('authgroup')\
|
||||
.exclude(authgroup__internal=True)\
|
||||
.filter(Q(authgroup__states=state) | Q(authgroup__states=None))
|
||||
|
||||
@staticmethod
|
||||
def get_all_non_internal_groups():
|
||||
return Group.objects.select_related('authgroup').exclude(authgroup__internal=True)
|
||||
def get_all_non_internal_groups() -> QuerySet:
|
||||
"""get groups that are not internal"""
|
||||
return Group.objects\
|
||||
.select_related('authgroup')\
|
||||
.exclude(authgroup__internal=True)
|
||||
|
||||
@staticmethod
|
||||
def get_group_leaders_groups(user):
|
||||
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())
|
||||
|
||||
@staticmethod
|
||||
def joinable_group(group, state):
|
||||
def joinable_group(group: Group, state: State) -> bool:
|
||||
"""
|
||||
Check if a group is a user/state joinable group, i.e.
|
||||
not an internal group for Corp, Alliance, Members etc,
|
||||
@@ -30,12 +56,15 @@ class GroupManager:
|
||||
:param state: allianceauth.authentication.State object
|
||||
:return: bool True if its joinable, False otherwise
|
||||
"""
|
||||
if len(group.authgroup.states.all()) != 0 and state not in group.authgroup.states.all():
|
||||
if (len(group.authgroup.states.all()) != 0
|
||||
and state not in group.authgroup.states.all()
|
||||
):
|
||||
return False
|
||||
return not group.authgroup.internal
|
||||
else:
|
||||
return not group.authgroup.internal
|
||||
|
||||
@staticmethod
|
||||
def check_internal_group(group):
|
||||
def check_internal_group(group: Group) -> bool:
|
||||
"""
|
||||
Check if a group is auditable, i.e not an internal group
|
||||
:param group: django.contrib.auth.models.Group object
|
||||
@@ -44,20 +73,11 @@ class GroupManager:
|
||||
return not group.authgroup.internal
|
||||
|
||||
@staticmethod
|
||||
def check_internal_group(group):
|
||||
"""
|
||||
Check if a group is auditable, i.e not an internal group
|
||||
:param group: django.contrib.auth.models.Group object
|
||||
:return: bool True if it is auditable, false otherwise
|
||||
"""
|
||||
return not group.authgroup.internal
|
||||
|
||||
@staticmethod
|
||||
def has_management_permission(user):
|
||||
def has_management_permission(user: User) -> bool:
|
||||
return user.has_perm('auth.group_management')
|
||||
|
||||
@classmethod
|
||||
def can_manage_groups(cls, user):
|
||||
def can_manage_groups(cls, user:User ) -> bool:
|
||||
"""
|
||||
For use with user_passes_test decorator.
|
||||
Check if the user can manage groups. Either has the
|
||||
@@ -71,7 +91,7 @@ class GroupManager:
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
def can_manage_group(cls, user, group):
|
||||
def can_manage_group(cls, user: User, group: Group) -> bool:
|
||||
"""
|
||||
Check user has permission to manage the given group
|
||||
:param user: User object to test permission of
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
<div class="panel-body">
|
||||
<p>
|
||||
<a class="btn btn-default" href="{% url 'groupmanagement:membership' %}" role="button">
|
||||
Back
|
||||
{% trans "Back" %}
|
||||
</a>
|
||||
</p>
|
||||
{% if entries %}
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<div class="panel-body">
|
||||
<p>
|
||||
<a class="btn btn-default" href="{% url 'groupmanagement:membership' %}" role="button">
|
||||
Back
|
||||
{% trans "Back" %}
|
||||
</a>
|
||||
</p>
|
||||
{% if group.user_set %}
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
{% include 'groupmanagement/menu.html' %}
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
Groups
|
||||
{% trans "Groups" %}
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
{% if groups %}
|
||||
|
||||
@@ -1,107 +0,0 @@
|
||||
from unittest import mock
|
||||
|
||||
from django.test import TestCase
|
||||
from allianceauth.tests.auth_utils import AuthUtils
|
||||
from allianceauth.eveonline.models import EveCorporationInfo, EveAllianceInfo, EveCharacter
|
||||
from django.contrib.auth.models import User, Group
|
||||
from allianceauth.groupmanagement.managers import GroupManager
|
||||
from allianceauth.groupmanagement.signals import check_groups_on_state_change
|
||||
|
||||
class GroupManagementVisibilityTestCase(TestCase):
|
||||
@classmethod
|
||||
def setUpTestData(cls):
|
||||
cls.user = AuthUtils.create_user('test')
|
||||
AuthUtils.add_main_character(cls.user, 'test character', '1', corp_id='2', corp_name='test_corp', corp_ticker='TEST', alliance_id='3', alliance_name='TEST')
|
||||
cls.user.profile.refresh_from_db()
|
||||
cls.alliance = EveAllianceInfo.objects.create(alliance_id='3', alliance_name='test alliance', alliance_ticker='TEST', executor_corp_id='2')
|
||||
cls.corp = EveCorporationInfo.objects.create(corporation_id='2', corporation_name='test corp', corporation_ticker='TEST', alliance=cls.alliance, member_count=1)
|
||||
cls.group1 = Group.objects.create(name='group1')
|
||||
cls.group2 = Group.objects.create(name='group2')
|
||||
cls.group3 = Group.objects.create(name='group3')
|
||||
|
||||
def setUp(self):
|
||||
self.user.refresh_from_db()
|
||||
|
||||
def _refresh_user(self):
|
||||
self.user = User.objects.get(pk=self.user.pk)
|
||||
|
||||
|
||||
def test_get_group_leaders_groups(self):
|
||||
self.group1.authgroup.group_leaders.add(self.user)
|
||||
self.group2.authgroup.group_leader_groups.add(self.group1)
|
||||
self._refresh_user()
|
||||
groups = GroupManager.get_group_leaders_groups(self.user)
|
||||
|
||||
self.assertIn(self.group1, groups) #avail due to user
|
||||
self.assertNotIn(self.group2, groups) #not avail due to group
|
||||
self.assertNotIn(self.group3, groups) #not avail at all
|
||||
|
||||
self.user.groups.add(self.group1)
|
||||
self._refresh_user()
|
||||
groups = GroupManager.get_group_leaders_groups(self.user)
|
||||
|
||||
self.assertIn(self.group1, groups) #avail due to user
|
||||
self.assertIn(self.group2, groups) #avail due to group1
|
||||
self.assertNotIn(self.group3, groups) #not avail at all
|
||||
|
||||
def test_can_manage_group(self):
|
||||
self.group1.authgroup.group_leaders.add(self.user)
|
||||
self.user.groups.add(self.group1)
|
||||
self._refresh_user()
|
||||
|
||||
self.assertTrue(GroupManager.can_manage_group(self.user, self.group1))
|
||||
self.assertFalse(GroupManager.can_manage_group(self.user, self.group2))
|
||||
self.assertFalse(GroupManager.can_manage_group(self.user, self.group3))
|
||||
|
||||
self.group2.authgroup.group_leader_groups.add(self.group1)
|
||||
self.group1.authgroup.group_leaders.remove(self.user)
|
||||
self._refresh_user()
|
||||
|
||||
self.assertFalse(GroupManager.can_manage_group(self.user, self.group1))
|
||||
self.assertTrue(GroupManager.can_manage_group(self.user, self.group2))
|
||||
self.assertFalse(GroupManager.can_manage_group(self.user, self.group3))
|
||||
|
||||
|
||||
class GroupManagementStateTestCase(TestCase):
|
||||
@classmethod
|
||||
def setUpTestData(cls):
|
||||
cls.user = AuthUtils.create_user('test')
|
||||
AuthUtils.add_main_character(cls.user, 'test character', '1', corp_id='2', corp_name='test_corp', corp_ticker='TEST', alliance_id='3', alliance_name='TEST')
|
||||
cls.user.profile.refresh_from_db()
|
||||
cls.alliance = EveAllianceInfo.objects.create(alliance_id='3', alliance_name='test alliance', alliance_ticker='TEST', executor_corp_id='2')
|
||||
cls.corp = EveCorporationInfo.objects.create(corporation_id='2', corporation_name='test corp', corporation_ticker='TEST', alliance=cls.alliance, member_count=1)
|
||||
cls.state_group = Group.objects.create(name='state_group')
|
||||
cls.open_group = Group.objects.create(name='open_group')
|
||||
cls.state = AuthUtils.create_state('test state', 500)
|
||||
cls.state_group.authgroup.states.add(cls.state)
|
||||
cls.state_group.authgroup.internal = False
|
||||
cls.state_group.save()
|
||||
|
||||
def setUp(self):
|
||||
self.user.refresh_from_db()
|
||||
self.state.refresh_from_db()
|
||||
|
||||
def _refresh_user(self):
|
||||
self.user = User.objects.get(pk=self.user.pk)
|
||||
|
||||
def _refresh_test_group(self):
|
||||
self.state_group = Group.objects.get(pk=self.state_group.pk)
|
||||
|
||||
def test_drop_state_group(self):
|
||||
self.user.groups.add(self.open_group)
|
||||
self.user.groups.add(self.state_group)
|
||||
self.assertEqual(self.user.profile.state.name, "Guest")
|
||||
|
||||
self.state.member_corporations.add(self.corp)
|
||||
self._refresh_user()
|
||||
self.assertEqual(self.user.profile.state, self.state)
|
||||
groups = self.user.groups.all()
|
||||
self.assertIn(self.state_group, groups) #keeps group
|
||||
self.assertIn(self.open_group, groups) #public group unafected
|
||||
|
||||
self.state.member_corporations.clear()
|
||||
self._refresh_user()
|
||||
self.assertEqual(self.user.profile.state.name, "Guest")
|
||||
groups = self.user.groups.all()
|
||||
self.assertNotIn(self.state_group, groups) #looses group
|
||||
self.assertIn(self.open_group, groups) #public group unafected
|
||||
337
allianceauth/groupmanagement/tests/test_managers.py
Normal file
337
allianceauth/groupmanagement/tests/test_managers.py
Normal file
@@ -0,0 +1,337 @@
|
||||
from unittest.mock import Mock, patch
|
||||
|
||||
from django.contrib.auth.models import Group, User
|
||||
from django.test import TestCase
|
||||
from django.urls import reverse
|
||||
|
||||
from allianceauth.eveonline.models import EveCorporationInfo, EveAllianceInfo
|
||||
from allianceauth.tests.auth_utils import AuthUtils
|
||||
|
||||
from ..models import AuthGroup
|
||||
from ..managers import GroupManager
|
||||
|
||||
|
||||
class MockUserNotAuthenticated():
|
||||
def __init__(self):
|
||||
self.is_authenticated = False
|
||||
|
||||
class GroupManagementVisibilityTestCase(TestCase):
|
||||
@classmethod
|
||||
def setUpTestData(cls):
|
||||
cls.user = AuthUtils.create_user('test')
|
||||
AuthUtils.add_main_character(
|
||||
cls.user, 'test character', '1', corp_id='2', corp_name='test_corp', corp_ticker='TEST', alliance_id='3', alliance_name='TEST'
|
||||
)
|
||||
cls.user.profile.refresh_from_db()
|
||||
cls.alliance = EveAllianceInfo.objects.create(alliance_id='3', alliance_name='test alliance', alliance_ticker='TEST', executor_corp_id='2')
|
||||
cls.corp = EveCorporationInfo.objects.create(
|
||||
corporation_id='2', corporation_name='test corp', corporation_ticker='TEST', alliance=cls.alliance, member_count=1
|
||||
)
|
||||
cls.group1 = Group.objects.create(name='group1')
|
||||
cls.group2 = Group.objects.create(name='group2')
|
||||
cls.group3 = Group.objects.create(name='group3')
|
||||
|
||||
def setUp(self):
|
||||
self.user.refresh_from_db()
|
||||
|
||||
def _refresh_user(self):
|
||||
self.user = User.objects.get(pk=self.user.pk)
|
||||
|
||||
|
||||
def test_get_group_leaders_groups(self):
|
||||
self.group1.authgroup.group_leaders.add(self.user)
|
||||
self.group2.authgroup.group_leader_groups.add(self.group1)
|
||||
self._refresh_user()
|
||||
groups = GroupManager.get_group_leaders_groups(self.user)
|
||||
|
||||
self.assertIn(self.group1, groups) #avail due to user
|
||||
self.assertNotIn(self.group2, groups) #not avail due to group
|
||||
self.assertNotIn(self.group3, groups) #not avail at all
|
||||
|
||||
self.user.groups.add(self.group1)
|
||||
self._refresh_user()
|
||||
groups = GroupManager.get_group_leaders_groups(self.user)
|
||||
|
||||
|
||||
def test_can_manage_group(self):
|
||||
self.group1.authgroup.group_leaders.add(self.user)
|
||||
self.user.groups.add(self.group1)
|
||||
self._refresh_user()
|
||||
|
||||
self.assertTrue(GroupManager.can_manage_group(self.user, self.group1))
|
||||
self.assertFalse(GroupManager.can_manage_group(self.user, self.group2))
|
||||
self.assertFalse(GroupManager.can_manage_group(self.user, self.group3))
|
||||
|
||||
self.group2.authgroup.group_leader_groups.add(self.group1)
|
||||
self.group1.authgroup.group_leaders.remove(self.user)
|
||||
self._refresh_user()
|
||||
|
||||
self.assertFalse(GroupManager.can_manage_group(self.user, self.group1))
|
||||
self.assertTrue(GroupManager.can_manage_group(self.user, self.group2))
|
||||
self.assertFalse(GroupManager.can_manage_group(self.user, self.group3))
|
||||
|
||||
|
||||
class TestGroupManager(TestCase):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
|
||||
# group 1
|
||||
cls.group_default = Group.objects.create(name='default')
|
||||
cls.group_default.authgroup.description = 'Default Group'
|
||||
cls.group_default.authgroup.internal = False
|
||||
cls.group_default.authgroup.hidden = False
|
||||
cls.group_default.authgroup.save()
|
||||
|
||||
# group 2
|
||||
cls.group_internal = Group.objects.create(name='internal')
|
||||
cls.group_internal.authgroup.description = 'Internal Group'
|
||||
cls.group_internal.authgroup.internal = True
|
||||
cls.group_internal.authgroup.save()
|
||||
|
||||
# group 3
|
||||
cls.group_hidden = Group.objects.create(name='hidden')
|
||||
cls.group_hidden.authgroup.description = 'Hidden Group'
|
||||
cls.group_hidden.authgroup.internal = False
|
||||
cls.group_hidden.authgroup.hidden = True
|
||||
cls.group_hidden.authgroup.save()
|
||||
|
||||
# group 4
|
||||
cls.group_open = Group.objects.create(name='open')
|
||||
cls.group_open.authgroup.description = 'Open Group'
|
||||
cls.group_open.authgroup.internal = False
|
||||
cls.group_open.authgroup.hidden = False
|
||||
cls.group_open.authgroup.open = True
|
||||
cls.group_open.authgroup.save()
|
||||
|
||||
# group 5
|
||||
cls.group_public_1 = Group.objects.create(name='public 1')
|
||||
cls.group_public_1.authgroup.description = 'Public Group 1'
|
||||
cls.group_public_1.authgroup.internal = False
|
||||
cls.group_public_1.authgroup.hidden = False
|
||||
cls.group_public_1.authgroup.public = True
|
||||
cls.group_public_1.authgroup.save()
|
||||
|
||||
# group 6
|
||||
cls.group_public_2 = Group.objects.create(name='public 2')
|
||||
cls.group_public_2.authgroup.description = 'Public Group 2'
|
||||
cls.group_public_2.authgroup.internal = False
|
||||
cls.group_public_2.authgroup.hidden = True
|
||||
cls.group_public_2.authgroup.open = True
|
||||
cls.group_public_2.authgroup.public = True
|
||||
cls.group_public_2.authgroup.save()
|
||||
|
||||
# group 7
|
||||
cls.group_default_member = Group.objects.create(name='default members')
|
||||
cls.group_default_member.authgroup.description = \
|
||||
'Default Group for members only'
|
||||
cls.group_default_member.authgroup.internal = False
|
||||
cls.group_default_member.authgroup.hidden = False
|
||||
cls.group_default_member.authgroup.open = False
|
||||
cls.group_default_member.authgroup.public = False
|
||||
cls.group_default_member.authgroup.states.add(
|
||||
AuthUtils.get_member_state()
|
||||
)
|
||||
cls.group_default_member.authgroup.save()
|
||||
|
||||
def setUp(self):
|
||||
self.user = AuthUtils.create_user('Bruce Wayne')
|
||||
|
||||
def test_get_joinable_group_member(self):
|
||||
result = GroupManager.get_joinable_groups(
|
||||
AuthUtils.get_member_state()
|
||||
)
|
||||
expected = {
|
||||
self.group_default,
|
||||
self.group_hidden,
|
||||
self.group_open,
|
||||
self.group_public_1,
|
||||
self.group_public_2,
|
||||
self.group_default_member
|
||||
}
|
||||
self.assertSetEqual(set(result), expected)
|
||||
|
||||
def test_get_joinable_group_guest(self):
|
||||
result = GroupManager.get_joinable_groups(
|
||||
AuthUtils.get_guest_state()
|
||||
)
|
||||
expected = {
|
||||
self.group_default,
|
||||
self.group_hidden,
|
||||
self.group_open,
|
||||
self.group_public_1,
|
||||
self.group_public_2
|
||||
}
|
||||
self.assertSetEqual(set(result), expected)
|
||||
|
||||
def test_joinable_group_member(self):
|
||||
member_state = AuthUtils.get_member_state()
|
||||
for x in [
|
||||
self.group_default,
|
||||
self.group_hidden,
|
||||
self.group_open,
|
||||
self.group_public_1,
|
||||
self.group_public_2,
|
||||
self.group_default_member
|
||||
]:
|
||||
self.assertTrue(GroupManager.joinable_group(x, member_state))
|
||||
|
||||
for x in [
|
||||
self.group_internal,
|
||||
]:
|
||||
self.assertFalse(GroupManager.joinable_group(x, member_state))
|
||||
|
||||
|
||||
def test_joinable_group_guest(self):
|
||||
guest_state = AuthUtils.get_guest_state()
|
||||
for x in [
|
||||
self.group_default,
|
||||
self.group_hidden,
|
||||
self.group_open,
|
||||
self.group_public_1,
|
||||
self.group_public_2
|
||||
]:
|
||||
self.assertTrue(GroupManager.joinable_group(x, guest_state))
|
||||
|
||||
for x in [
|
||||
self.group_internal,
|
||||
self.group_default_member
|
||||
]:
|
||||
self.assertFalse(GroupManager.joinable_group(x, guest_state))
|
||||
|
||||
|
||||
def test_get_all_non_internal_groups(self):
|
||||
result = GroupManager.get_all_non_internal_groups()
|
||||
expected = {
|
||||
self.group_default,
|
||||
self.group_hidden,
|
||||
self.group_open,
|
||||
self.group_public_1,
|
||||
self.group_public_2,
|
||||
self.group_default_member
|
||||
}
|
||||
self.assertSetEqual(set(result), expected)
|
||||
|
||||
def test_check_internal_group(self):
|
||||
self.assertTrue(
|
||||
GroupManager.check_internal_group(self.group_default)
|
||||
)
|
||||
self.assertFalse(
|
||||
GroupManager.check_internal_group(self.group_internal)
|
||||
)
|
||||
|
||||
def test_get_joinable_groups_for_user_no_permission(self):
|
||||
AuthUtils.assign_state(self.user, AuthUtils.get_guest_state())
|
||||
result = GroupManager.get_joinable_groups_for_user(self.user)
|
||||
expected= {self.group_public_1, self.group_public_2}
|
||||
self.assertSetEqual(set(result), expected)
|
||||
|
||||
def test_get_joinable_groups_for_user_guest_w_permission_(self):
|
||||
AuthUtils.assign_state(self.user, AuthUtils.get_guest_state())
|
||||
AuthUtils.add_permission_to_user_by_name(
|
||||
'groupmanagement.request_groups', self.user
|
||||
)
|
||||
result = GroupManager.get_joinable_groups_for_user(self.user)
|
||||
expected = {
|
||||
self.group_default,
|
||||
self.group_hidden,
|
||||
self.group_open,
|
||||
self.group_public_1,
|
||||
self.group_public_2
|
||||
}
|
||||
self.assertSetEqual(set(result), expected)
|
||||
|
||||
def test_get_joinable_groups_for_user_member_w_permission(self):
|
||||
AuthUtils.assign_state(self.user, AuthUtils.get_member_state(), True)
|
||||
AuthUtils.add_permission_to_user_by_name(
|
||||
'groupmanagement.request_groups', self.user
|
||||
)
|
||||
result = GroupManager.get_joinable_groups_for_user(self.user)
|
||||
expected = {
|
||||
self.group_default,
|
||||
self.group_hidden,
|
||||
self.group_open,
|
||||
self.group_public_1,
|
||||
self.group_public_2,
|
||||
self.group_default_member
|
||||
}
|
||||
self.assertSetEqual(set(result), expected)
|
||||
|
||||
def test_get_joinable_groups_for_user_member_w_permission_no_hidden(self):
|
||||
AuthUtils.assign_state(self.user, AuthUtils.get_member_state(), True)
|
||||
AuthUtils.add_permission_to_user_by_name(
|
||||
'groupmanagement.request_groups', self.user
|
||||
)
|
||||
result = GroupManager.get_joinable_groups_for_user(
|
||||
self.user, include_hidden=False
|
||||
)
|
||||
expected = {
|
||||
self.group_default,
|
||||
self.group_open,
|
||||
self.group_public_1,
|
||||
self.group_default_member
|
||||
}
|
||||
self.assertSetEqual(set(result), expected)
|
||||
|
||||
def test_has_management_permission(self):
|
||||
user = AuthUtils.create_user('Clark Kent')
|
||||
AuthUtils.add_permission_to_user_by_name(
|
||||
'auth.group_management', user
|
||||
)
|
||||
self.assertTrue(GroupManager.has_management_permission(user))
|
||||
|
||||
def test_can_manage_groups_no_perm_no_group(self):
|
||||
user = AuthUtils.create_user('Clark Kent')
|
||||
self.assertFalse(GroupManager.can_manage_groups(user))
|
||||
|
||||
def test_can_manage_groups_user_not_authenticated(self):
|
||||
user = MockUserNotAuthenticated()
|
||||
self.assertFalse(GroupManager.can_manage_groups(user))
|
||||
|
||||
def test_can_manage_groups_has_perm(self):
|
||||
user = AuthUtils.create_user('Clark Kent')
|
||||
AuthUtils.add_permission_to_user_by_name(
|
||||
'auth.group_management', user
|
||||
)
|
||||
self.assertTrue(GroupManager.can_manage_groups(user))
|
||||
|
||||
def test_can_manage_groups_no_perm_leads_group(self):
|
||||
user = AuthUtils.create_user('Clark Kent')
|
||||
self.group_default.authgroup.group_leaders.add(user)
|
||||
self.assertTrue(GroupManager.can_manage_groups(user))
|
||||
|
||||
def test_can_manage_group_no_perm_no_group(self):
|
||||
user = AuthUtils.create_user('Clark Kent')
|
||||
self.assertFalse(
|
||||
GroupManager.can_manage_group(user, self.group_default)
|
||||
)
|
||||
|
||||
def test_can_manage_group_has_perm(self):
|
||||
user = AuthUtils.create_user('Clark Kent')
|
||||
AuthUtils.add_permission_to_user_by_name(
|
||||
'auth.group_management', user
|
||||
)
|
||||
self.assertTrue(
|
||||
GroupManager.can_manage_group(user, self.group_default)
|
||||
)
|
||||
|
||||
def test_can_manage_group_no_perm_leads_correct_group(self):
|
||||
user = AuthUtils.create_user('Clark Kent')
|
||||
self.group_default.authgroup.group_leaders.add(user)
|
||||
self.assertTrue(
|
||||
GroupManager.can_manage_group(user, self.group_default)
|
||||
)
|
||||
|
||||
def test_can_manage_group_no_perm_leads_other_group(self):
|
||||
user = AuthUtils.create_user('Clark Kent')
|
||||
self.group_hidden.authgroup.group_leaders.add(user)
|
||||
self.assertFalse(
|
||||
GroupManager.can_manage_group(user, self.group_default)
|
||||
)
|
||||
|
||||
def test_can_manage_group_user_not_authenticated(self):
|
||||
user = MockUserNotAuthenticated()
|
||||
self.assertFalse(
|
||||
GroupManager.can_manage_group(user, self.group_default)
|
||||
)
|
||||
167
allianceauth/groupmanagement/tests/test_models.py
Normal file
167
allianceauth/groupmanagement/tests/test_models.py
Normal file
@@ -0,0 +1,167 @@
|
||||
from unittest import mock
|
||||
|
||||
from django.contrib.auth.models import User, Group
|
||||
from django.test import TestCase
|
||||
|
||||
from allianceauth.tests.auth_utils import AuthUtils
|
||||
from allianceauth.eveonline.models import (
|
||||
EveCorporationInfo, EveAllianceInfo, EveCharacter
|
||||
)
|
||||
|
||||
from ..models import GroupRequest, RequestLog
|
||||
|
||||
|
||||
def create_testdata():
|
||||
# clear DB
|
||||
User.objects.all().delete()
|
||||
Group.objects.all().delete()
|
||||
EveCharacter.objects.all().delete()
|
||||
EveCorporationInfo.objects.all().delete()
|
||||
EveAllianceInfo.objects.all().delete()
|
||||
|
||||
# group 1
|
||||
group = Group.objects.create(name='Superheros')
|
||||
group.authgroup.description = 'Default Group'
|
||||
group.authgroup.internal = False
|
||||
group.authgroup.hidden = False
|
||||
group.authgroup.save()
|
||||
|
||||
# user 1
|
||||
user_1 = AuthUtils.create_user('Bruce Wayne')
|
||||
AuthUtils.add_main_character_2(
|
||||
user_1,
|
||||
name='Bruce Wayne',
|
||||
character_id=1001,
|
||||
corp_id=2001,
|
||||
corp_name='Wayne Technologies'
|
||||
)
|
||||
user_1.groups.add(group)
|
||||
group.authgroup.group_leaders.add(user_1)
|
||||
|
||||
# user 2
|
||||
user_2 = AuthUtils.create_user('Clark Kent')
|
||||
AuthUtils.add_main_character_2(
|
||||
user_2,
|
||||
name='Clark Kent',
|
||||
character_id=1002,
|
||||
corp_id=2002,
|
||||
corp_name='Wayne Technologies'
|
||||
)
|
||||
return group, user_1, user_2
|
||||
|
||||
|
||||
|
||||
class TestGroupRequest(TestCase):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
cls.group, cls.user_1, _ = create_testdata()
|
||||
|
||||
def test_main_char(self):
|
||||
group_request = GroupRequest.objects.create(
|
||||
status='Pending',
|
||||
user=self.user_1,
|
||||
group=self.group
|
||||
)
|
||||
expected = self.user_1.profile.main_character
|
||||
self.assertEqual(group_request.main_char, expected)
|
||||
|
||||
def test_str(self):
|
||||
group_request = GroupRequest.objects.create(
|
||||
status='Pending',
|
||||
user=self.user_1,
|
||||
group=self.group
|
||||
)
|
||||
expected = 'Bruce Wayne:Superheros'
|
||||
self.assertEqual(str(group_request), expected)
|
||||
|
||||
|
||||
class TestRequestLog(TestCase):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
cls.group, cls.user_1, cls.user_2 = create_testdata()
|
||||
|
||||
def test_requestor(self):
|
||||
request_log = RequestLog.objects.create(
|
||||
group=self.group,
|
||||
request_info='Clark Kent:Superheros',
|
||||
request_actor=self.user_1
|
||||
)
|
||||
expected = 'Clark Kent'
|
||||
self.assertEqual(request_log.requestor(), expected)
|
||||
|
||||
def test_type_to_str_removed(self):
|
||||
request_log = RequestLog.objects.create(
|
||||
request_type=None,
|
||||
group=self.group,
|
||||
request_info='Clark Kent:Superheros',
|
||||
request_actor=self.user_1
|
||||
)
|
||||
expected = 'Removed'
|
||||
self.assertEqual(request_log.type_to_str(), expected)
|
||||
|
||||
def test_type_to_str_leave(self):
|
||||
request_log = RequestLog.objects.create(
|
||||
request_type=True,
|
||||
group=self.group,
|
||||
request_info='Clark Kent:Superheros',
|
||||
request_actor=self.user_1
|
||||
)
|
||||
expected = 'Leave'
|
||||
self.assertEqual(request_log.type_to_str(), expected)
|
||||
|
||||
def test_type_to_str_join(self):
|
||||
request_log = RequestLog.objects.create(
|
||||
request_type=False,
|
||||
group=self.group,
|
||||
request_info='Clark Kent:Superheros',
|
||||
request_actor=self.user_1
|
||||
)
|
||||
expected = 'Join'
|
||||
self.assertEqual(request_log.type_to_str(), expected)
|
||||
|
||||
def test_action_to_str_accept(self):
|
||||
request_log = RequestLog.objects.create(
|
||||
group=self.group,
|
||||
request_info='Clark Kent:Superheros',
|
||||
request_actor=self.user_1,
|
||||
action = True
|
||||
)
|
||||
expected = 'Accept'
|
||||
self.assertEqual(request_log.action_to_str(), expected)
|
||||
|
||||
def test_action_to_str_reject(self):
|
||||
request_log = RequestLog.objects.create(
|
||||
group=self.group,
|
||||
request_info='Clark Kent:Superheros',
|
||||
request_actor=self.user_1,
|
||||
action = False
|
||||
)
|
||||
expected = 'Reject'
|
||||
self.assertEqual(request_log.action_to_str(), expected)
|
||||
|
||||
def test_req_char(self):
|
||||
request_log = RequestLog.objects.create(
|
||||
group=self.group,
|
||||
request_info='Clark Kent:Superheros',
|
||||
request_actor=self.user_1,
|
||||
action = False
|
||||
)
|
||||
expected = self.user_2.profile.main_character
|
||||
self.assertEqual(request_log.req_char(), expected)
|
||||
|
||||
|
||||
class TestAuthGroup(TestCase):
|
||||
|
||||
def test_str(self):
|
||||
group = Group.objects.create(name='Superheros')
|
||||
group.authgroup.description = 'Default Group'
|
||||
group.authgroup.internal = False
|
||||
group.authgroup.hidden = False
|
||||
group.authgroup.save()
|
||||
|
||||
expected = 'Superheros'
|
||||
self.assertEqual(str(group.authgroup), expected)
|
||||
61
allianceauth/groupmanagement/tests/test_signals.py
Normal file
61
allianceauth/groupmanagement/tests/test_signals.py
Normal file
@@ -0,0 +1,61 @@
|
||||
from unittest import mock
|
||||
|
||||
from django.test import TestCase
|
||||
from django.contrib.auth.models import User, Group
|
||||
|
||||
from allianceauth.eveonline.models import EveCorporationInfo, EveAllianceInfo
|
||||
from allianceauth.tests.auth_utils import AuthUtils
|
||||
|
||||
from ..signals import check_groups_on_state_change
|
||||
|
||||
|
||||
class GroupManagementStateTestCase(TestCase):
|
||||
|
||||
@classmethod
|
||||
def setUpTestData(cls):
|
||||
cls.user = AuthUtils.create_user('test')
|
||||
AuthUtils.add_main_character(
|
||||
cls.user, 'test character', '1', corp_id='2', corp_name='test_corp', corp_ticker='TEST', alliance_id='3', alliance_name='TEST'
|
||||
)
|
||||
cls.user.profile.refresh_from_db()
|
||||
cls.alliance = EveAllianceInfo.objects.create(
|
||||
alliance_id='3', alliance_name='test alliance', alliance_ticker='TEST', executor_corp_id='2'
|
||||
)
|
||||
cls.corp = EveCorporationInfo.objects.create(
|
||||
corporation_id='2', corporation_name='test corp', corporation_ticker='TEST', alliance=cls.alliance, member_count=1
|
||||
)
|
||||
cls.state_group = Group.objects.create(name='state_group')
|
||||
cls.open_group = Group.objects.create(name='open_group')
|
||||
cls.state = AuthUtils.create_state('test state', 500)
|
||||
cls.state_group.authgroup.states.add(cls.state)
|
||||
cls.state_group.authgroup.internal = False
|
||||
cls.state_group.save()
|
||||
|
||||
def setUp(self):
|
||||
self.user.refresh_from_db()
|
||||
self.state.refresh_from_db()
|
||||
|
||||
def _refresh_user(self):
|
||||
self.user = User.objects.get(pk=self.user.pk)
|
||||
|
||||
def _refresh_test_group(self):
|
||||
self.state_group = Group.objects.get(pk=self.state_group.pk)
|
||||
|
||||
def test_drop_state_group(self):
|
||||
self.user.groups.add(self.open_group)
|
||||
self.user.groups.add(self.state_group)
|
||||
self.assertEqual(self.user.profile.state.name, "Guest")
|
||||
|
||||
self.state.member_corporations.add(self.corp)
|
||||
self._refresh_user()
|
||||
self.assertEqual(self.user.profile.state, self.state)
|
||||
groups = self.user.groups.all()
|
||||
self.assertIn(self.state_group, groups) #keeps group
|
||||
self.assertIn(self.open_group, groups) #public group unafected
|
||||
|
||||
self.state.member_corporations.clear()
|
||||
self._refresh_user()
|
||||
self.assertEqual(self.user.profile.state.name, "Guest")
|
||||
groups = self.user.groups.all()
|
||||
self.assertNotIn(self.state_group, groups) #looses group
|
||||
self.assertIn(self.open_group, groups) #public group unafected
|
||||
22
allianceauth/groupmanagement/tests/test_views.py
Normal file
22
allianceauth/groupmanagement/tests/test_views.py
Normal file
@@ -0,0 +1,22 @@
|
||||
from unittest.mock import Mock, patch
|
||||
|
||||
from django.test import RequestFactory, TestCase
|
||||
from django.urls import reverse
|
||||
|
||||
from allianceauth.tests.auth_utils import AuthUtils
|
||||
from esi.models import Token
|
||||
|
||||
from .. import views
|
||||
|
||||
|
||||
class TestViews(TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.factory = RequestFactory()
|
||||
self.user = AuthUtils.create_user('Bruce Wayne')
|
||||
|
||||
def test_groups_view_can_load(self):
|
||||
request = self.factory.get(reverse('groupmanagement:groups'))
|
||||
request.user = self.user
|
||||
response = views.groups_view(request)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
@@ -1,5 +1,6 @@
|
||||
import logging
|
||||
|
||||
from django.conf import settings
|
||||
from django.contrib import messages
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.contrib.auth.decorators import user_passes_test
|
||||
@@ -10,12 +11,12 @@ from django.db.models import Count
|
||||
from django.http import Http404
|
||||
from django.shortcuts import render, redirect, get_object_or_404
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from .managers import GroupManager
|
||||
from .models import GroupRequest, RequestLog
|
||||
|
||||
from allianceauth.notifications import notify
|
||||
|
||||
from django.conf import settings
|
||||
from .managers import GroupManager
|
||||
from .models import GroupRequest, RequestLog
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -235,7 +236,7 @@ def group_reject_request(request, 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})
|
||||
logger.exception("Unhandled exception occured while user %s attempting to reject group request id %s" % (
|
||||
logger.exception("Unhandled exception occurred while user %s attempting to reject group request id %s" % (
|
||||
request.user, group_request_id))
|
||||
pass
|
||||
|
||||
@@ -269,9 +270,9 @@ def group_leave_accept_request(request, group_request_id):
|
||||
(request.user, group_request_id))
|
||||
raise p
|
||||
except:
|
||||
messages.error(request, _('An unhandled error occured while processing the application from %(mainchar)s to leave %(group)s.') % {
|
||||
messages.error(request, _('An unhandled error occurred while processing the application from %(mainchar)s to leave %(group)s.') % {
|
||||
"mainchar": group_request.main_char, "group": group_request.group})
|
||||
logger.exception("Unhandled exception occured while user %s attempting to accept group leave request id %s" % (
|
||||
logger.exception("Unhandled exception occurred while user %s attempting to accept group leave request id %s" % (
|
||||
request.user, group_request_id))
|
||||
pass
|
||||
|
||||
@@ -303,9 +304,9 @@ def group_leave_reject_request(request, group_request_id):
|
||||
(request.user, group_request_id))
|
||||
raise p
|
||||
except:
|
||||
messages.error(request, _('An unhandled error occured while processing the application from %(mainchar)s to leave %(group)s.') % {
|
||||
messages.error(request, _('An unhandled error occurred while processing the application from %(mainchar)s to leave %(group)s.') % {
|
||||
"mainchar": group_request.main_char, "group": group_request.group})
|
||||
logger.exception("Unhandled exception occured while user %s attempting to reject group leave request id %s" % (
|
||||
logger.exception("Unhandled exception occurred while user %s attempting to reject group leave request id %s" % (
|
||||
request.user, group_request_id))
|
||||
pass
|
||||
|
||||
@@ -315,24 +316,23 @@ def group_leave_reject_request(request, group_request_id):
|
||||
@login_required
|
||||
def groups_view(request):
|
||||
logger.debug("groups_view called by user %s" % request.user)
|
||||
|
||||
groups_qs = GroupManager.get_joinable_groups_for_user(
|
||||
request.user, include_hidden=False
|
||||
)
|
||||
groups_qs = groups_qs.order_by('name')
|
||||
groups = []
|
||||
for group in groups_qs:
|
||||
group_request = GroupRequest.objects\
|
||||
.filter(user=request.user)\
|
||||
.filter(group=group)
|
||||
groups.append({
|
||||
'group': group,
|
||||
'request': group_request[0] if group_request else None
|
||||
})
|
||||
|
||||
group_query = GroupManager.get_joinable_groups(request.user.profile.state)
|
||||
|
||||
if not request.user.has_perm('groupmanagement.request_groups'):
|
||||
# Filter down to public groups only for non-members
|
||||
group_query = group_query.filter(authgroup__public=True)
|
||||
logger.debug("Not a member, only public groups will be available")
|
||||
|
||||
for group in group_query:
|
||||
# Exclude hidden
|
||||
if not group.authgroup.hidden:
|
||||
group_request = GroupRequest.objects.filter(user=request.user).filter(group=group)
|
||||
|
||||
groups.append({'group': group, 'request': group_request[0] if group_request else None})
|
||||
|
||||
render_items = {'groups': groups}
|
||||
return render(request, 'groupmanagement/groups.html', context=render_items)
|
||||
context = {'groups': groups}
|
||||
return render(request, 'groupmanagement/groups.html', context=context)
|
||||
|
||||
|
||||
@login_required
|
||||
@@ -349,13 +349,13 @@ def group_request_add(request, group_id):
|
||||
# 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))
|
||||
messages.warning(request, "You are already a member of that group.")
|
||||
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))
|
||||
messages.warning(request, "You cannot join that group")
|
||||
messages.warning(request, _("You cannot join that group"))
|
||||
return redirect('groupmanagement:groups')
|
||||
if group.authgroup.open:
|
||||
logger.info("%s joining %s as is an open group" % (request.user, group))
|
||||
@@ -364,7 +364,7 @@ def group_request_add(request, group_id):
|
||||
req = GroupRequest.objects.filter(user=request.user, group=group)
|
||||
if len(req) > 0:
|
||||
logger.info("%s attempted to join %s but already has an open application" % (request.user, group))
|
||||
messages.warning(request, "You already have a pending application for that group.")
|
||||
messages.warning(request, _("You already have a pending application for that group."))
|
||||
return redirect("groupmanagement:groups")
|
||||
grouprequest = GroupRequest()
|
||||
grouprequest.status = _('Pending')
|
||||
@@ -398,7 +398,7 @@ def group_request_leave(request, group_id):
|
||||
req = GroupRequest.objects.filter(user=request.user, group=group)
|
||||
if len(req) > 0:
|
||||
logger.info("%s attempted to leave %s but already has an pending leave request." % (request.user, group))
|
||||
messages.warning(request, "You already have a pending leave request for that group.")
|
||||
messages.warning(request, _("You already have a pending leave request for that group."))
|
||||
return redirect("groupmanagement:groups")
|
||||
if getattr(settings, 'AUTO_LEAVE', False):
|
||||
logger.info("%s leaving joinable group %s due to auto_leave" % (request.user, group))
|
||||
|
||||
Binary file not shown.
@@ -4,18 +4,18 @@
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
# Translators:
|
||||
# Rounon Dax <rounon.dax@terra-nanotech.de>, 2020
|
||||
# Erik Kalkoken <erik.kalkoken@gmail.com>, 2020
|
||||
# Joel Falknau <ozirascal@gmail.com>, 2020
|
||||
# Rounon Dax <rounon.dax@terra-nanotech.de>, 2020
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2020-03-04 23:04+0000\n"
|
||||
"POT-Creation-Date: 2020-04-02 03:23+0000\n"
|
||||
"PO-Revision-Date: 2020-02-18 03:14+0000\n"
|
||||
"Last-Translator: Joel Falknau <ozirascal@gmail.com>, 2020\n"
|
||||
"Last-Translator: Rounon Dax <rounon.dax@terra-nanotech.de>, 2020\n"
|
||||
"Language-Team: German (https://www.transifex.com/alliance-auth/teams/107430/de/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
@@ -71,9 +71,7 @@ msgid "Change Main"
|
||||
msgstr "Hauptcharakter ändern"
|
||||
|
||||
#: allianceauth/authentication/templates/authentication/dashboard.html:97
|
||||
#: allianceauth/permissions_tool/templates/permissions_tool/overview.html:40
|
||||
#: allianceauth/templates/allianceauth/side-menu.html:15
|
||||
msgid "Groups"
|
||||
msgid "Group Memberships"
|
||||
msgstr "Gruppen"
|
||||
|
||||
#: allianceauth/authentication/templates/authentication/dashboard.html:117
|
||||
@@ -140,32 +138,41 @@ msgstr "Euer IT Team"
|
||||
msgid "Submit"
|
||||
msgstr "Absenden"
|
||||
|
||||
#: allianceauth/authentication/views.py:39
|
||||
#: allianceauth/authentication/views.py:74
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Cannot change main character to %(char)s: character owned by a different "
|
||||
"account."
|
||||
msgstr ""
|
||||
"Der Haputcharakter kann nicht zu %(char)s geändert werden. Dieser Charakter "
|
||||
"gehört zu einem anderen Konto."
|
||||
|
||||
#: allianceauth/authentication/views.py:80
|
||||
#, python-format
|
||||
msgid "Changed main character to %(char)s"
|
||||
msgstr "Haupcharakter geändert zu %(char)s"
|
||||
|
||||
#: allianceauth/authentication/views.py:48
|
||||
#: allianceauth/authentication/views.py:89
|
||||
#, python-format
|
||||
msgid "Added %(name)s to your account."
|
||||
msgstr "%(name)s zu Deinem Konto hinzugefügt."
|
||||
|
||||
#: allianceauth/authentication/views.py:50
|
||||
#: allianceauth/authentication/views.py:91
|
||||
#, python-format
|
||||
msgid "Failed to add %(name)s to your account: they already have an account."
|
||||
msgstr ""
|
||||
"Es ist nicht möglich %(name)s zu Deinem Konto hinzu zu fügen: Dieser hat "
|
||||
"bereits ein eigenes Konto."
|
||||
|
||||
#: allianceauth/authentication/views.py:89
|
||||
#: allianceauth/authentication/views.py:130
|
||||
msgid "Unable to authenticate as the selected character."
|
||||
msgstr "Authentifizierung mit dem ausgewählten Charakter nicht möglich."
|
||||
|
||||
#: allianceauth/authentication/views.py:107
|
||||
#: allianceauth/authentication/views.py:148
|
||||
msgid "Registration token has expired."
|
||||
msgstr "Token zur Registrierung ist abgelaufen."
|
||||
|
||||
#: allianceauth/authentication/views.py:159
|
||||
#: allianceauth/authentication/views.py:200
|
||||
msgid ""
|
||||
"Sent confirmation email. Please follow the link to confirm your email "
|
||||
"address."
|
||||
@@ -173,12 +180,12 @@ msgstr ""
|
||||
"Bestätigungsmail gesendet. Bitte folge dem Link in der E-Mail zur "
|
||||
"Bestätigung."
|
||||
|
||||
#: allianceauth/authentication/views.py:164
|
||||
#: allianceauth/authentication/views.py:205
|
||||
msgid "Confirmed your email address. Please login to continue."
|
||||
msgstr ""
|
||||
"Deine E-Mail Adresse wurde bestätigt. Bitte log Dich ein um fortzufahren."
|
||||
|
||||
#: allianceauth/authentication/views.py:169
|
||||
#: allianceauth/authentication/views.py:210
|
||||
msgid "Registraion of new accounts it not allowed at this time."
|
||||
msgstr "Registrierung von neuen Konten ist zur Zeit nicht erlaubt."
|
||||
|
||||
@@ -540,6 +547,12 @@ msgstr "FAT-Link ist abgelaufen."
|
||||
msgid "Audit Log"
|
||||
msgstr "Protokoll"
|
||||
|
||||
#: allianceauth/groupmanagement/templates/groupmanagement/audit.html:18
|
||||
#: allianceauth/groupmanagement/templates/groupmanagement/groupmembers.html:20
|
||||
#: allianceauth/permissions_tool/templates/permissions_tool/audit.html:13
|
||||
msgid "Back"
|
||||
msgstr "Zurück"
|
||||
|
||||
#: allianceauth/groupmanagement/templates/groupmanagement/audit.html:25
|
||||
msgid "Date/Time"
|
||||
msgstr "Datum/Uhrzeit"
|
||||
@@ -599,6 +612,12 @@ msgstr "Keine Gruppenmitglieder vorhanden."
|
||||
msgid "Groups Membership"
|
||||
msgstr "Gruppenmitgliedschaft"
|
||||
|
||||
#: allianceauth/groupmanagement/templates/groupmanagement/groupmembership.html:14
|
||||
#: allianceauth/permissions_tool/templates/permissions_tool/overview.html:40
|
||||
#: allianceauth/templates/allianceauth/side-menu.html:15
|
||||
msgid "Groups"
|
||||
msgstr "Gruppen"
|
||||
|
||||
#: allianceauth/groupmanagement/templates/groupmanagement/groupmembership.html:23
|
||||
#: allianceauth/groupmanagement/templates/groupmanagement/groups.html:16
|
||||
msgid "Description"
|
||||
@@ -718,26 +737,26 @@ msgstr "Gruppenanfragen"
|
||||
msgid "Group Membership"
|
||||
msgstr "Gruppenmitgliedschaft"
|
||||
|
||||
#: allianceauth/groupmanagement/views.py:164
|
||||
#: allianceauth/groupmanagement/views.py:166
|
||||
#, python-format
|
||||
msgid "Removed user %(user)s from group %(group)s."
|
||||
msgstr "Benutzer %(user)s von Gruppe %(group)s entfernt."
|
||||
|
||||
#: allianceauth/groupmanagement/views.py:166
|
||||
#: allianceauth/groupmanagement/views.py:168
|
||||
msgid "User does not exist in that group"
|
||||
msgstr "Benutzer existiert nicht in dieser Gruppe"
|
||||
|
||||
#: allianceauth/groupmanagement/views.py:169
|
||||
#: allianceauth/groupmanagement/views.py:171
|
||||
msgid "Group does not exist"
|
||||
msgstr "Gruppe existiert nicht"
|
||||
|
||||
#: allianceauth/groupmanagement/views.py:196
|
||||
#: allianceauth/groupmanagement/views.py:198
|
||||
#, python-format
|
||||
msgid "Accepted application from %(mainchar)s to %(group)s."
|
||||
msgstr "Beitrittsgesuch von %(mainchar)s zur Gruppe %(group)s zugestimmt."
|
||||
|
||||
#: allianceauth/groupmanagement/views.py:203
|
||||
#: allianceauth/groupmanagement/views.py:236
|
||||
#: allianceauth/groupmanagement/views.py:205
|
||||
#: allianceauth/groupmanagement/views.py:238
|
||||
#, python-format
|
||||
msgid ""
|
||||
"An unhandled error occurred while processing the application from "
|
||||
@@ -746,37 +765,46 @@ msgstr ""
|
||||
"Bei der Bearbeitung des Beitrittsgesuchs von %(mainchar)s zur Gruppe "
|
||||
"%(group)s ist ein unbehandelter Fehler aufgetreten."
|
||||
|
||||
#: allianceauth/groupmanagement/views.py:229
|
||||
#: allianceauth/groupmanagement/views.py:231
|
||||
#, python-format
|
||||
msgid "Rejected application from %(mainchar)s to %(group)s."
|
||||
msgstr "Beitrittsgesuch von %(mainchar)s zur Gruppe %(group)s abgelehnt."
|
||||
|
||||
#: allianceauth/groupmanagement/views.py:265
|
||||
#: allianceauth/groupmanagement/views.py:267
|
||||
#, python-format
|
||||
msgid "Accepted application from %(mainchar)s to leave %(group)s."
|
||||
msgstr "Austrittsgesuch von %(mainchar)s für Gruppe %(group)s akzeptiert."
|
||||
|
||||
#: allianceauth/groupmanagement/views.py:271
|
||||
#: allianceauth/groupmanagement/views.py:305
|
||||
#: allianceauth/groupmanagement/views.py:273
|
||||
#: allianceauth/groupmanagement/views.py:307
|
||||
#, python-format
|
||||
msgid ""
|
||||
"An unhandled error occured while processing the application from "
|
||||
"An unhandled error occurred while processing the application from "
|
||||
"%(mainchar)s to leave %(group)s."
|
||||
msgstr ""
|
||||
"Bei der Bearbeitung des Austrittsgesuchs von %(mainchar)s für Gruppe "
|
||||
"%(group)s ist ein unbehandelter Fehler aufgetreten."
|
||||
|
||||
#: allianceauth/groupmanagement/views.py:298
|
||||
#: allianceauth/groupmanagement/views.py:300
|
||||
#, python-format
|
||||
msgid "Rejected application from %(mainchar)s to leave %(group)s."
|
||||
msgstr "Austrittsgesuch von %(mainchar)s für Gruppe %(group)s abgelehnt."
|
||||
|
||||
#: allianceauth/groupmanagement/views.py:345
|
||||
#: allianceauth/groupmanagement/views.py:346
|
||||
#: allianceauth/groupmanagement/views.py:358
|
||||
msgid "You cannot join that group"
|
||||
msgstr "Du kannst dieser Gruppe nicht beitreten"
|
||||
|
||||
#: allianceauth/groupmanagement/views.py:369
|
||||
#: allianceauth/groupmanagement/views.py:407
|
||||
#: allianceauth/groupmanagement/views.py:352
|
||||
msgid "You are already a member of that group."
|
||||
msgstr "Du bist bereits Mitglied dieser Gruppe."
|
||||
|
||||
#: allianceauth/groupmanagement/views.py:367
|
||||
msgid "You already have a pending application for that group."
|
||||
msgstr "Du hast Dich bereits für diese Gruppe beworben."
|
||||
|
||||
#: allianceauth/groupmanagement/views.py:370
|
||||
#: allianceauth/groupmanagement/views.py:408
|
||||
#: allianceauth/hrapplications/templates/hrapplications/management.html:37
|
||||
#: allianceauth/hrapplications/templates/hrapplications/management.html:72
|
||||
#: allianceauth/hrapplications/templates/hrapplications/management.html:99
|
||||
@@ -788,20 +816,24 @@ msgstr "Du kannst dieser Gruppe nicht beitreten"
|
||||
msgid "Pending"
|
||||
msgstr "Beantragt"
|
||||
|
||||
#: allianceauth/groupmanagement/views.py:375
|
||||
#: allianceauth/groupmanagement/views.py:376
|
||||
#, python-format
|
||||
msgid "Applied to group %(group)s."
|
||||
msgstr "Beitritt zur Gruppe %(group)s beantragt."
|
||||
|
||||
#: allianceauth/groupmanagement/views.py:386
|
||||
#: allianceauth/groupmanagement/views.py:387
|
||||
msgid "You cannot leave that group"
|
||||
msgstr "Du kannst diese Gruppe nicht verlassen"
|
||||
|
||||
#: allianceauth/groupmanagement/views.py:391
|
||||
#: allianceauth/groupmanagement/views.py:392
|
||||
msgid "You are not a member of that group"
|
||||
msgstr "Du bist kein Mitglied dieser Gruppe"
|
||||
|
||||
#: allianceauth/groupmanagement/views.py:413
|
||||
#: allianceauth/groupmanagement/views.py:401
|
||||
msgid "You already have a pending leave request for that group."
|
||||
msgstr "Du hast bereits ein ausstehendes Austrittsgesuch für diese Gruppe."
|
||||
|
||||
#: allianceauth/groupmanagement/views.py:414
|
||||
#, python-format
|
||||
msgid "Applied to leave group %(group)s."
|
||||
msgstr "Austrittsgesuch für Gruppe %(group)s gesendet."
|
||||
@@ -1147,10 +1179,6 @@ msgstr "Änderungen für Operation timer %(opname)s gespeichert."
|
||||
msgid "Permissions Audit"
|
||||
msgstr "Berechtigungsprüfung"
|
||||
|
||||
#: allianceauth/permissions_tool/templates/permissions_tool/audit.html:13
|
||||
msgid "Back"
|
||||
msgstr "Zurück"
|
||||
|
||||
#: allianceauth/permissions_tool/templates/permissions_tool/audit.html:22
|
||||
msgid "User / Character"
|
||||
msgstr "Benutzer / Character"
|
||||
@@ -1196,6 +1224,18 @@ msgstr "Nutzer"
|
||||
msgid "States"
|
||||
msgstr "Status"
|
||||
|
||||
#: allianceauth/services/abstract.py:72
|
||||
msgid "That service account already exists"
|
||||
msgstr "Dieses Dienstkonto existiert bereits"
|
||||
|
||||
#: allianceauth/services/abstract.py:104
|
||||
msgid "Successfully set your {} password"
|
||||
msgstr "Dein {} Passwort wurde erfolgreich gesetzt"
|
||||
|
||||
#: allianceauth/services/auth_hooks.py:11
|
||||
msgid "Services"
|
||||
msgstr "Dienste"
|
||||
|
||||
#: allianceauth/services/forms.py:6
|
||||
msgid "Name of Fleet:"
|
||||
msgstr "SRP Flotte erstellen:"
|
||||
@@ -1260,15 +1300,85 @@ msgstr "Passwort muss mindestens 8 Zeichen lang sein"
|
||||
msgid "Link Discord Server"
|
||||
msgstr "Verbinde Discord Server"
|
||||
|
||||
#: allianceauth/services/modules/openfire/forms.py:7
|
||||
msgid "Message"
|
||||
msgstr "Nachricht"
|
||||
#: allianceauth/services/modules/discord/views.py:26
|
||||
msgid "Deactivated Discord account."
|
||||
msgstr "Discord Konto deaktiviert."
|
||||
|
||||
#: allianceauth/services/modules/discord/views.py:29
|
||||
#: allianceauth/services/modules/discord/views.py:41
|
||||
#: allianceauth/services/modules/discord/views.py:65
|
||||
msgid "An error occurred while processing your Discord account."
|
||||
msgstr "Es gab einen Fehler bei der Verarbeitung Deines Discord Kontos."
|
||||
|
||||
#: allianceauth/services/modules/discord/views.py:62
|
||||
msgid "Activated Discord account."
|
||||
msgstr "Discord Konto aktiviert."
|
||||
|
||||
#: allianceauth/services/modules/discourse/views.py:37
|
||||
msgid "You are not authorized to access Discourse."
|
||||
msgstr "Du bist nicht autorisiert auf Discorse zuzugreifen."
|
||||
|
||||
#: allianceauth/services/modules/discourse/views.py:42
|
||||
msgid "You must have a main character set to access Discourse."
|
||||
msgstr ""
|
||||
"Du musst einen Hauptcharakter gesetzt haben um auf Discourse zuzugreifen."
|
||||
|
||||
#: allianceauth/services/modules/discourse/views.py:52
|
||||
msgid ""
|
||||
"No SSO payload or signature. Please contact support if this problem "
|
||||
"persists."
|
||||
msgstr ""
|
||||
"Keine SSO-Nutzdaten oder Signaturen. Bitte wenden Sie sich an den Support, "
|
||||
"wenn das Problem weiterhin besteht."
|
||||
|
||||
#: allianceauth/services/modules/discourse/views.py:62
|
||||
#: allianceauth/services/modules/discourse/views.py:70
|
||||
msgid "Invalid payload. Please contact support if this problem persists."
|
||||
msgstr ""
|
||||
"Ungültige Nutzdaten. Bitte wenden Sie sich an den Support, wenn das Problem "
|
||||
"weiterhin besteht."
|
||||
|
||||
#: allianceauth/services/modules/ips4/views.py:31
|
||||
msgid "Activated IPSuite4 account."
|
||||
msgstr "IP4Suite Konto aktiviert."
|
||||
|
||||
#: allianceauth/services/modules/ips4/views.py:40
|
||||
#: allianceauth/services/modules/ips4/views.py:62
|
||||
#: allianceauth/services/modules/ips4/views.py:83
|
||||
#: allianceauth/services/modules/ips4/views.py:103
|
||||
msgid "An error occurred while processing your IPSuite4 account."
|
||||
msgstr "Es gab einen Fehler bei der Verarbeitung Deines IPSuite4 Kontos."
|
||||
|
||||
#: allianceauth/services/modules/ips4/views.py:53
|
||||
msgid "Reset IPSuite4 password."
|
||||
msgstr "IPSuite4 Passwort zurücksetzen."
|
||||
|
||||
#: allianceauth/services/modules/ips4/views.py:80
|
||||
msgid "Set IPSuite4 password."
|
||||
msgstr "Setze IPSuite4 Passwort."
|
||||
|
||||
#: allianceauth/services/modules/ips4/views.py:100
|
||||
msgid "Deactivated IPSuite4 account."
|
||||
msgstr "IP4Suite Konto deaktiviert."
|
||||
|
||||
#: allianceauth/services/modules/openfire/auth_hooks.py:26
|
||||
msgid "Jabber"
|
||||
msgstr "Jabber"
|
||||
|
||||
#: allianceauth/services/modules/openfire/auth_hooks.py:78
|
||||
#: allianceauth/services/modules/openfire/templates/services/openfire/broadcast.html:6
|
||||
#: allianceauth/services/modules/openfire/templates/services/openfire/broadcast.html:11
|
||||
msgid "Jabber Broadcast"
|
||||
msgstr "Jabber Übertragung"
|
||||
|
||||
#: allianceauth/services/modules/openfire/auth_hooks.py:91
|
||||
msgid "Fleet Broadcast Formatter"
|
||||
msgstr "Flotten Ping Formatierung"
|
||||
|
||||
#: allianceauth/services/modules/openfire/forms.py:7
|
||||
msgid "Message"
|
||||
msgstr "Nachricht"
|
||||
|
||||
#: allianceauth/services/modules/openfire/templates/services/openfire/broadcast.html:17
|
||||
msgid "Broadcast Sent!!"
|
||||
msgstr "Übertragung gesendet!!"
|
||||
@@ -1277,6 +1387,76 @@ msgstr "Übertragung gesendet!!"
|
||||
msgid "Broadcast"
|
||||
msgstr "Übertragungen"
|
||||
|
||||
#: allianceauth/services/modules/openfire/views.py:35
|
||||
msgid "Activated jabber account."
|
||||
msgstr "Jabber Konto aktiviert."
|
||||
|
||||
#: allianceauth/services/modules/openfire/views.py:44
|
||||
#: allianceauth/services/modules/openfire/views.py:57
|
||||
#: allianceauth/services/modules/openfire/views.py:78
|
||||
#: allianceauth/services/modules/openfire/views.py:151
|
||||
msgid "An error occurred while processing your jabber account."
|
||||
msgstr "Es gab einen Fehler bei der Verarbeitung Deines Jabber Kontos."
|
||||
|
||||
#: allianceauth/services/modules/openfire/views.py:70
|
||||
msgid "Reset jabber password."
|
||||
msgstr "Jabber Passwort zurücksetzen."
|
||||
|
||||
#: allianceauth/services/modules/openfire/views.py:119
|
||||
#, python-format
|
||||
msgid "Sent jabber broadcast to %s"
|
||||
msgstr "Sende Jabber Durchsage an %s"
|
||||
|
||||
#: allianceauth/services/modules/openfire/views.py:148
|
||||
msgid "Set jabber password."
|
||||
msgstr "Setze Jabber Passwort."
|
||||
|
||||
#: allianceauth/services/modules/phpbb3/views.py:34
|
||||
msgid "Activated forum account."
|
||||
msgstr "Forum Konto aktiviert."
|
||||
|
||||
#: allianceauth/services/modules/phpbb3/views.py:43
|
||||
#: allianceauth/services/modules/phpbb3/views.py:57
|
||||
#: allianceauth/services/modules/phpbb3/views.py:80
|
||||
#: allianceauth/services/modules/phpbb3/views.py:103
|
||||
msgid "An error occurred while processing your forum account."
|
||||
msgstr "Es gab einen Fehler bei der Verarbeitung Deines Forum Kontos."
|
||||
|
||||
#: allianceauth/services/modules/phpbb3/views.py:54
|
||||
msgid "Deactivated forum account."
|
||||
msgstr "Forum Konto deaktiviert."
|
||||
|
||||
#: allianceauth/services/modules/phpbb3/views.py:71
|
||||
msgid "Reset forum password."
|
||||
msgstr "Forum Passwort zurücksetzen."
|
||||
|
||||
#: allianceauth/services/modules/phpbb3/views.py:100
|
||||
msgid "Set forum password."
|
||||
msgstr "Setze Forum Passwort."
|
||||
|
||||
#: allianceauth/services/modules/smf/views.py:34
|
||||
msgid "Activated SMF account."
|
||||
msgstr "SMF Konto aktiviert."
|
||||
|
||||
#: allianceauth/services/modules/smf/views.py:43
|
||||
#: allianceauth/services/modules/smf/views.py:58
|
||||
#: allianceauth/services/modules/smf/views.py:80
|
||||
#: allianceauth/services/modules/smf/views.py:103
|
||||
msgid "An error occurred while processing your SMF account."
|
||||
msgstr "Es gab einen Fehler bei der Verarbeitung Deines SMF Kontos."
|
||||
|
||||
#: allianceauth/services/modules/smf/views.py:55
|
||||
msgid "Deactivated SMF account."
|
||||
msgstr "SMF Konto deaktiviert."
|
||||
|
||||
#: allianceauth/services/modules/smf/views.py:72
|
||||
msgid "Reset SMF password."
|
||||
msgstr "SMF Passwort zurücksetzen."
|
||||
|
||||
#: allianceauth/services/modules/smf/views.py:100
|
||||
msgid "Set SMF password."
|
||||
msgstr "Setze SMF Passwort."
|
||||
|
||||
#: allianceauth/services/modules/teamspeak3/forms.py:14
|
||||
#, python-format
|
||||
msgid "Unable to locate user %s on server"
|
||||
@@ -1300,6 +1480,47 @@ msgstr "Server beitreten"
|
||||
msgid "Continue"
|
||||
msgstr "Fortsetzen"
|
||||
|
||||
#: allianceauth/services/modules/teamspeak3/views.py:34
|
||||
msgid "Activated TeamSpeak3 account."
|
||||
msgstr "TeamSpeak3 Konto aktiviert."
|
||||
|
||||
#: allianceauth/services/modules/teamspeak3/views.py:37
|
||||
#: allianceauth/services/modules/teamspeak3/views.py:74
|
||||
#: allianceauth/services/modules/teamspeak3/views.py:100
|
||||
msgid "An error occurred while processing your TeamSpeak3 account."
|
||||
msgstr "Es gab einen Fehler bei der Verarbeitung Deines TeamSpeak3 Kontos."
|
||||
|
||||
#: allianceauth/services/modules/teamspeak3/views.py:71
|
||||
msgid "Deactivated TeamSpeak3 account."
|
||||
msgstr "TeamSpeak3 Konto deaktiviert."
|
||||
|
||||
#: allianceauth/services/modules/teamspeak3/views.py:97
|
||||
msgid "Reset TeamSpeak3 permission key."
|
||||
msgstr "TeamSpeak3 Berechtigungsschlüssel zurücksetzen."
|
||||
|
||||
#: allianceauth/services/modules/xenforo/views.py:30
|
||||
msgid "Activated XenForo account."
|
||||
msgstr "XenForo Konto aktiviert."
|
||||
|
||||
#: allianceauth/services/modules/xenforo/views.py:40
|
||||
#: allianceauth/services/modules/xenforo/views.py:52
|
||||
#: allianceauth/services/modules/xenforo/views.py:73
|
||||
#: allianceauth/services/modules/xenforo/views.py:94
|
||||
msgid "An error occurred while processing your XenForo account."
|
||||
msgstr "Es gab einen Fehler bei der Verarbeitung Deines XenForo Kontos."
|
||||
|
||||
#: allianceauth/services/modules/xenforo/views.py:50
|
||||
msgid "Deactivated XenForo account."
|
||||
msgstr "XenForo Konto deaktiviert."
|
||||
|
||||
#: allianceauth/services/modules/xenforo/views.py:65
|
||||
msgid "Reset XenForo account password."
|
||||
msgstr "XenForo Passwort zurüclsetzen."
|
||||
|
||||
#: allianceauth/services/modules/xenforo/views.py:91
|
||||
msgid "Changed XenForo password."
|
||||
msgstr "Setze XenForo Passwort."
|
||||
|
||||
#: allianceauth/services/templates/services/fleetformattertool.html:6
|
||||
msgid "Fleet Formatter Tool"
|
||||
msgstr "Flottenformatierung"
|
||||
|
||||
@@ -8,7 +8,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2020-03-09 15:16+0000\n"
|
||||
"POT-Creation-Date: 2020-04-02 03:23+0000\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
@@ -65,9 +65,7 @@ msgid "Change Main"
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/authentication/templates/authentication/dashboard.html:97
|
||||
#: allianceauth/permissions_tool/templates/permissions_tool/overview.html:40
|
||||
#: allianceauth/templates/allianceauth/side-menu.html:15
|
||||
msgid "Groups"
|
||||
msgid "Group Memberships"
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/authentication/templates/authentication/dashboard.html:117
|
||||
@@ -132,40 +130,47 @@ msgstr ""
|
||||
msgid "Submit"
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/authentication/views.py:39
|
||||
#: allianceauth/authentication/views.py:74
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Cannot change main character to %(char)s: character owned by a different "
|
||||
"account."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/authentication/views.py:80
|
||||
#, python-format
|
||||
msgid "Changed main character to %(char)s"
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/authentication/views.py:48
|
||||
#: allianceauth/authentication/views.py:89
|
||||
#, python-format
|
||||
msgid "Added %(name)s to your account."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/authentication/views.py:50
|
||||
#: allianceauth/authentication/views.py:91
|
||||
#, python-format
|
||||
msgid "Failed to add %(name)s to your account: they already have an account."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/authentication/views.py:89
|
||||
#: allianceauth/authentication/views.py:130
|
||||
msgid "Unable to authenticate as the selected character."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/authentication/views.py:107
|
||||
#: allianceauth/authentication/views.py:148
|
||||
msgid "Registration token has expired."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/authentication/views.py:159
|
||||
#: allianceauth/authentication/views.py:200
|
||||
msgid ""
|
||||
"Sent confirmation email. Please follow the link to confirm your email "
|
||||
"address."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/authentication/views.py:164
|
||||
#: allianceauth/authentication/views.py:205
|
||||
msgid "Confirmed your email address. Please login to continue."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/authentication/views.py:169
|
||||
#: allianceauth/authentication/views.py:210
|
||||
msgid "Registraion of new accounts it not allowed at this time."
|
||||
msgstr ""
|
||||
|
||||
@@ -527,6 +532,12 @@ msgstr ""
|
||||
msgid "Audit Log"
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/groupmanagement/templates/groupmanagement/audit.html:18
|
||||
#: allianceauth/groupmanagement/templates/groupmanagement/groupmembers.html:20
|
||||
#: allianceauth/permissions_tool/templates/permissions_tool/audit.html:13
|
||||
msgid "Back"
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/groupmanagement/templates/groupmanagement/audit.html:25
|
||||
msgid "Date/Time"
|
||||
msgstr ""
|
||||
@@ -586,6 +597,12 @@ msgstr ""
|
||||
msgid "Groups Membership"
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/groupmanagement/templates/groupmanagement/groupmembership.html:14
|
||||
#: allianceauth/permissions_tool/templates/permissions_tool/overview.html:40
|
||||
#: allianceauth/templates/allianceauth/side-menu.html:15
|
||||
msgid "Groups"
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/groupmanagement/templates/groupmanagement/groupmembership.html:23
|
||||
#: allianceauth/groupmanagement/templates/groupmanagement/groups.html:16
|
||||
msgid "Description"
|
||||
@@ -705,61 +722,70 @@ msgstr ""
|
||||
msgid "Group Membership"
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/groupmanagement/views.py:164
|
||||
#: allianceauth/groupmanagement/views.py:166
|
||||
#, python-format
|
||||
msgid "Removed user %(user)s from group %(group)s."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/groupmanagement/views.py:166
|
||||
#: allianceauth/groupmanagement/views.py:168
|
||||
msgid "User does not exist in that group"
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/groupmanagement/views.py:169
|
||||
#: allianceauth/groupmanagement/views.py:171
|
||||
msgid "Group does not exist"
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/groupmanagement/views.py:196
|
||||
#: allianceauth/groupmanagement/views.py:198
|
||||
#, python-format
|
||||
msgid "Accepted application from %(mainchar)s to %(group)s."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/groupmanagement/views.py:203
|
||||
#: allianceauth/groupmanagement/views.py:236
|
||||
#: allianceauth/groupmanagement/views.py:205
|
||||
#: allianceauth/groupmanagement/views.py:238
|
||||
#, python-format
|
||||
msgid ""
|
||||
"An unhandled error occurred while processing the application from "
|
||||
"%(mainchar)s to %(group)s."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/groupmanagement/views.py:229
|
||||
#: allianceauth/groupmanagement/views.py:231
|
||||
#, python-format
|
||||
msgid "Rejected application from %(mainchar)s to %(group)s."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/groupmanagement/views.py:265
|
||||
#: allianceauth/groupmanagement/views.py:267
|
||||
#, python-format
|
||||
msgid "Accepted application from %(mainchar)s to leave %(group)s."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/groupmanagement/views.py:271
|
||||
#: allianceauth/groupmanagement/views.py:305
|
||||
#: allianceauth/groupmanagement/views.py:273
|
||||
#: allianceauth/groupmanagement/views.py:307
|
||||
#, python-format
|
||||
msgid ""
|
||||
"An unhandled error occured while processing the application from "
|
||||
"An unhandled error occurred while processing the application from "
|
||||
"%(mainchar)s to leave %(group)s."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/groupmanagement/views.py:298
|
||||
#: allianceauth/groupmanagement/views.py:300
|
||||
#, python-format
|
||||
msgid "Rejected application from %(mainchar)s to leave %(group)s."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/groupmanagement/views.py:345
|
||||
#: allianceauth/groupmanagement/views.py:346
|
||||
#: allianceauth/groupmanagement/views.py:358
|
||||
msgid "You cannot join that group"
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/groupmanagement/views.py:369
|
||||
#: allianceauth/groupmanagement/views.py:407
|
||||
#: allianceauth/groupmanagement/views.py:352
|
||||
msgid "You are already a member of that group."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/groupmanagement/views.py:367
|
||||
msgid "You already have a pending application for that group."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/groupmanagement/views.py:370
|
||||
#: allianceauth/groupmanagement/views.py:408
|
||||
#: allianceauth/hrapplications/templates/hrapplications/management.html:37
|
||||
#: allianceauth/hrapplications/templates/hrapplications/management.html:72
|
||||
#: allianceauth/hrapplications/templates/hrapplications/management.html:99
|
||||
@@ -771,20 +797,24 @@ msgstr ""
|
||||
msgid "Pending"
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/groupmanagement/views.py:375
|
||||
#: allianceauth/groupmanagement/views.py:376
|
||||
#, python-format
|
||||
msgid "Applied to group %(group)s."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/groupmanagement/views.py:386
|
||||
#: allianceauth/groupmanagement/views.py:387
|
||||
msgid "You cannot leave that group"
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/groupmanagement/views.py:391
|
||||
#: allianceauth/groupmanagement/views.py:392
|
||||
msgid "You are not a member of that group"
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/groupmanagement/views.py:413
|
||||
#: allianceauth/groupmanagement/views.py:401
|
||||
msgid "You already have a pending leave request for that group."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/groupmanagement/views.py:414
|
||||
#, python-format
|
||||
msgid "Applied to leave group %(group)s."
|
||||
msgstr ""
|
||||
@@ -1130,10 +1160,6 @@ msgstr ""
|
||||
msgid "Permissions Audit"
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/permissions_tool/templates/permissions_tool/audit.html:13
|
||||
msgid "Back"
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/permissions_tool/templates/permissions_tool/audit.html:22
|
||||
msgid "User / Character"
|
||||
msgstr ""
|
||||
@@ -1179,6 +1205,18 @@ msgstr ""
|
||||
msgid "States"
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/services/abstract.py:72
|
||||
msgid "That service account already exists"
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/services/abstract.py:104
|
||||
msgid "Successfully set your {} password"
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/services/auth_hooks.py:11
|
||||
msgid "Services"
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/services/forms.py:6
|
||||
msgid "Name of Fleet:"
|
||||
msgstr ""
|
||||
@@ -1243,15 +1281,79 @@ msgstr ""
|
||||
msgid "Link Discord Server"
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/services/modules/openfire/forms.py:7
|
||||
msgid "Message"
|
||||
#: allianceauth/services/modules/discord/views.py:26
|
||||
msgid "Deactivated Discord account."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/services/modules/discord/views.py:29
|
||||
#: allianceauth/services/modules/discord/views.py:41
|
||||
#: allianceauth/services/modules/discord/views.py:65
|
||||
msgid "An error occurred while processing your Discord account."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/services/modules/discord/views.py:62
|
||||
msgid "Activated Discord account."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/services/modules/discourse/views.py:37
|
||||
msgid "You are not authorized to access Discourse."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/services/modules/discourse/views.py:42
|
||||
msgid "You must have a main character set to access Discourse."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/services/modules/discourse/views.py:52
|
||||
msgid ""
|
||||
"No SSO payload or signature. Please contact support if this problem persists."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/services/modules/discourse/views.py:62
|
||||
#: allianceauth/services/modules/discourse/views.py:70
|
||||
msgid "Invalid payload. Please contact support if this problem persists."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/services/modules/ips4/views.py:31
|
||||
msgid "Activated IPSuite4 account."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/services/modules/ips4/views.py:40
|
||||
#: allianceauth/services/modules/ips4/views.py:62
|
||||
#: allianceauth/services/modules/ips4/views.py:83
|
||||
#: allianceauth/services/modules/ips4/views.py:103
|
||||
msgid "An error occurred while processing your IPSuite4 account."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/services/modules/ips4/views.py:53
|
||||
msgid "Reset IPSuite4 password."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/services/modules/ips4/views.py:80
|
||||
msgid "Set IPSuite4 password."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/services/modules/ips4/views.py:100
|
||||
msgid "Deactivated IPSuite4 account."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/services/modules/openfire/auth_hooks.py:26
|
||||
msgid "Jabber"
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/services/modules/openfire/auth_hooks.py:78
|
||||
#: allianceauth/services/modules/openfire/templates/services/openfire/broadcast.html:6
|
||||
#: allianceauth/services/modules/openfire/templates/services/openfire/broadcast.html:11
|
||||
msgid "Jabber Broadcast"
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/services/modules/openfire/auth_hooks.py:91
|
||||
msgid "Fleet Broadcast Formatter"
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/services/modules/openfire/forms.py:7
|
||||
msgid "Message"
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/services/modules/openfire/templates/services/openfire/broadcast.html:17
|
||||
msgid "Broadcast Sent!!"
|
||||
msgstr ""
|
||||
@@ -1260,6 +1362,76 @@ msgstr ""
|
||||
msgid "Broadcast"
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/services/modules/openfire/views.py:35
|
||||
msgid "Activated jabber account."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/services/modules/openfire/views.py:44
|
||||
#: allianceauth/services/modules/openfire/views.py:57
|
||||
#: allianceauth/services/modules/openfire/views.py:78
|
||||
#: allianceauth/services/modules/openfire/views.py:151
|
||||
msgid "An error occurred while processing your jabber account."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/services/modules/openfire/views.py:70
|
||||
msgid "Reset jabber password."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/services/modules/openfire/views.py:119
|
||||
#, python-format
|
||||
msgid "Sent jabber broadcast to %s"
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/services/modules/openfire/views.py:148
|
||||
msgid "Set jabber password."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/services/modules/phpbb3/views.py:34
|
||||
msgid "Activated forum account."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/services/modules/phpbb3/views.py:43
|
||||
#: allianceauth/services/modules/phpbb3/views.py:57
|
||||
#: allianceauth/services/modules/phpbb3/views.py:80
|
||||
#: allianceauth/services/modules/phpbb3/views.py:103
|
||||
msgid "An error occurred while processing your forum account."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/services/modules/phpbb3/views.py:54
|
||||
msgid "Deactivated forum account."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/services/modules/phpbb3/views.py:71
|
||||
msgid "Reset forum password."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/services/modules/phpbb3/views.py:100
|
||||
msgid "Set forum password."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/services/modules/smf/views.py:34
|
||||
msgid "Activated SMF account."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/services/modules/smf/views.py:43
|
||||
#: allianceauth/services/modules/smf/views.py:58
|
||||
#: allianceauth/services/modules/smf/views.py:80
|
||||
#: allianceauth/services/modules/smf/views.py:103
|
||||
msgid "An error occurred while processing your SMF account."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/services/modules/smf/views.py:55
|
||||
msgid "Deactivated SMF account."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/services/modules/smf/views.py:72
|
||||
msgid "Reset SMF password."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/services/modules/smf/views.py:100
|
||||
msgid "Set SMF password."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/services/modules/teamspeak3/forms.py:14
|
||||
#, python-format
|
||||
msgid "Unable to locate user %s on server"
|
||||
@@ -1283,6 +1455,47 @@ msgstr ""
|
||||
msgid "Continue"
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/services/modules/teamspeak3/views.py:34
|
||||
msgid "Activated TeamSpeak3 account."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/services/modules/teamspeak3/views.py:37
|
||||
#: allianceauth/services/modules/teamspeak3/views.py:74
|
||||
#: allianceauth/services/modules/teamspeak3/views.py:100
|
||||
msgid "An error occurred while processing your TeamSpeak3 account."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/services/modules/teamspeak3/views.py:71
|
||||
msgid "Deactivated TeamSpeak3 account."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/services/modules/teamspeak3/views.py:97
|
||||
msgid "Reset TeamSpeak3 permission key."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/services/modules/xenforo/views.py:30
|
||||
msgid "Activated XenForo account."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/services/modules/xenforo/views.py:40
|
||||
#: allianceauth/services/modules/xenforo/views.py:52
|
||||
#: allianceauth/services/modules/xenforo/views.py:73
|
||||
#: allianceauth/services/modules/xenforo/views.py:94
|
||||
msgid "An error occurred while processing your XenForo account."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/services/modules/xenforo/views.py:50
|
||||
msgid "Deactivated XenForo account."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/services/modules/xenforo/views.py:65
|
||||
msgid "Reset XenForo account password."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/services/modules/xenforo/views.py:91
|
||||
msgid "Changed XenForo password."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/services/templates/services/fleetformattertool.html:6
|
||||
msgid "Fleet Formatter Tool"
|
||||
msgstr ""
|
||||
|
||||
Binary file not shown.
@@ -12,7 +12,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2020-03-04 23:04+0000\n"
|
||||
"POT-Creation-Date: 2020-03-26 03:07+0000\n"
|
||||
"PO-Revision-Date: 2020-02-18 03:14+0000\n"
|
||||
"Last-Translator: frank1210 <francolopez_16@hotmail.com>, 2020\n"
|
||||
"Language-Team: Spanish (https://www.transifex.com/alliance-auth/teams/107430/es/)\n"
|
||||
@@ -70,10 +70,8 @@ msgid "Change Main"
|
||||
msgstr "Cambiar Personaje Principal"
|
||||
|
||||
#: allianceauth/authentication/templates/authentication/dashboard.html:97
|
||||
#: allianceauth/permissions_tool/templates/permissions_tool/overview.html:40
|
||||
#: allianceauth/templates/allianceauth/side-menu.html:15
|
||||
msgid "Groups"
|
||||
msgstr "Grupos"
|
||||
msgid "Group Memberships"
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/authentication/templates/authentication/dashboard.html:117
|
||||
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkstatisticscorpview.html:23
|
||||
@@ -137,45 +135,52 @@ msgstr "Tu equipo de IT"
|
||||
msgid "Submit"
|
||||
msgstr "Enviar"
|
||||
|
||||
#: allianceauth/authentication/views.py:39
|
||||
#: allianceauth/authentication/views.py:74
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Cannot change main character to %(char)s: character owned by a different "
|
||||
"account."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/authentication/views.py:80
|
||||
#, python-format
|
||||
msgid "Changed main character to %(char)s"
|
||||
msgstr "Se ha cambiado tu personaje principal ha %(char)s"
|
||||
|
||||
#: allianceauth/authentication/views.py:48
|
||||
#: allianceauth/authentication/views.py:89
|
||||
#, python-format
|
||||
msgid "Added %(name)s to your account."
|
||||
msgstr "Se ha agregado a %(name)s a tu cuenta"
|
||||
|
||||
#: allianceauth/authentication/views.py:50
|
||||
#: allianceauth/authentication/views.py:91
|
||||
#, python-format
|
||||
msgid "Failed to add %(name)s to your account: they already have an account."
|
||||
msgstr ""
|
||||
"Se fallo en agregar a %(name)s a tu cuenta: Ya se encuentra registrado en "
|
||||
"otra cuenta."
|
||||
|
||||
#: allianceauth/authentication/views.py:89
|
||||
#: allianceauth/authentication/views.py:130
|
||||
msgid "Unable to authenticate as the selected character."
|
||||
msgstr "Imposible validar con el personaje seleccionado."
|
||||
|
||||
#: allianceauth/authentication/views.py:107
|
||||
#: allianceauth/authentication/views.py:148
|
||||
msgid "Registration token has expired."
|
||||
msgstr "El token de registracion expiro."
|
||||
|
||||
#: allianceauth/authentication/views.py:159
|
||||
#: allianceauth/authentication/views.py:200
|
||||
msgid ""
|
||||
"Sent confirmation email. Please follow the link to confirm your email "
|
||||
"address."
|
||||
msgstr ""
|
||||
"Confirmacion de mail enviada. Por favor siga el enlace para confirmar "
|
||||
|
||||
#: allianceauth/authentication/views.py:164
|
||||
#: allianceauth/authentication/views.py:205
|
||||
msgid "Confirmed your email address. Please login to continue."
|
||||
msgstr ""
|
||||
"Se ha confirmado su direccion de mail. Por favor igrese su token para "
|
||||
"continuar."
|
||||
|
||||
#: allianceauth/authentication/views.py:169
|
||||
#: allianceauth/authentication/views.py:210
|
||||
msgid "Registraion of new accounts it not allowed at this time."
|
||||
msgstr "Registracion de nuevas cuentas no es permitido por el momento."
|
||||
|
||||
@@ -538,6 +543,12 @@ msgstr "Enlace de participacion expirado."
|
||||
msgid "Audit Log"
|
||||
msgstr "Log de Auditoria"
|
||||
|
||||
#: allianceauth/groupmanagement/templates/groupmanagement/audit.html:18
|
||||
#: allianceauth/groupmanagement/templates/groupmanagement/groupmembers.html:20
|
||||
#: allianceauth/permissions_tool/templates/permissions_tool/audit.html:13
|
||||
msgid "Back"
|
||||
msgstr "Volver"
|
||||
|
||||
#: allianceauth/groupmanagement/templates/groupmanagement/audit.html:25
|
||||
msgid "Date/Time"
|
||||
msgstr "Fecha/Hora"
|
||||
@@ -597,6 +608,12 @@ msgstr "no hay miembros para listar."
|
||||
msgid "Groups Membership"
|
||||
msgstr "Membresia de grupos"
|
||||
|
||||
#: allianceauth/groupmanagement/templates/groupmanagement/groupmembership.html:14
|
||||
#: allianceauth/permissions_tool/templates/permissions_tool/overview.html:40
|
||||
#: allianceauth/templates/allianceauth/side-menu.html:15
|
||||
msgid "Groups"
|
||||
msgstr "Grupos"
|
||||
|
||||
#: allianceauth/groupmanagement/templates/groupmanagement/groupmembership.html:23
|
||||
#: allianceauth/groupmanagement/templates/groupmanagement/groups.html:16
|
||||
msgid "Description"
|
||||
@@ -716,26 +733,26 @@ msgstr "Solicitudes de Grupo"
|
||||
msgid "Group Membership"
|
||||
msgstr "Membresia de Grupo"
|
||||
|
||||
#: allianceauth/groupmanagement/views.py:164
|
||||
#: allianceauth/groupmanagement/views.py:166
|
||||
#, python-format
|
||||
msgid "Removed user %(user)s from group %(group)s."
|
||||
msgstr "El usuario %(user)s fue removido del grupo %(group)s"
|
||||
|
||||
#: allianceauth/groupmanagement/views.py:166
|
||||
#: allianceauth/groupmanagement/views.py:168
|
||||
msgid "User does not exist in that group"
|
||||
msgstr "El usuario no existe en ese grupos"
|
||||
|
||||
#: allianceauth/groupmanagement/views.py:169
|
||||
#: allianceauth/groupmanagement/views.py:171
|
||||
msgid "Group does not exist"
|
||||
msgstr "El grupo no existe"
|
||||
|
||||
#: allianceauth/groupmanagement/views.py:196
|
||||
#: allianceauth/groupmanagement/views.py:198
|
||||
#, python-format
|
||||
msgid "Accepted application from %(mainchar)s to %(group)s."
|
||||
msgstr "Solicitud aceptada de %(mainchar)s a %(group)s"
|
||||
|
||||
#: allianceauth/groupmanagement/views.py:203
|
||||
#: allianceauth/groupmanagement/views.py:236
|
||||
#: allianceauth/groupmanagement/views.py:205
|
||||
#: allianceauth/groupmanagement/views.py:238
|
||||
#, python-format
|
||||
msgid ""
|
||||
"An unhandled error occurred while processing the application from "
|
||||
@@ -744,38 +761,45 @@ msgstr ""
|
||||
"Ocurrio un error cuando se intento procesar la informacion de %(mainchar)s "
|
||||
"al grupo %(group)s."
|
||||
|
||||
#: allianceauth/groupmanagement/views.py:229
|
||||
#: allianceauth/groupmanagement/views.py:231
|
||||
#, python-format
|
||||
msgid "Rejected application from %(mainchar)s to %(group)s."
|
||||
msgstr "Se rechazo la solicitud de %(mainchar)s al grupo %(group)s."
|
||||
|
||||
#: allianceauth/groupmanagement/views.py:265
|
||||
#: allianceauth/groupmanagement/views.py:267
|
||||
#, python-format
|
||||
msgid "Accepted application from %(mainchar)s to leave %(group)s."
|
||||
msgstr "Se acepto la solicitud de %(mainchar)s para dejar el grupo %(group)s."
|
||||
|
||||
#: allianceauth/groupmanagement/views.py:271
|
||||
#: allianceauth/groupmanagement/views.py:305
|
||||
#: allianceauth/groupmanagement/views.py:273
|
||||
#: allianceauth/groupmanagement/views.py:307
|
||||
#, python-format
|
||||
msgid ""
|
||||
"An unhandled error occured while processing the application from "
|
||||
"An unhandled error occurred while processing the application from "
|
||||
"%(mainchar)s to leave %(group)s."
|
||||
msgstr ""
|
||||
"Ocurrio un error cuando se intento procesar la informacion de %(mainchar)s "
|
||||
"para dejar el grupo %(group)s."
|
||||
|
||||
#: allianceauth/groupmanagement/views.py:298
|
||||
#: allianceauth/groupmanagement/views.py:300
|
||||
#, python-format
|
||||
msgid "Rejected application from %(mainchar)s to leave %(group)s."
|
||||
msgstr ""
|
||||
"Se rechazo la solicitud de %(mainchar)s para dejar el grupo %(group)s."
|
||||
|
||||
#: allianceauth/groupmanagement/views.py:345
|
||||
#: allianceauth/groupmanagement/views.py:347
|
||||
#: allianceauth/groupmanagement/views.py:359
|
||||
msgid "You cannot join that group"
|
||||
msgstr "No puedes unirte a ese grupo"
|
||||
|
||||
#: allianceauth/groupmanagement/views.py:369
|
||||
#: allianceauth/groupmanagement/views.py:407
|
||||
#: allianceauth/groupmanagement/views.py:353
|
||||
msgid "You are already a member of that group."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/groupmanagement/views.py:368
|
||||
msgid "You already have a pending application for that group."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/groupmanagement/views.py:371
|
||||
#: allianceauth/groupmanagement/views.py:409
|
||||
#: allianceauth/hrapplications/templates/hrapplications/management.html:37
|
||||
#: allianceauth/hrapplications/templates/hrapplications/management.html:72
|
||||
#: allianceauth/hrapplications/templates/hrapplications/management.html:99
|
||||
@@ -787,20 +811,24 @@ msgstr "No puedes unirte a ese grupo"
|
||||
msgid "Pending"
|
||||
msgstr "Pendiente"
|
||||
|
||||
#: allianceauth/groupmanagement/views.py:375
|
||||
#: allianceauth/groupmanagement/views.py:377
|
||||
#, python-format
|
||||
msgid "Applied to group %(group)s."
|
||||
msgstr "Solicitud enviada al grupo %(group)s."
|
||||
|
||||
#: allianceauth/groupmanagement/views.py:386
|
||||
#: allianceauth/groupmanagement/views.py:388
|
||||
msgid "You cannot leave that group"
|
||||
msgstr "No puedes dejar el grupos"
|
||||
|
||||
#: allianceauth/groupmanagement/views.py:391
|
||||
#: allianceauth/groupmanagement/views.py:393
|
||||
msgid "You are not a member of that group"
|
||||
msgstr "No eres miembro de ese grupo"
|
||||
|
||||
#: allianceauth/groupmanagement/views.py:413
|
||||
#: allianceauth/groupmanagement/views.py:402
|
||||
msgid "You already have a pending leave request for that group."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/groupmanagement/views.py:415
|
||||
#, python-format
|
||||
msgid "Applied to leave group %(group)s."
|
||||
msgstr "Solicitaste dejar el grupo %(group)s."
|
||||
@@ -1146,10 +1174,6 @@ msgstr "Se guardaron los cambios para la operacion %(opname)s"
|
||||
msgid "Permissions Audit"
|
||||
msgstr "Auditar Permisos"
|
||||
|
||||
#: allianceauth/permissions_tool/templates/permissions_tool/audit.html:13
|
||||
msgid "Back"
|
||||
msgstr "Volver"
|
||||
|
||||
#: allianceauth/permissions_tool/templates/permissions_tool/audit.html:22
|
||||
msgid "User / Character"
|
||||
msgstr ""
|
||||
@@ -1195,6 +1219,18 @@ msgstr "Usuarios"
|
||||
msgid "States"
|
||||
msgstr "Estados"
|
||||
|
||||
#: allianceauth/services/abstract.py:72
|
||||
msgid "That service account already exists"
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/services/abstract.py:104
|
||||
msgid "Successfully set your {} password"
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/services/auth_hooks.py:11
|
||||
msgid "Services"
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/services/forms.py:6
|
||||
msgid "Name of Fleet:"
|
||||
msgstr "Nombre de la flota:"
|
||||
@@ -1259,15 +1295,80 @@ msgstr "La contraseña tiene que tener 8 caracteres de largo minimo"
|
||||
msgid "Link Discord Server"
|
||||
msgstr "Enlace a servidor de Discord"
|
||||
|
||||
#: allianceauth/services/modules/openfire/forms.py:7
|
||||
msgid "Message"
|
||||
msgstr "Mensaje"
|
||||
#: allianceauth/services/modules/discord/views.py:26
|
||||
msgid "Deactivated Discord account."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/services/modules/discord/views.py:29
|
||||
#: allianceauth/services/modules/discord/views.py:41
|
||||
#: allianceauth/services/modules/discord/views.py:65
|
||||
msgid "An error occurred while processing your Discord account."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/services/modules/discord/views.py:62
|
||||
msgid "Activated Discord account."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/services/modules/discourse/views.py:37
|
||||
msgid "You are not authorized to access Discourse."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/services/modules/discourse/views.py:42
|
||||
msgid "You must have a main character set to access Discourse."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/services/modules/discourse/views.py:52
|
||||
msgid ""
|
||||
"No SSO payload or signature. Please contact support if this problem "
|
||||
"persists."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/services/modules/discourse/views.py:62
|
||||
#: allianceauth/services/modules/discourse/views.py:70
|
||||
msgid "Invalid payload. Please contact support if this problem persists."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/services/modules/ips4/views.py:31
|
||||
msgid "Activated IPSuite4 account."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/services/modules/ips4/views.py:40
|
||||
#: allianceauth/services/modules/ips4/views.py:62
|
||||
#: allianceauth/services/modules/ips4/views.py:83
|
||||
#: allianceauth/services/modules/ips4/views.py:103
|
||||
msgid "An error occurred while processing your IPSuite4 account."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/services/modules/ips4/views.py:53
|
||||
msgid "Reset IPSuite4 password."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/services/modules/ips4/views.py:80
|
||||
msgid "Set IPSuite4 password."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/services/modules/ips4/views.py:100
|
||||
msgid "Deactivated IPSuite4 account."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/services/modules/openfire/auth_hooks.py:26
|
||||
msgid "Jabber"
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/services/modules/openfire/auth_hooks.py:78
|
||||
#: allianceauth/services/modules/openfire/templates/services/openfire/broadcast.html:6
|
||||
#: allianceauth/services/modules/openfire/templates/services/openfire/broadcast.html:11
|
||||
msgid "Jabber Broadcast"
|
||||
msgstr "Anuncio por Jabber"
|
||||
|
||||
#: allianceauth/services/modules/openfire/auth_hooks.py:91
|
||||
msgid "Fleet Broadcast Formatter"
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/services/modules/openfire/forms.py:7
|
||||
msgid "Message"
|
||||
msgstr "Mensaje"
|
||||
|
||||
#: allianceauth/services/modules/openfire/templates/services/openfire/broadcast.html:17
|
||||
msgid "Broadcast Sent!!"
|
||||
msgstr "Ping Enviado"
|
||||
@@ -1276,6 +1377,76 @@ msgstr "Ping Enviado"
|
||||
msgid "Broadcast"
|
||||
msgstr "Anuncio"
|
||||
|
||||
#: allianceauth/services/modules/openfire/views.py:35
|
||||
msgid "Activated jabber account."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/services/modules/openfire/views.py:44
|
||||
#: allianceauth/services/modules/openfire/views.py:57
|
||||
#: allianceauth/services/modules/openfire/views.py:78
|
||||
#: allianceauth/services/modules/openfire/views.py:151
|
||||
msgid "An error occurred while processing your jabber account."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/services/modules/openfire/views.py:70
|
||||
msgid "Reset jabber password."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/services/modules/openfire/views.py:119
|
||||
#, python-format
|
||||
msgid "Sent jabber broadcast to %s"
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/services/modules/openfire/views.py:148
|
||||
msgid "Set jabber password."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/services/modules/phpbb3/views.py:34
|
||||
msgid "Activated forum account."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/services/modules/phpbb3/views.py:43
|
||||
#: allianceauth/services/modules/phpbb3/views.py:57
|
||||
#: allianceauth/services/modules/phpbb3/views.py:80
|
||||
#: allianceauth/services/modules/phpbb3/views.py:103
|
||||
msgid "An error occurred while processing your forum account."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/services/modules/phpbb3/views.py:54
|
||||
msgid "Deactivated forum account."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/services/modules/phpbb3/views.py:71
|
||||
msgid "Reset forum password."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/services/modules/phpbb3/views.py:100
|
||||
msgid "Set forum password."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/services/modules/smf/views.py:34
|
||||
msgid "Activated SMF account."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/services/modules/smf/views.py:43
|
||||
#: allianceauth/services/modules/smf/views.py:58
|
||||
#: allianceauth/services/modules/smf/views.py:80
|
||||
#: allianceauth/services/modules/smf/views.py:103
|
||||
msgid "An error occurred while processing your SMF account."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/services/modules/smf/views.py:55
|
||||
msgid "Deactivated SMF account."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/services/modules/smf/views.py:72
|
||||
msgid "Reset SMF password."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/services/modules/smf/views.py:100
|
||||
msgid "Set SMF password."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/services/modules/teamspeak3/forms.py:14
|
||||
#, python-format
|
||||
msgid "Unable to locate user %s on server"
|
||||
@@ -1299,6 +1470,47 @@ msgstr "Unirse al Servidor"
|
||||
msgid "Continue"
|
||||
msgstr "Continuar"
|
||||
|
||||
#: allianceauth/services/modules/teamspeak3/views.py:34
|
||||
msgid "Activated TeamSpeak3 account."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/services/modules/teamspeak3/views.py:37
|
||||
#: allianceauth/services/modules/teamspeak3/views.py:74
|
||||
#: allianceauth/services/modules/teamspeak3/views.py:100
|
||||
msgid "An error occurred while processing your TeamSpeak3 account."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/services/modules/teamspeak3/views.py:71
|
||||
msgid "Deactivated TeamSpeak3 account."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/services/modules/teamspeak3/views.py:97
|
||||
msgid "Reset TeamSpeak3 permission key."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/services/modules/xenforo/views.py:30
|
||||
msgid "Activated XenForo account."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/services/modules/xenforo/views.py:40
|
||||
#: allianceauth/services/modules/xenforo/views.py:52
|
||||
#: allianceauth/services/modules/xenforo/views.py:73
|
||||
#: allianceauth/services/modules/xenforo/views.py:94
|
||||
msgid "An error occurred while processing your XenForo account."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/services/modules/xenforo/views.py:50
|
||||
msgid "Deactivated XenForo account."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/services/modules/xenforo/views.py:65
|
||||
msgid "Reset XenForo account password."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/services/modules/xenforo/views.py:91
|
||||
msgid "Changed XenForo password."
|
||||
msgstr ""
|
||||
|
||||
#: allianceauth/services/templates/services/fleetformattertool.html:6
|
||||
msgid "Fleet Formatter Tool"
|
||||
msgstr "Formato de Ping"
|
||||
|
||||
BIN
allianceauth/locale/ko_KR/LC_MESSAGES/django.mo
Normal file
BIN
allianceauth/locale/ko_KR/LC_MESSAGES/django.mo
Normal file
Binary file not shown.
2023
allianceauth/locale/ko_KR/LC_MESSAGES/django.po
Normal file
2023
allianceauth/locale/ko_KR/LC_MESSAGES/django.po
Normal file
File diff suppressed because it is too large
Load Diff
BIN
allianceauth/locale/ru/LC_MESSAGES/django.mo
Normal file
BIN
allianceauth/locale/ru/LC_MESSAGES/django.mo
Normal file
Binary file not shown.
2038
allianceauth/locale/ru/LC_MESSAGES/django.po
Normal file
2038
allianceauth/locale/ru/LC_MESSAGES/django.po
Normal file
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@@ -5,15 +5,16 @@
|
||||
#
|
||||
# Translators:
|
||||
# Joel Falknau <ozirascal@gmail.com>, 2020
|
||||
# Jesse . <sgeine@hotmail.com>, 2020
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2020-03-04 23:04+0000\n"
|
||||
"POT-Creation-Date: 2020-03-10 01:32+0000\n"
|
||||
"PO-Revision-Date: 2020-02-18 03:14+0000\n"
|
||||
"Last-Translator: Joel Falknau <ozirascal@gmail.com>, 2020\n"
|
||||
"Last-Translator: Jesse . <sgeine@hotmail.com>, 2020\n"
|
||||
"Language-Team: Chinese Simplified (https://www.transifex.com/alliance-auth/teams/107430/zh-Hans/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
@@ -68,10 +69,8 @@ msgid "Change Main"
|
||||
msgstr "修改主要角色"
|
||||
|
||||
#: allianceauth/authentication/templates/authentication/dashboard.html:97
|
||||
#: allianceauth/permissions_tool/templates/permissions_tool/overview.html:40
|
||||
#: allianceauth/templates/allianceauth/side-menu.html:15
|
||||
msgid "Groups"
|
||||
msgstr "群组"
|
||||
msgid "Group Memberships"
|
||||
msgstr "用户组成员"
|
||||
|
||||
#: allianceauth/authentication/templates/authentication/dashboard.html:117
|
||||
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkstatisticscorpview.html:23
|
||||
@@ -135,40 +134,40 @@ msgstr "您的IT团队"
|
||||
msgid "Submit"
|
||||
msgstr "提交"
|
||||
|
||||
#: allianceauth/authentication/views.py:39
|
||||
#: allianceauth/authentication/views.py:77
|
||||
#, python-format
|
||||
msgid "Changed main character to %(char)s"
|
||||
msgstr "修改主要角色为%(char)s"
|
||||
|
||||
#: allianceauth/authentication/views.py:48
|
||||
#: allianceauth/authentication/views.py:86
|
||||
#, python-format
|
||||
msgid "Added %(name)s to your account."
|
||||
msgstr "添加%(name)s到您的账户"
|
||||
|
||||
#: allianceauth/authentication/views.py:50
|
||||
#: allianceauth/authentication/views.py:88
|
||||
#, python-format
|
||||
msgid "Failed to add %(name)s to your account: they already have an account."
|
||||
msgstr "添加%(name)s到您的账户失败:他们已经在一个账户中了"
|
||||
|
||||
#: allianceauth/authentication/views.py:89
|
||||
#: allianceauth/authentication/views.py:127
|
||||
msgid "Unable to authenticate as the selected character."
|
||||
msgstr "无法作为选定的角色进行身份验证"
|
||||
|
||||
#: allianceauth/authentication/views.py:107
|
||||
#: allianceauth/authentication/views.py:145
|
||||
msgid "Registration token has expired."
|
||||
msgstr "注册令牌过期。"
|
||||
|
||||
#: allianceauth/authentication/views.py:159
|
||||
#: allianceauth/authentication/views.py:197
|
||||
msgid ""
|
||||
"Sent confirmation email. Please follow the link to confirm your email "
|
||||
"address."
|
||||
msgstr "已经发送了确认邮件。请按照链接确定您的电邮地址"
|
||||
|
||||
#: allianceauth/authentication/views.py:164
|
||||
#: allianceauth/authentication/views.py:202
|
||||
msgid "Confirmed your email address. Please login to continue."
|
||||
msgstr "已确认您的电邮地址。请登录以继续"
|
||||
|
||||
#: allianceauth/authentication/views.py:169
|
||||
#: allianceauth/authentication/views.py:207
|
||||
msgid "Registraion of new accounts it not allowed at this time."
|
||||
msgstr "现在不允许注册新账户。"
|
||||
|
||||
@@ -706,61 +705,61 @@ msgstr "用户组请求"
|
||||
msgid "Group Membership"
|
||||
msgstr "用户组成员"
|
||||
|
||||
#: allianceauth/groupmanagement/views.py:164
|
||||
#: allianceauth/groupmanagement/views.py:165
|
||||
#, python-format
|
||||
msgid "Removed user %(user)s from group %(group)s."
|
||||
msgstr "已将用户%(user)s从用户组%(group)s中移除"
|
||||
|
||||
#: allianceauth/groupmanagement/views.py:166
|
||||
#: allianceauth/groupmanagement/views.py:167
|
||||
msgid "User does not exist in that group"
|
||||
msgstr "那个用户组中不存在这个用户"
|
||||
|
||||
#: allianceauth/groupmanagement/views.py:169
|
||||
#: allianceauth/groupmanagement/views.py:170
|
||||
msgid "Group does not exist"
|
||||
msgstr "用户组不存在"
|
||||
|
||||
#: allianceauth/groupmanagement/views.py:196
|
||||
#: allianceauth/groupmanagement/views.py:197
|
||||
#, python-format
|
||||
msgid "Accepted application from %(mainchar)s to %(group)s."
|
||||
msgstr "已接受用户%(mainchar)s加入%(group)s的申请"
|
||||
|
||||
#: allianceauth/groupmanagement/views.py:203
|
||||
#: allianceauth/groupmanagement/views.py:236
|
||||
#: allianceauth/groupmanagement/views.py:204
|
||||
#: allianceauth/groupmanagement/views.py:237
|
||||
#, python-format
|
||||
msgid ""
|
||||
"An unhandled error occurred while processing the application from "
|
||||
"%(mainchar)s to %(group)s."
|
||||
msgstr "在处理用户%(mainchar)s加入%(group)s的申请的过程中出现了一个搞不定的错误"
|
||||
|
||||
#: allianceauth/groupmanagement/views.py:229
|
||||
#: allianceauth/groupmanagement/views.py:230
|
||||
#, python-format
|
||||
msgid "Rejected application from %(mainchar)s to %(group)s."
|
||||
msgstr "%(mainchar)s加入%(group)s的申请已拒绝"
|
||||
|
||||
#: allianceauth/groupmanagement/views.py:265
|
||||
#: allianceauth/groupmanagement/views.py:266
|
||||
#, python-format
|
||||
msgid "Accepted application from %(mainchar)s to leave %(group)s."
|
||||
msgstr "%(mainchar)s加入%(group)s的申请已通过"
|
||||
|
||||
#: allianceauth/groupmanagement/views.py:271
|
||||
#: allianceauth/groupmanagement/views.py:305
|
||||
#: allianceauth/groupmanagement/views.py:272
|
||||
#: allianceauth/groupmanagement/views.py:306
|
||||
#, python-format
|
||||
msgid ""
|
||||
"An unhandled error occured while processing the application from "
|
||||
"%(mainchar)s to leave %(group)s."
|
||||
msgstr "在处理%(mainchar)s离开%(group)s的请求时发生了搞不定的错误"
|
||||
|
||||
#: allianceauth/groupmanagement/views.py:298
|
||||
#: allianceauth/groupmanagement/views.py:299
|
||||
#, python-format
|
||||
msgid "Rejected application from %(mainchar)s to leave %(group)s."
|
||||
msgstr "%(mainchar)s离开%(group)s的请求已被拒绝"
|
||||
|
||||
#: allianceauth/groupmanagement/views.py:345
|
||||
#: allianceauth/groupmanagement/views.py:346
|
||||
msgid "You cannot join that group"
|
||||
msgstr "你无法加入那个用户组"
|
||||
|
||||
#: allianceauth/groupmanagement/views.py:369
|
||||
#: allianceauth/groupmanagement/views.py:407
|
||||
#: allianceauth/groupmanagement/views.py:370
|
||||
#: allianceauth/groupmanagement/views.py:408
|
||||
#: allianceauth/hrapplications/templates/hrapplications/management.html:37
|
||||
#: allianceauth/hrapplications/templates/hrapplications/management.html:72
|
||||
#: allianceauth/hrapplications/templates/hrapplications/management.html:99
|
||||
@@ -772,20 +771,20 @@ msgstr "你无法加入那个用户组"
|
||||
msgid "Pending"
|
||||
msgstr "待定"
|
||||
|
||||
#: allianceauth/groupmanagement/views.py:375
|
||||
#: allianceauth/groupmanagement/views.py:376
|
||||
#, python-format
|
||||
msgid "Applied to group %(group)s."
|
||||
msgstr "修改已经应用到%(group)s啦"
|
||||
|
||||
#: allianceauth/groupmanagement/views.py:386
|
||||
#: allianceauth/groupmanagement/views.py:387
|
||||
msgid "You cannot leave that group"
|
||||
msgstr "你无法离开那个用户组"
|
||||
|
||||
#: allianceauth/groupmanagement/views.py:391
|
||||
#: allianceauth/groupmanagement/views.py:392
|
||||
msgid "You are not a member of that group"
|
||||
msgstr "你不是那个用户组的成员"
|
||||
|
||||
#: allianceauth/groupmanagement/views.py:413
|
||||
#: allianceauth/groupmanagement/views.py:414
|
||||
#, python-format
|
||||
msgid "Applied to leave group %(group)s."
|
||||
msgstr "已经离开群组%(group)s"
|
||||
@@ -1176,6 +1175,11 @@ msgstr "操作类型"
|
||||
msgid "Users"
|
||||
msgstr "用户"
|
||||
|
||||
#: allianceauth/permissions_tool/templates/permissions_tool/overview.html:40
|
||||
#: allianceauth/templates/allianceauth/side-menu.html:15
|
||||
msgid "Groups"
|
||||
msgstr "群组"
|
||||
|
||||
#: allianceauth/permissions_tool/templates/permissions_tool/overview.html:43
|
||||
msgid "States"
|
||||
msgstr "声望"
|
||||
|
||||
@@ -11,6 +11,15 @@ app = Celery('{{ project_name }}')
|
||||
# Using a string here means the worker don't have to serialize
|
||||
# the configuration object to child processes.
|
||||
app.config_from_object('django.conf:settings')
|
||||
|
||||
# setup priorities ( 0 Highest, 9 Lowest )
|
||||
app.conf.broker_transport_options = {
|
||||
'priority_steps': list(range(10)), # setup que to have 10 steps
|
||||
'queue_order_strategy': 'priority', # setup que to use prio sorting
|
||||
}
|
||||
app.conf.task_default_priority = 5 # anything called with the task.delay() will be given normal priority (5)
|
||||
app.conf.worker_prefetch_multiplier = 1 # only prefetch single tasks at a time on the workers so that prio tasks happen
|
||||
|
||||
app.conf.ONCE = {
|
||||
'backend': 'allianceauth.services.tasks.DjangoBackend',
|
||||
'settings': {}
|
||||
|
||||
@@ -84,6 +84,8 @@ LANGUAGES = (
|
||||
('de', ugettext('German')),
|
||||
('es', ugettext('Spanish')),
|
||||
('zh-hans', ugettext('Chinese Simplified')),
|
||||
('ru', ugettext('Russian')),
|
||||
('ko', ugettext('Korean')),
|
||||
)
|
||||
|
||||
TEMPLATES = [
|
||||
@@ -218,6 +220,14 @@ LOGGING = {
|
||||
'maxBytes': 1024 * 1024 * 5, # edit this line to change max log file size
|
||||
'backupCount': 5, # edit this line to change number of log backups
|
||||
},
|
||||
'extension_file': {
|
||||
'level': 'DEBUG',
|
||||
'class': 'logging.handlers.RotatingFileHandler',
|
||||
'filename': os.path.join(BASE_DIR, 'log/extensions.log'),
|
||||
'formatter': 'verbose',
|
||||
'maxBytes': 1024 * 1024 * 5, # edit this line to change max log file size
|
||||
'backupCount': 5, # edit this line to change number of log backups
|
||||
},
|
||||
'console': {
|
||||
'level': 'DEBUG', # edit this line to change logging level to console
|
||||
'class': 'logging.StreamHandler',
|
||||
@@ -234,6 +244,10 @@ LOGGING = {
|
||||
'handlers': ['log_file', 'console', 'notifications'],
|
||||
'level': 'DEBUG',
|
||||
},
|
||||
'extensions': {
|
||||
'handlers': ['extension_file', 'console'],
|
||||
'level': 'DEBUG',
|
||||
},
|
||||
'django': {
|
||||
'handlers': ['log_file', 'console'],
|
||||
'level': 'ERROR',
|
||||
|
||||
@@ -17,6 +17,7 @@ from django.contrib.auth.mixins import LoginRequiredMixin, PermissionRequiredMix
|
||||
from django.db import models, IntegrityError
|
||||
from django.core.exceptions import ObjectDoesNotExist
|
||||
from django.shortcuts import render, Http404, redirect
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from .forms import ServicePasswordModelForm
|
||||
|
||||
@@ -68,7 +69,7 @@ class BaseCreatePasswordServiceAccountView(BaseServiceView, ServiceCredentialsVi
|
||||
try:
|
||||
svc_obj = self.model.objects.create(user=request.user)
|
||||
except IntegrityError:
|
||||
messages.error(request, "That service account already exists")
|
||||
messages.error(request, _("That service account already exists"))
|
||||
return redirect(self.index_redirect)
|
||||
|
||||
return render(request, self.template_name,
|
||||
@@ -100,7 +101,7 @@ class BaseSetPasswordServiceAccountView(ServicesCRUDMixin, BaseServiceView, Upda
|
||||
def post(self, request, *args, **kwargs):
|
||||
result = super(BaseSetPasswordServiceAccountView, self).post(request, *args, **kwargs)
|
||||
if self.get_form().is_valid():
|
||||
messages.success(request, "Successfully set your {} password".format(self.service_name))
|
||||
messages.success(request, _("Successfully set your {} password".format(self.service_name)))
|
||||
return result
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from allianceauth import hooks
|
||||
|
||||
from .hooks import MenuItemHook
|
||||
from .hooks import ServicesHook
|
||||
|
||||
@@ -6,7 +8,7 @@ from .hooks import ServicesHook
|
||||
class Services(MenuItemHook):
|
||||
def __init__(self):
|
||||
MenuItemHook.__init__(self,
|
||||
'Services',
|
||||
_('Services'),
|
||||
'fa fa-cogs fa-fw',
|
||||
'services:services', 100)
|
||||
|
||||
|
||||
@@ -9,6 +9,29 @@ from allianceauth.hooks import get_hooks
|
||||
from .models import NameFormatConfig
|
||||
|
||||
|
||||
def get_extension_logger(name):
|
||||
"""
|
||||
Takes the name of a plugin/extension and generates a child logger of the extensions logger
|
||||
to be used by the extension to log events to the extensions logger.
|
||||
|
||||
The logging level is decided by whether or not DEBUG is set to true in the project settings. If
|
||||
DEBUG is set to false, then the logging level is set to INFO.
|
||||
|
||||
:param: name: the name of the extension doing the logging
|
||||
:return: an extensions child logger
|
||||
"""
|
||||
import logging
|
||||
from django.conf import settings
|
||||
|
||||
logger = logging.getLogger('extensions.' + name)
|
||||
logger.name = name
|
||||
logger.level = logging.INFO
|
||||
if settings.DEBUG:
|
||||
logger.level = logging.DEBUG
|
||||
|
||||
return logger
|
||||
|
||||
|
||||
class ServicesHook:
|
||||
"""
|
||||
Abstract base class for creating a compatible services
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.10.1 on 2016-09-05 21:40
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
('auth', '0008_alter_user_username_max_length'),
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='DiscordAuthToken',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('email', models.CharField(max_length=254, unique=True)),
|
||||
('token', models.CharField(max_length=254)),
|
||||
('user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='GroupCache',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('created', models.DateTimeField(auto_now_add=True)),
|
||||
('groups', models.TextField(default={})),
|
||||
('service', models.CharField(choices=[(b'discourse', b'discourse'), (b'discord', b'discord')], max_length=254, unique=True)),
|
||||
],
|
||||
),
|
||||
]
|
||||
@@ -1,22 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.10.1 on 2016-10-16 01:35
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('services', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='discordauthtoken',
|
||||
name='user',
|
||||
),
|
||||
migrations.DeleteModel(
|
||||
name='DiscordAuthToken',
|
||||
),
|
||||
]
|
||||
@@ -1,18 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.10.5 on 2017-09-02 06:07
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('services', '0002_auto_20161016_0135'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.DeleteModel(
|
||||
name='GroupCache',
|
||||
),
|
||||
]
|
||||
18
allianceauth/services/migrations/0003_remove_broken_link.py
Normal file
18
allianceauth/services/migrations/0003_remove_broken_link.py
Normal file
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 2.2.10 on 2020-03-21 13:11
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('services', '0002_nameformatter'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='nameformatconfig',
|
||||
name='format',
|
||||
field=models.CharField(help_text='For information on constructing name formats please see the official documentation, topic "Services Name Formats".', max_length=100),
|
||||
),
|
||||
]
|
||||
@@ -4,14 +4,30 @@ from allianceauth.authentication.models import State
|
||||
|
||||
|
||||
class NameFormatConfig(models.Model):
|
||||
service_name = models.CharField(max_length=100, blank=False, null=False)
|
||||
default_to_username = models.BooleanField(default=True, help_text="If a user has no main_character, "
|
||||
"default to using their Auth username instead.")
|
||||
format = models.CharField(max_length=100, blank=False, null=False,
|
||||
help_text='For information on constructing name formats, please see the '
|
||||
'<a href="https://allianceauth.readthedocs.io/en/latest/features/nameformats">'
|
||||
'name format documentation</a>')
|
||||
states = models.ManyToManyField(State, help_text="States to apply this format to. You should only have one "
|
||||
"formatter for each state for each service.")
|
||||
service_name = models.CharField(max_length=100, blank=False)
|
||||
default_to_username = models.BooleanField(
|
||||
default=True,
|
||||
help_text=
|
||||
'If a user has no main_character, '
|
||||
'default to using their Auth username instead.'
|
||||
)
|
||||
format = models.CharField(
|
||||
max_length=100,
|
||||
blank=False,
|
||||
help_text=
|
||||
'For information on constructing name formats '
|
||||
'please see the official documentation, '
|
||||
'topic "Services Name Formats".'
|
||||
)
|
||||
states = models.ManyToManyField(
|
||||
State,
|
||||
help_text=
|
||||
"States to apply this format to. You should only have one "
|
||||
"formatter for each state for each service."
|
||||
)
|
||||
|
||||
def __str__(self):
|
||||
return '%s: %s' % (
|
||||
self.service_name, ', '.join([str(x) for x in self.states.all()])
|
||||
)
|
||||
|
||||
|
||||
@@ -5,8 +5,10 @@ from django.contrib.auth.decorators import login_required
|
||||
from django.contrib.auth.decorators import permission_required
|
||||
from django.contrib.auth.decorators import user_passes_test
|
||||
from django.shortcuts import redirect
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from allianceauth.services.views import superuser_test
|
||||
|
||||
from .manager import DiscordOAuthManager
|
||||
from .tasks import DiscordTasks
|
||||
|
||||
@@ -21,10 +23,10 @@ def deactivate_discord(request):
|
||||
logger.debug("deactivate_discord called by user %s" % request.user)
|
||||
if DiscordTasks.delete_user(request.user):
|
||||
logger.info("Successfully deactivated discord for user %s" % request.user)
|
||||
messages.success(request, 'Deactivated Discord account.')
|
||||
messages.success(request, _('Deactivated Discord account.'))
|
||||
else:
|
||||
logger.error("Unsuccessful attempt to deactivate discord for user %s" % request.user)
|
||||
messages.error(request, 'An error occurred while processing your Discord account.')
|
||||
messages.error(request, _('An error occurred while processing your Discord account.'))
|
||||
return redirect("services:services")
|
||||
|
||||
|
||||
@@ -36,7 +38,7 @@ def reset_discord(request):
|
||||
logger.info("Successfully deleted discord user for user %s - forwarding to discord activation." % request.user)
|
||||
return redirect("discord:activate")
|
||||
logger.error("Unsuccessful attempt to reset discord for user %s" % request.user)
|
||||
messages.error(request, 'An error occurred while processing your Discord account.')
|
||||
messages.error(request, _('An error occurred while processing your Discord account.'))
|
||||
return redirect("services:services")
|
||||
|
||||
|
||||
@@ -57,10 +59,10 @@ def discord_callback(request):
|
||||
return redirect("services:services")
|
||||
if DiscordTasks.add_user(request.user, code):
|
||||
logger.info("Successfully activated Discord for user %s" % request.user)
|
||||
messages.success(request, 'Activated Discord account.')
|
||||
messages.success(request, _('Activated Discord account.'))
|
||||
else:
|
||||
logger.error("Failed to activate Discord for user %s" % request.user)
|
||||
messages.error(request, 'An error occurred while processing your Discord account.')
|
||||
messages.error(request, _('An error occurred while processing your Discord account.'))
|
||||
return redirect("services:services")
|
||||
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ from django.conf import settings
|
||||
from django.contrib import messages
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.shortcuts import render, redirect
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from .manager import DiscourseManager
|
||||
from .tasks import DiscourseTasks
|
||||
@@ -33,12 +34,12 @@ def discourse_sso(request):
|
||||
|
||||
# Check if user has access
|
||||
if not request.user.has_perm(ACCESS_PERM):
|
||||
messages.error(request, 'You are not authorized to access Discourse.')
|
||||
messages.error(request, _('You are not authorized to access Discourse.'))
|
||||
logger.warning('User %s attempted to access Discourse but does not have permission.' % request.user)
|
||||
return redirect('authentication:dashboard')
|
||||
|
||||
if not request.user.profile.main_character:
|
||||
messages.error(request, "You must have a main character set to access Discourse.")
|
||||
messages.error(request, _("You must have a main character set to access Discourse."))
|
||||
logger.warning('User %s attempted to access Discourse but does not have a main character.' % request.user)
|
||||
return redirect('authentication:characters')
|
||||
|
||||
@@ -48,7 +49,7 @@ def discourse_sso(request):
|
||||
signature = request.GET.get('sig')
|
||||
|
||||
if None in [payload, signature]:
|
||||
messages.error(request, 'No SSO payload or signature. Please contact support if this problem persists.')
|
||||
messages.error(request, _('No SSO payload or signature. Please contact support if this problem persists.'))
|
||||
return redirect('authentication:dashboard')
|
||||
|
||||
# Validate the payload
|
||||
@@ -58,7 +59,7 @@ def discourse_sso(request):
|
||||
assert 'nonce' in decoded
|
||||
assert len(payload) > 0
|
||||
except AssertionError:
|
||||
messages.error(request, 'Invalid payload. Please contact support if this problem persists.')
|
||||
messages.error(request, _('Invalid payload. Please contact support if this problem persists.'))
|
||||
return redirect('authentication:dashboard')
|
||||
|
||||
key = str(settings.DISCOURSE_SSO_SECRET).encode('utf-8')
|
||||
@@ -66,7 +67,7 @@ def discourse_sso(request):
|
||||
this_signature = h.hexdigest()
|
||||
|
||||
if this_signature != signature:
|
||||
messages.error(request, 'Invalid payload. Please contact support if this problem persists.')
|
||||
messages.error(request, _('Invalid payload. Please contact support if this problem persists.'))
|
||||
return redirect('authentication:dashboard')
|
||||
|
||||
## Build the return payload
|
||||
|
||||
@@ -3,6 +3,7 @@ import logging
|
||||
from django.contrib import messages
|
||||
from django.contrib.auth.decorators import login_required, permission_required
|
||||
from django.shortcuts import render, redirect
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from allianceauth.services.forms import ServicePasswordForm
|
||||
from .manager import Ips4Manager
|
||||
@@ -27,7 +28,7 @@ def activate_ips4(request):
|
||||
logger.debug("Updated authserviceinfo for user %s with IPS4 credentials." % request.user)
|
||||
# update_ips4_groups.delay(request.user.pk)
|
||||
logger.info("Successfully activated IPS4 for user %s" % request.user)
|
||||
messages.success(request, 'Activated IPSuite4 account.')
|
||||
messages.success(request, _('Activated IPSuite4 account.'))
|
||||
credentials = {
|
||||
'username': result[0],
|
||||
'password': result[1],
|
||||
@@ -36,7 +37,7 @@ def activate_ips4(request):
|
||||
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.')
|
||||
messages.error(request, _('An error occurred while processing your IPSuite4 account.'))
|
||||
return redirect("services:services")
|
||||
|
||||
|
||||
@@ -49,7 +50,7 @@ def reset_ips4_password(request):
|
||||
# false we failed
|
||||
if result != "":
|
||||
logger.info("Successfully reset IPS4 password for user %s" % request.user)
|
||||
messages.success(request, 'Reset IPSuite4 password.')
|
||||
messages.success(request, _('Reset IPSuite4 password.'))
|
||||
credentials = {
|
||||
'username': request.user.ips4.username,
|
||||
'password': result,
|
||||
@@ -58,7 +59,7 @@ def reset_ips4_password(request):
|
||||
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.')
|
||||
messages.error(request, _('An error occurred while processing your IPSuite4 account.'))
|
||||
return redirect("services:services")
|
||||
|
||||
|
||||
@@ -76,10 +77,10 @@ def set_ips4_password(request):
|
||||
result = Ips4Manager.update_custom_password(request.user.ips4.username, plain_password=password)
|
||||
if result != "":
|
||||
logger.info("Successfully set IPS4 password for user %s" % request.user)
|
||||
messages.success(request, 'Set IPSuite4 password.')
|
||||
messages.success(request, _('Set IPSuite4 password.'))
|
||||
else:
|
||||
logger.error("Failed to install custom IPS4 password for user %s" % request.user)
|
||||
messages.error(request, 'An error occurred while processing your IPSuite4 account.')
|
||||
messages.error(request, _('An error occurred while processing your IPSuite4 account.'))
|
||||
return redirect('services:services')
|
||||
else:
|
||||
logger.debug("Request is not type POST - providing empty form.")
|
||||
@@ -96,9 +97,9 @@ def deactivate_ips4(request):
|
||||
logger.debug("deactivate_ips4 called by user %s" % request.user)
|
||||
if Ips4Tasks.delete_user(request.user):
|
||||
logger.info("Successfully deactivated IPS4 for user %s" % request.user)
|
||||
messages.success(request, 'Deactivated IPSuite4 account.')
|
||||
messages.success(request, _('Deactivated IPSuite4 account.'))
|
||||
else:
|
||||
logger.error("Unsuccessful attempt to deactivate IPS4 for user %s" % request.user)
|
||||
messages.error(request, 'An error occurred while processing your IPSuite4 account.')
|
||||
messages.error(request, _('An error occurred while processing your IPSuite4 account.'))
|
||||
return redirect("services:services")
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ import logging
|
||||
|
||||
from django.conf import settings
|
||||
from django.template.loader import render_to_string
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from allianceauth import hooks
|
||||
from allianceauth.services.hooks import ServicesHook, MenuItemHook
|
||||
@@ -22,7 +23,7 @@ class OpenfireService(ServicesHook):
|
||||
|
||||
@property
|
||||
def title(self):
|
||||
return "Jabber"
|
||||
return _("Jabber")
|
||||
|
||||
def delete_user(self, user, notify_user=False):
|
||||
logger.debug('Deleting user %s %s account' % (user, self.name))
|
||||
@@ -74,7 +75,7 @@ def register_service():
|
||||
class JabberBroadcast(MenuItemHook):
|
||||
def __init__(self):
|
||||
MenuItemHook.__init__(self,
|
||||
'Jabber Broadcast',
|
||||
_('Jabber Broadcast'),
|
||||
'fa fa-lock fa-fw fa-bullhorn',
|
||||
'openfire:broadcast')
|
||||
|
||||
@@ -87,7 +88,7 @@ class JabberBroadcast(MenuItemHook):
|
||||
class FleetBroadcastFormatter(MenuItemHook):
|
||||
def __init__(self):
|
||||
MenuItemHook.__init__(self,
|
||||
'Fleet Broadcast Formatter',
|
||||
_('Fleet Broadcast Formatter'),
|
||||
'fa fa-lock fa-fw fa-space-shuttle',
|
||||
'services:fleet_format_tool')
|
||||
|
||||
|
||||
@@ -5,8 +5,10 @@ from django.contrib import messages
|
||||
from django.contrib.auth.decorators import login_required, permission_required
|
||||
from django.contrib.auth.models import Group
|
||||
from django.shortcuts import render, redirect
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from allianceauth.services.forms import ServicePasswordForm
|
||||
|
||||
from .forms import JabberBroadcastForm
|
||||
from .manager import OpenfireManager, PingBotException
|
||||
from .models import OpenfireUser
|
||||
@@ -30,7 +32,7 @@ def activate_jabber(request):
|
||||
logger.debug("Updated authserviceinfo for user %s with jabber credentials. Updating groups." % request.user)
|
||||
OpenfireTasks.update_groups.delay(request.user.pk)
|
||||
logger.info("Successfully activated jabber for user %s" % request.user)
|
||||
messages.success(request, 'Activated jabber account.')
|
||||
messages.success(request, _('Activated jabber account.'))
|
||||
credentials = {
|
||||
'username': info[0],
|
||||
'password': info[1],
|
||||
@@ -39,7 +41,7 @@ def activate_jabber(request):
|
||||
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.')
|
||||
messages.error(request, _('An error occurred while processing your jabber account.'))
|
||||
return redirect("services:services")
|
||||
|
||||
|
||||
@@ -52,7 +54,7 @@ def deactivate_jabber(request):
|
||||
messages.success(request, 'Deactivated jabber account.')
|
||||
else:
|
||||
logger.error("Unsuccessful attempt to deactivate jabber for user %s" % request.user)
|
||||
messages.error(request, 'An error occurred while processing your jabber account.')
|
||||
messages.error(request, _('An error occurred while processing your jabber account.'))
|
||||
return redirect("services:services")
|
||||
|
||||
|
||||
@@ -65,7 +67,7 @@ def reset_jabber_password(request):
|
||||
# If our username is blank means we failed
|
||||
if result != "":
|
||||
logger.info("Successfully reset jabber password for user %s" % request.user)
|
||||
messages.success(request, 'Reset jabber password.')
|
||||
messages.success(request, _('Reset jabber password.'))
|
||||
credentials = {
|
||||
'username': request.user.openfire.username,
|
||||
'password': result,
|
||||
@@ -73,7 +75,7 @@ def reset_jabber_password(request):
|
||||
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.')
|
||||
messages.error(request, _('An error occurred while processing your jabber account.'))
|
||||
return redirect("services:services")
|
||||
|
||||
|
||||
@@ -114,7 +116,7 @@ def jabber_broadcast_view(request):
|
||||
|
||||
OpenfireManager.send_broadcast_message(group_to_send, message_to_send)
|
||||
|
||||
messages.success(request, 'Sent jabber broadcast to %s' % group_to_send)
|
||||
messages.success(request, _('Sent jabber broadcast to %s' % group_to_send))
|
||||
logger.info("Sent jabber broadcast on behalf of user %s" % request.user)
|
||||
except PingBotException as e:
|
||||
messages.error(request, e)
|
||||
@@ -143,10 +145,10 @@ def set_jabber_password(request):
|
||||
result = OpenfireManager.update_user_pass(request.user.openfire.username, password=password)
|
||||
if result != "":
|
||||
logger.info("Successfully set jabber password for user %s" % request.user)
|
||||
messages.success(request, 'Set jabber password.')
|
||||
messages.success(request, _('Set jabber password.'))
|
||||
else:
|
||||
logger.error("Failed to install custom jabber password for user %s" % request.user)
|
||||
messages.error(request, 'An error occurred while processing your jabber account.')
|
||||
messages.error(request, _('An error occurred while processing your jabber account.'))
|
||||
return redirect("services:services")
|
||||
else:
|
||||
logger.debug("Request is not type POST - providing empty form.")
|
||||
|
||||
@@ -3,8 +3,10 @@ import logging
|
||||
from django.contrib import messages
|
||||
from django.contrib.auth.decorators import login_required, permission_required
|
||||
from django.shortcuts import render, redirect
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from allianceauth.services.forms import ServicePasswordForm
|
||||
|
||||
from .manager import Phpbb3Manager
|
||||
from .models import Phpbb3User
|
||||
from .tasks import Phpbb3Tasks
|
||||
@@ -29,7 +31,7 @@ def activate_forum(request):
|
||||
logger.debug("Updated authserviceinfo for user %s with forum credentials. Updating groups." % request.user)
|
||||
Phpbb3Tasks.update_groups.delay(request.user.pk)
|
||||
logger.info("Successfully activated forum for user %s" % request.user)
|
||||
messages.success(request, 'Activated forum account.')
|
||||
messages.success(request, _('Activated forum account.'))
|
||||
credentials = {
|
||||
'username': result[0],
|
||||
'password': result[1],
|
||||
@@ -38,7 +40,7 @@ def activate_forum(request):
|
||||
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.')
|
||||
messages.error(request, _('An error occurred while processing your forum account.'))
|
||||
return redirect("services:services")
|
||||
|
||||
|
||||
@@ -49,10 +51,10 @@ def deactivate_forum(request):
|
||||
# false we failed
|
||||
if Phpbb3Tasks.delete_user(request.user):
|
||||
logger.info("Successfully deactivated forum for user %s" % request.user)
|
||||
messages.success(request, 'Deactivated forum account.')
|
||||
messages.success(request, _('Deactivated forum account.'))
|
||||
else:
|
||||
logger.error("Unsuccessful attempt to activate forum for user %s" % request.user)
|
||||
messages.error(request, 'An error occurred while processing your forum account.')
|
||||
messages.error(request, _('An error occurred while processing your forum account.'))
|
||||
return redirect("services:services")
|
||||
|
||||
|
||||
@@ -66,7 +68,7 @@ def reset_forum_password(request):
|
||||
# false we failed
|
||||
if result != "":
|
||||
logger.info("Successfully reset forum password for user %s" % request.user)
|
||||
messages.success(request, 'Reset forum password.')
|
||||
messages.success(request, _('Reset forum password.'))
|
||||
credentials = {
|
||||
'username': request.user.phpbb3.username,
|
||||
'password': result,
|
||||
@@ -75,7 +77,7 @@ def reset_forum_password(request):
|
||||
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.')
|
||||
messages.error(request, _('An error occurred while processing your forum account.'))
|
||||
return redirect("services:services")
|
||||
|
||||
|
||||
@@ -95,10 +97,10 @@ def set_forum_password(request):
|
||||
password=password)
|
||||
if result != "":
|
||||
logger.info("Successfully set forum password for user %s" % request.user)
|
||||
messages.success(request, 'Set forum password.')
|
||||
messages.success(request, _('Set forum password.'))
|
||||
else:
|
||||
logger.error("Failed to install custom forum password for user %s" % request.user)
|
||||
messages.error(request, 'An error occurred while processing your forum account.')
|
||||
messages.error(request, _('An error occurred while processing your forum account.'))
|
||||
return redirect("services:services")
|
||||
else:
|
||||
logger.debug("Request is not type POST - providing empty form.")
|
||||
|
||||
@@ -3,8 +3,10 @@ import logging
|
||||
from django.contrib import messages
|
||||
from django.contrib.auth.decorators import login_required, permission_required
|
||||
from django.shortcuts import render, redirect
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from allianceauth.services.forms import ServicePasswordForm
|
||||
|
||||
from .manager import SmfManager
|
||||
from .models import SmfUser
|
||||
from .tasks import SmfTasks
|
||||
@@ -29,7 +31,7 @@ def activate_smf(request):
|
||||
logger.debug("Updated authserviceinfo for user %s with smf credentials. Updating groups." % request.user)
|
||||
SmfTasks.update_groups.delay(request.user.pk)
|
||||
logger.info("Successfully activated smf for user %s" % request.user)
|
||||
messages.success(request, 'Activated SMF account.')
|
||||
messages.success(request, _('Activated SMF account.'))
|
||||
credentials = {
|
||||
'username': result[0],
|
||||
'password': result[1],
|
||||
@@ -38,7 +40,7 @@ def activate_smf(request):
|
||||
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.')
|
||||
messages.error(request, _('An error occurred while processing your SMF account.'))
|
||||
return redirect("services:services")
|
||||
|
||||
|
||||
@@ -50,10 +52,10 @@ def deactivate_smf(request):
|
||||
# false we failed
|
||||
if result:
|
||||
logger.info("Successfully deactivated smf for user %s" % request.user)
|
||||
messages.success(request, 'Deactivated SMF account.')
|
||||
messages.success(request, _('Deactivated SMF account.'))
|
||||
else:
|
||||
logger.error("Unsuccessful attempt to activate smf for user %s" % request.user)
|
||||
messages.error(request, 'An error occurred while processing your SMF account.')
|
||||
messages.error(request, _('An error occurred while processing your SMF account.'))
|
||||
return redirect("services:services")
|
||||
|
||||
|
||||
@@ -67,7 +69,7 @@ def reset_smf_password(request):
|
||||
# false we failed
|
||||
if result != "":
|
||||
logger.info("Successfully reset smf password for user %s" % request.user)
|
||||
messages.success(request, 'Reset SMF password.')
|
||||
messages.success(request, _('Reset SMF password.'))
|
||||
credentials = {
|
||||
'username': request.user.smf.username,
|
||||
'password': result,
|
||||
@@ -75,7 +77,7 @@ def reset_smf_password(request):
|
||||
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.')
|
||||
messages.error(request, _('An error occurred while processing your SMF account.'))
|
||||
return redirect("services:services")
|
||||
|
||||
|
||||
@@ -95,10 +97,10 @@ def set_smf_password(request):
|
||||
password=password)
|
||||
if result != "":
|
||||
logger.info("Successfully set smf password for user %s" % request.user)
|
||||
messages.success(request, 'Set SMF password.')
|
||||
messages.success(request, _('Set SMF password.'))
|
||||
else:
|
||||
logger.error("Failed to install custom smf password for user %s" % request.user)
|
||||
messages.error(request, 'An error occurred while processing your SMF account.')
|
||||
messages.error(request, _('An error occurred while processing your SMF account.'))
|
||||
return redirect("services:services")
|
||||
else:
|
||||
logger.debug("Request is not type POST - providing empty form.")
|
||||
|
||||
@@ -4,6 +4,8 @@ from django.contrib import messages
|
||||
from django.contrib.auth.decorators import login_required, permission_required
|
||||
from django.shortcuts import render, redirect
|
||||
from django.conf import settings
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from .manager import Teamspeak3Manager
|
||||
from .forms import TeamspeakJoinForm
|
||||
from .models import Teamspeak3User
|
||||
@@ -29,10 +31,10 @@ def activate_teamspeak3(request):
|
||||
Teamspeak3User.objects.update_or_create(user=request.user, defaults={'uid': result[0], 'perm_key': result[1]})
|
||||
logger.debug("Updated authserviceinfo for user %s with TS3 credentials. Updating groups." % request.user)
|
||||
logger.info("Successfully activated TS3 for user %s" % request.user)
|
||||
messages.success(request, 'Activated TeamSpeak3 account.')
|
||||
messages.success(request, _('Activated TeamSpeak3 account.'))
|
||||
return redirect("teamspeak3:verify")
|
||||
logger.error("Unsuccessful attempt to activate TS3 for user %s" % request.user)
|
||||
messages.error(request, 'An error occurred while processing your TeamSpeak3 account.')
|
||||
messages.error(request, _('An error occurred while processing your TeamSpeak3 account.'))
|
||||
return redirect("services:services")
|
||||
|
||||
|
||||
@@ -66,10 +68,10 @@ def deactivate_teamspeak3(request):
|
||||
logger.debug("deactivate_teamspeak3 called by user %s" % request.user)
|
||||
if Teamspeak3Tasks.has_account(request.user) and Teamspeak3Tasks.delete_user(request.user):
|
||||
logger.info("Successfully deactivated TS3 for user %s" % request.user)
|
||||
messages.success(request, 'Deactivated TeamSpeak3 account.')
|
||||
messages.success(request, _('Deactivated TeamSpeak3 account.'))
|
||||
else:
|
||||
logger.error("Unsuccessful attempt to deactivate TS3 for user %s" % request.user)
|
||||
messages.error(request, 'An error occurred while processing your TeamSpeak3 account.')
|
||||
messages.error(request, _('An error occurred while processing your TeamSpeak3 account.'))
|
||||
return redirect("services:services")
|
||||
|
||||
|
||||
@@ -92,8 +94,8 @@ def reset_teamspeak3_perm(request):
|
||||
logger.debug("Updated authserviceinfo for user %s with TS3 credentials. Updating groups." % request.user)
|
||||
Teamspeak3Tasks.update_groups.delay(request.user.pk)
|
||||
logger.info("Successfully reset TS3 permission key for user %s" % request.user)
|
||||
messages.success(request, 'Reset TeamSpeak3 permission key.')
|
||||
messages.success(request, _('Reset TeamSpeak3 permission key.'))
|
||||
else:
|
||||
logger.error("Unsuccessful attempt to reset TS3 permission key for user %s" % request.user)
|
||||
messages.error(request, 'An error occurred while processing your TeamSpeak3 account.')
|
||||
messages.error(request, _('An error occurred while processing your TeamSpeak3 account.'))
|
||||
return redirect("services:services")
|
||||
|
||||
@@ -3,8 +3,10 @@ import logging
|
||||
from django.contrib import messages
|
||||
from django.contrib.auth.decorators import login_required, permission_required
|
||||
from django.shortcuts import render, redirect
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from allianceauth.services.forms import ServicePasswordForm
|
||||
|
||||
from .manager import XenForoManager
|
||||
from .models import XenforoUser
|
||||
from .tasks import XenforoTasks
|
||||
@@ -25,7 +27,7 @@ def activate_xenforo_forum(request):
|
||||
if result['response']['status_code'] == 200:
|
||||
XenforoUser.objects.update_or_create(user=request.user, defaults={'username': result['username']})
|
||||
logger.info("Updated user %s with XenForo credentials. Updating groups." % request.user)
|
||||
messages.success(request, 'Activated XenForo account.')
|
||||
messages.success(request, _('Activated XenForo account.'))
|
||||
credentials = {
|
||||
'username': result['username'],
|
||||
'password': result['password'],
|
||||
@@ -35,7 +37,7 @@ def activate_xenforo_forum(request):
|
||||
|
||||
else:
|
||||
logger.error("Unsuccessful attempt to activate xenforo for user %s" % request.user)
|
||||
messages.error(request, 'An error occurred while processing your XenForo account.')
|
||||
messages.error(request, _('An error occurred while processing your XenForo account.'))
|
||||
return redirect("services:services")
|
||||
|
||||
|
||||
@@ -45,9 +47,9 @@ def deactivate_xenforo_forum(request):
|
||||
logger.debug("deactivate_xenforo_forum called by user %s" % request.user)
|
||||
if XenforoTasks.delete_user(request.user):
|
||||
logger.info("Successfully deactivated XenForo for user %s" % request.user)
|
||||
messages.success(request, 'Deactivated XenForo account.')
|
||||
messages.success(request, _('Deactivated XenForo account.'))
|
||||
else:
|
||||
messages.error(request, 'An error occurred while processing your XenForo account.')
|
||||
messages.error(request, _('An error occurred while processing your XenForo account.'))
|
||||
return redirect("services:services")
|
||||
|
||||
|
||||
@@ -60,7 +62,7 @@ def reset_xenforo_password(request):
|
||||
# Based on XenAPI's response codes
|
||||
if result['response']['status_code'] == 200:
|
||||
logger.info("Successfully reset XenForo password for user %s" % request.user)
|
||||
messages.success(request, 'Reset XenForo account password.')
|
||||
messages.success(request, _('Reset XenForo account password.'))
|
||||
credentials = {
|
||||
'username': request.user.xenforo.username,
|
||||
'password': result['password'],
|
||||
@@ -68,7 +70,7 @@ def reset_xenforo_password(request):
|
||||
return render(request, 'services/service_credentials.html',
|
||||
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.')
|
||||
messages.error(request, _('An error occurred while processing your XenForo account.'))
|
||||
return redirect("services:services")
|
||||
|
||||
|
||||
@@ -86,10 +88,10 @@ def set_xenforo_password(request):
|
||||
result = XenForoManager.update_user_password(request.user.xenforo.username, password)
|
||||
if result['response']['status_code'] == 200:
|
||||
logger.info("Successfully reset XenForo password for user %s" % request.user)
|
||||
messages.success(request, 'Changed XenForo password.')
|
||||
messages.success(request, _('Changed XenForo password.'))
|
||||
else:
|
||||
logger.error("Failed to install custom XenForo password for user %s" % request.user)
|
||||
messages.error(request, 'An error occurred while processing your XenForo account.')
|
||||
messages.error(request, _('An error occurred while processing your XenForo account.'))
|
||||
return redirect('services:services')
|
||||
else:
|
||||
logger.debug("Request is not type POST - providing empty form.")
|
||||
|
||||
17
allianceauth/services/tests/test_models.py
Normal file
17
allianceauth/services/tests/test_models.py
Normal file
@@ -0,0 +1,17 @@
|
||||
from django.test import TestCase
|
||||
from allianceauth.tests.auth_utils import AuthUtils
|
||||
|
||||
from ..models import NameFormatConfig
|
||||
|
||||
|
||||
class TestNameFormatConfig(TestCase):
|
||||
|
||||
def test_str(self):
|
||||
obj = NameFormatConfig.objects.create(
|
||||
service_name='mumble',
|
||||
format='{{character_name}}'
|
||||
)
|
||||
obj.states.add(AuthUtils.get_member_state())
|
||||
obj.states.add(AuthUtils.get_guest_state())
|
||||
expected = 'mumble: Member, Guest'
|
||||
self.assertEqual(str(obj), expected)
|
||||
@@ -8,7 +8,7 @@ from django.contrib.humanize.templatetags.humanize import intcomma
|
||||
from django.http import JsonResponse, Http404
|
||||
from django.shortcuts import render, redirect, get_object_or_404
|
||||
from django.utils import timezone
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django.db.models import Sum
|
||||
from allianceauth.authentication.decorators import permissions_required
|
||||
from allianceauth.eveonline.providers import provider
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
[ZoneTransfer]
|
||||
ZoneId=3
|
||||
ReferrerUrl=https://github.com/ErikKalkoken/filterDropDown/blob/master/js/filterDropDown.min.js
|
||||
HostUrl=https://raw.githubusercontent.com/ErikKalkoken/filterDropDown/master/js/filterDropDown.min.js
|
||||
@@ -1,27 +1,45 @@
|
||||
from allianceauth.authentication.models import UserProfile, State, get_guest_state
|
||||
from allianceauth.authentication.signals import state_member_alliances_changed, state_member_characters_changed, \
|
||||
state_member_corporations_changed, state_saved
|
||||
from django.contrib.auth.models import User, Group
|
||||
from django.contrib.auth.models import User, Group, Permission
|
||||
from django.db.models.signals import m2m_changed, pre_save, post_save
|
||||
from django.test import TestCase
|
||||
from esi.models import Token
|
||||
from allianceauth.eveonline.models import EveCharacter
|
||||
|
||||
from allianceauth.services.signals import m2m_changed_group_permissions, m2m_changed_user_permissions, \
|
||||
m2m_changed_state_permissions
|
||||
from allianceauth.services.signals import m2m_changed_user_groups, disable_services_on_inactive
|
||||
from esi.models import Token
|
||||
|
||||
from allianceauth.authentication.models import (
|
||||
UserProfile, State, get_guest_state
|
||||
)
|
||||
from allianceauth.eveonline.models import EveCharacter
|
||||
from allianceauth.authentication.signals import (
|
||||
state_member_alliances_changed,
|
||||
state_member_characters_changed,
|
||||
state_member_corporations_changed,
|
||||
state_saved,
|
||||
reassess_on_profile_save,
|
||||
assign_state_on_active_change,
|
||||
check_state_on_character_update
|
||||
)
|
||||
from allianceauth.services.signals import (
|
||||
m2m_changed_group_permissions,
|
||||
m2m_changed_user_permissions,
|
||||
m2m_changed_state_permissions,
|
||||
m2m_changed_user_groups, disable_services_on_inactive
|
||||
)
|
||||
|
||||
|
||||
class AuthUtils:
|
||||
def __init__(self):
|
||||
pass
|
||||
"""Utilities for making it easier to create tests for Alliance Auth"""
|
||||
|
||||
@staticmethod
|
||||
def _create_user(username):
|
||||
def _create_user(username):
|
||||
return User.objects.create(username=username)
|
||||
|
||||
@classmethod
|
||||
def create_user(cls, username, disconnect_signals=False):
|
||||
"""create a new user
|
||||
|
||||
username: Name of the user
|
||||
|
||||
disconnect_signals: whether to run process without signals
|
||||
"""
|
||||
if disconnect_signals:
|
||||
cls.disconnect_signals()
|
||||
user = cls._create_user(username)
|
||||
@@ -95,6 +113,11 @@ class AuthUtils:
|
||||
m2m_changed.disconnect(state_member_characters_changed, sender=State.member_characters.through)
|
||||
m2m_changed.disconnect(state_member_alliances_changed, sender=State.member_alliances.through)
|
||||
post_save.disconnect(state_saved, sender=State)
|
||||
post_save.disconnect(reassess_on_profile_save, sender=UserProfile)
|
||||
pre_save.disconnect(assign_state_on_active_change, sender=User)
|
||||
post_save.disconnect(
|
||||
check_state_on_character_update, sender=EveCharacter
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def connect_signals(cls):
|
||||
@@ -107,6 +130,9 @@ class AuthUtils:
|
||||
m2m_changed.connect(state_member_characters_changed, sender=State.member_characters.through)
|
||||
m2m_changed.connect(state_member_alliances_changed, sender=State.member_alliances.through)
|
||||
post_save.connect(state_saved, sender=State)
|
||||
post_save.connect(reassess_on_profile_save, sender=UserProfile)
|
||||
pre_save.connect(assign_state_on_active_change, sender=User)
|
||||
post_save.connect(check_state_on_character_update, sender=EveCharacter)
|
||||
|
||||
@classmethod
|
||||
def add_main_character(cls, user, name, character_id, corp_id='', corp_name='', corp_ticker='', alliance_id='',
|
||||
@@ -122,6 +148,40 @@ class AuthUtils:
|
||||
)
|
||||
UserProfile.objects.update_or_create(user=user, defaults={'main_character': char})
|
||||
|
||||
@classmethod
|
||||
def add_main_character_2(
|
||||
cls,
|
||||
user,
|
||||
name,
|
||||
character_id,
|
||||
corp_id='',
|
||||
corp_name='',
|
||||
corp_ticker='',
|
||||
alliance_id='',
|
||||
alliance_name='',
|
||||
disconnect_signals=False
|
||||
):
|
||||
"""new version that works in all cases"""
|
||||
if disconnect_signals:
|
||||
cls.disconnect_signals()
|
||||
|
||||
char = EveCharacter.objects.create(
|
||||
character_id=character_id,
|
||||
character_name=name,
|
||||
corporation_id=corp_id,
|
||||
corporation_name=corp_name,
|
||||
corporation_ticker=corp_ticker,
|
||||
alliance_id=alliance_id,
|
||||
alliance_name=alliance_name,
|
||||
)
|
||||
user.profile.main_character = char
|
||||
user.profile.save()
|
||||
|
||||
if disconnect_signals:
|
||||
cls.connect_signals()
|
||||
|
||||
return char
|
||||
|
||||
@classmethod
|
||||
def add_permissions_to_groups(cls, perms, groups, disconnect_signals=True):
|
||||
if disconnect_signals:
|
||||
@@ -130,14 +190,67 @@ class AuthUtils:
|
||||
for group in groups:
|
||||
for perm in perms:
|
||||
group.permissions.add(perm)
|
||||
group = Group.objects.get(pk=group.pk) # reload permission cache
|
||||
|
||||
if disconnect_signals:
|
||||
cls.connect_signals()
|
||||
|
||||
@classmethod
|
||||
def add_permissions_to_state(cls, perms, states, disconnect_signals=True):
|
||||
return cls.add_permissions_to_groups(perms, states, disconnect_signals=disconnect_signals)
|
||||
return cls.add_permissions_to_groups(
|
||||
perms, states, disconnect_signals=disconnect_signals
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def add_permissions_to_user(cls, perms, user, disconnect_signals=True):
|
||||
"""add list of permissions to user
|
||||
|
||||
perms: list of Permission objects
|
||||
|
||||
user: user object
|
||||
|
||||
disconnect_signals: whether to run process without signals
|
||||
"""
|
||||
if disconnect_signals:
|
||||
cls.disconnect_signals()
|
||||
|
||||
for perm in perms:
|
||||
user.user_permissions.add(perm)
|
||||
|
||||
user = User.objects.get(pk=user.pk) # reload permission cache
|
||||
if disconnect_signals:
|
||||
cls.connect_signals()
|
||||
|
||||
@classmethod
|
||||
def add_permission_to_user_by_name(
|
||||
cls, perm, user, disconnect_signals=True
|
||||
):
|
||||
"""returns permission specified by qualified name
|
||||
|
||||
perm: Permission name as 'app_label.codename'
|
||||
|
||||
user: user object
|
||||
|
||||
disconnect_signals: whether to run process without signals
|
||||
"""
|
||||
p = cls.get_permission_by_name(perm)
|
||||
cls.add_permissions_to_user([p], user, disconnect_signals)
|
||||
|
||||
@staticmethod
|
||||
def get_permission_by_name(perm: str) -> Permission:
|
||||
"""returns permission specified by qualified name
|
||||
|
||||
perm: Permission name as 'app_label.codename'
|
||||
|
||||
Returns: Permission object or throws exception if not found
|
||||
"""
|
||||
perm_parts = perm.split('.')
|
||||
if len(perm_parts) != 2:
|
||||
raise ValueError('Invalid format for permission name')
|
||||
|
||||
return Permission.objects.get(
|
||||
content_type__app_label=perm_parts[0], codename=perm_parts[1]
|
||||
)
|
||||
|
||||
class BaseViewTestCase(TestCase):
|
||||
def setUp(self):
|
||||
|
||||
60
allianceauth/tests/test_auth_utils.py
Normal file
60
allianceauth/tests/test_auth_utils.py
Normal file
@@ -0,0 +1,60 @@
|
||||
from unittest import mock
|
||||
|
||||
from django.contrib.auth.models import User, Group, Permission
|
||||
from django.test import TestCase
|
||||
|
||||
from allianceauth.eveonline.models import (
|
||||
EveCorporationInfo, EveAllianceInfo, EveCharacter
|
||||
)
|
||||
|
||||
from .auth_utils import AuthUtils
|
||||
|
||||
|
||||
class TestAuthUtils(TestCase):
|
||||
|
||||
def test_can_create_user(self):
|
||||
user = AuthUtils.create_user('Bruce Wayne')
|
||||
self.assertTrue(User.objects.filter(username='Bruce Wayne').exists())
|
||||
|
||||
def test_can_add_main_character_2(self):
|
||||
user = AuthUtils.create_user('Bruce Wayne')
|
||||
character = AuthUtils.add_main_character_2(
|
||||
user,
|
||||
name='Bruce Wayne',
|
||||
character_id=1001,
|
||||
corp_id=2001,
|
||||
corp_name='Wayne Technologies',
|
||||
corp_ticker='WYT',
|
||||
alliance_id=3001,
|
||||
alliance_name='Wayne Enterprises'
|
||||
)
|
||||
expected = character
|
||||
self.assertEqual(user.profile.main_character, expected)
|
||||
|
||||
def test_can_add_permission_to_group(self):
|
||||
group = Group.objects.create(name='Dummy Group')
|
||||
p = AuthUtils.get_permission_by_name('auth.group_management')
|
||||
AuthUtils.add_permissions_to_groups([p], [group])
|
||||
self.assertTrue(group.permissions.filter(pk=p.pk).exists())
|
||||
|
||||
def test_can_add_permission_to_user_by_name(self):
|
||||
user = AuthUtils.create_user('Bruce Wayne')
|
||||
AuthUtils.add_permission_to_user_by_name(
|
||||
'auth.timer_management', user
|
||||
)
|
||||
self.assertTrue(user.has_perm('auth.timer_management'))
|
||||
|
||||
|
||||
class TestGetPermissionByName(TestCase):
|
||||
|
||||
def test_can_get_permission_by_name(self):
|
||||
expected = Permission.objects.get(
|
||||
content_type__app_label='auth', codename='timer_management'
|
||||
)
|
||||
self.assertEqual(
|
||||
AuthUtils.get_permission_by_name('auth.timer_management'), expected
|
||||
)
|
||||
|
||||
def test_raises_exception_on_invalid_permission_format(self):
|
||||
with self.assertRaises(ValueError):
|
||||
AuthUtils.get_permission_by_name('timer_management')
|
||||
@@ -1,4 +0,0 @@
|
||||
[ZoneTransfer]
|
||||
ZoneId=3
|
||||
ReferrerUrl=https://i.imgur.com/6dXZ5BH.png
|
||||
HostUrl=https://i.imgur.com/6dXZ5BH.png
|
||||
@@ -1,4 +0,0 @@
|
||||
[ZoneTransfer]
|
||||
ZoneId=3
|
||||
ReferrerUrl=https://i.imgur.com/Er1g02v.png
|
||||
HostUrl=https://i.imgur.com/Er1g02v.png
|
||||
@@ -9,4 +9,5 @@ This section describes how to extend **Alliance Auth** with custom apps and serv
|
||||
integrating-services
|
||||
menu-hooks
|
||||
url-hooks
|
||||
logging
|
||||
```
|
||||
|
||||
15
docs/development/custom/logging.md
Normal file
15
docs/development/custom/logging.md
Normal file
@@ -0,0 +1,15 @@
|
||||
# Logging from Custom Apps
|
||||
Alliance Auth provides a logger for use with custom apps to make everyone's life a little easier.
|
||||
|
||||
## Using the Extensions Logger
|
||||
AllianceAuth provides a helper function to get the logger for the current module to reduce the amount of
|
||||
code you need to write.
|
||||
|
||||
```python
|
||||
from allianceauth.services.hooks import get_extension_logger
|
||||
|
||||
logger = get_extension_logger(__name__)
|
||||
```
|
||||
|
||||
This works by creating a child logger of the extension logger which propagates all log entries
|
||||
to the parent (extensions) logger.
|
||||
@@ -1,6 +1,6 @@
|
||||
# Overview
|
||||
|
||||
**Alliance Auth** (AA) is a web application that helps Eve Online organizations efficiently manage access to external services and web apps.
|
||||
**Alliance Auth** (AA) is a web site that helps Eve Online organizations efficiently manage access to applications and external services.
|
||||
|
||||
It has the following key features:
|
||||
|
||||
@@ -14,6 +14,4 @@ It has the following key features:
|
||||
|
||||
- Can be easily extended with additional services and apps. Many are provided by the [community](/features/community/index).
|
||||
|
||||
Here is an example how the main page of the web site looks:
|
||||
|
||||

|
||||
- Chinese, English, German and Spanish localization
|
||||
|
||||
@@ -3,7 +3,9 @@
|
||||
|
||||
Welcome to the official documentation for **Alliance Auth**!
|
||||
|
||||
**Alliance Auth** is a web application that helps Eve Online organizations efficiently manage access to external services and web apps.
|
||||

|
||||
|
||||
**Alliance Auth** is a web site that helps Eve Online organizations efficiently manage access to applications and external services.
|
||||
|
||||
```eval_rst
|
||||
.. toctree::
|
||||
|
||||
@@ -9,7 +9,7 @@ This document describes how to install **Alliance Auth** from scratch.
|
||||
|
||||
```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 [Features](/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 **Features** for details.
|
||||
```
|
||||
|
||||
## Dependencies
|
||||
@@ -44,7 +44,14 @@ yum install python36u python36u-devel python36u-setuptools python36u-pip
|
||||
|
||||
### Database
|
||||
|
||||
It's recommended to use a database service instead of SQLite. Many options are available, but this guide will use MariaDB. Note that Alliance Auth requires Maria DB 10.2.x or higher.
|
||||
It's recommended to use a database service instead of SQLite. Many options are available, but this guide will use MariaDB.
|
||||
|
||||
```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!
|
||||
|
||||
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:
|
||||
|
||||
@@ -188,6 +195,12 @@ You can install **Alliance Auth** with the following command. This will install
|
||||
pip install allianceauth
|
||||
```
|
||||
|
||||
You should also install Gunicorn now unless you want to use another WSGI server (see [Gunicorn](#gunicorn) for details):
|
||||
|
||||
```bash
|
||||
pip install gunicorn
|
||||
```
|
||||
|
||||
Now you need to create the application that will run the **Alliance Auth** install. Ensure you are in the allianceserver home directory by issuing:
|
||||
|
||||
```bash
|
||||
@@ -237,16 +250,15 @@ To run the **Alliance Auth** website a [WSGI Server](https://www.fullstackpython
|
||||
|
||||
The default configuration is good enough for most installations. Additional information is available in the [gunicorn](gunicorn.md) doc.
|
||||
|
||||
Use this command to install Gunicorn:
|
||||
|
||||
```bash
|
||||
pip install gunicorn
|
||||
```
|
||||
|
||||
### Supervisor
|
||||
|
||||
[Supervisor](http://supervisord.org/) is a process watchdog service: it makes sure other processes are started automatically and kept running. It can be used to automatically start the WSGI server and Celery workers for background tasks. Installation varies by OS:
|
||||
|
||||
```eval_rst
|
||||
.. note::
|
||||
Many package managers will install Supervisor 3 by default, which requires Python 2.
|
||||
```
|
||||
|
||||
Ubuntu:
|
||||
|
||||
```bash
|
||||
|
||||
@@ -20,7 +20,7 @@ Check out the full [Gunicorn docs](http://docs.gunicorn.org/en/latest/index.html
|
||||
|
||||
Install Gunicorn using pip, `pip install gunicorn`.
|
||||
|
||||
In your `myauth` base directory, try running `gunicorn --bind 0.0.0.0:8000 myauth.wsgi`. You should be able to browse to http://yourserver:8000 and see your Alliance Auth installation running. Images and styling will be missing, but don't worry, your web server will provide them.
|
||||
In your `myauth` base directory, try running `gunicorn --bind 0.0.0.0:8000 myauth.wsgi`. You should be able to browse to `http://yourserver:8000` and see your Alliance Auth installation running. Images and styling will be missing, but don't worry, your web server will provide them.
|
||||
|
||||
Once you validate its running, you can kill the process with Ctrl+C and continue.
|
||||
|
||||
@@ -30,28 +30,30 @@ You should use [Supervisor](allianceauth.md#supervisor) to keep all of Alliance
|
||||
|
||||
### Sample Supervisor config
|
||||
|
||||
You'll want to edit `/etc/supervisor/conf.d/myauth_gunicorn.conf` (or whatever you want to call the config file)
|
||||
You'll want to edit `/etc/supervisor/conf.d/myauth.conf` (or whatever you want to call the config file)
|
||||
|
||||
```text
|
||||
[program:myauth-gunicorn]
|
||||
[program:gunicorn]
|
||||
user = allianceserver
|
||||
directory=/home/allianceserver/myauth/
|
||||
command=gunicorn myauth.wsgi --workers=3 --timeout 120
|
||||
command=/home/allianceserver/venv/auth/bin/gunicorn myauth.wsgi --workers=3 --timeout 120
|
||||
stdout_logfile=/home/allianceserver/myauth/log/gunicorn.log
|
||||
stderr_logfile=/home/allianceserver/myauth/log/gunicorn.log
|
||||
autostart=true
|
||||
autorestart=true
|
||||
stopsignal=INT
|
||||
```
|
||||
|
||||
- `[program:myauth-gunicorn]` - Change myauth-gunicorn to whatever you wish to call your process in Supervisor.
|
||||
- `[program:gunicorn]` - Change `gunicorn` to whatever you wish to call your process in Supervisor.
|
||||
- `user = allianceserver` - Change to whatever user you wish Gunicorn to run as. You could even set this as allianceserver if you wished. I'll leave the question security of that up to you.
|
||||
- `directory=/home/allianceserver/myauth/` - Needs to be the path to your Alliance Auth project.
|
||||
- `command=gunicorn myauth.wsgi --workers=3 --timeout 120` - Running Gunicorn and the options to launch with. This is where you have some decisions to make, we'll continue below.
|
||||
- `command=/home/allianceserver/venv/auth/bin/gunicorn myauth.wsgi --workers=3 --timeout 120` - Running Gunicorn and the options to launch with. This is where you have some decisions to make, we'll continue below.
|
||||
|
||||
#### Gunicorn Arguments
|
||||
|
||||
See the [Commonly Used Arguments](http://docs.gunicorn.org/en/latest/run.html#commonly-used-arguments) or [Full list of settings](http://docs.gunicorn.org/en/stable/settings.html) for more information.
|
||||
|
||||
##### Where to bind Gunicorn to?
|
||||
##### Where to bind Gunicorn to
|
||||
|
||||
What address are you going to use to reference it? By default, without a bind parameter, Gunicorn will bind to `127.0.0.1:8000`. This might be fine for your application. If it clashes with another application running on that port you will need to change it. I would suggest using UNIX sockets too, if you can.
|
||||
|
||||
@@ -63,9 +65,9 @@ Whatever you decide to use, remember it because we'll need it when configuring y
|
||||
|
||||
##### Number of workers
|
||||
|
||||
By default Gunicorn will spawn only one worker. The number you set this to will depend on your own server environment, how many visitors you have etc. Gunicorn suggests between 2-4 workers per core. Really you could probably get away with 2-4 in total for most installs.
|
||||
By default Gunicorn will spawn only one worker. The number you set this to will depend on your own server environment, how many visitors you have etc. Gunicorn suggests `(2 x $num_cores) + 1` for the number of workers. So for example if you have 2 cores you want 2 x 2 + 1 = 5 workers. See [here](https://docs.gunicorn.org/en/stable/design.html#how-many-workers) for the official discussion on this topic.
|
||||
|
||||
Change it by adding `--workers=2` to the command.
|
||||
Change it by adding `--workers=5` to the command.
|
||||
|
||||
##### Running with a virtual environment
|
||||
|
||||
@@ -73,9 +75,11 @@ If you're running with a virtual environment, you'll need to add the path to the
|
||||
|
||||
e.g. `command=/path/to/venv/bin/gunicorn myauth.wsgi`
|
||||
|
||||
The example config is using the myauth venv from the main installation guide: `command=/home/allianceserver/venv/auth/bin/gunicorn myauth.wsgi`
|
||||
|
||||
### Starting via Supervisor
|
||||
|
||||
Once you have your configuration all sorted, you will need to reload your supervisor config `service supervisor reload` and then you can start the Gunicorn server via `supervisorctl start aauth-gunicorn` (or whatever you renamed it to). You should see something like the following `aauth-gunicorn: started`. If you get some other message, you'll need to consult the Supervisor log files, usually found in `/var/log/supervisor/`.
|
||||
Once you have your configuration all sorted, you will need to reload your supervisor config `service supervisor reload` and then you can start the Gunicorn server via `supervisorctl start myauth:gunicorn` (or whatever you renamed it to). You should see something like the following `myauth-gunicorn: started`. If you get some other message, you'll need to consult the Supervisor log files, usually found in `/var/log/supervisor/`.
|
||||
|
||||
## Configuring your webserver
|
||||
|
||||
@@ -85,4 +89,4 @@ Any web server capable of proxy passing should be able to sit in front of Gunico
|
||||
|
||||
In the past when you made changes you restarted the entire Apache server. This is no longer required. When you update or make configuration changes that ask you to restart Apache, instead you can just restart Gunicorn:
|
||||
|
||||
`supervisorctl restart myauth-gunicorn`, or the service name you chose for it.
|
||||
`supervisorctl restart gunicorn`, or the service name you chose for it.
|
||||
|
||||
@@ -12,5 +12,5 @@ In addition to main guide for installation Alliance Auth you also find guides fo
|
||||
nginx
|
||||
apache
|
||||
gunicorn
|
||||
upgradev1
|
||||
upgrade_python
|
||||
```
|
||||
|
||||
270
docs/installation/upgrade_python.md
Normal file
270
docs/installation/upgrade_python.md
Normal file
@@ -0,0 +1,270 @@
|
||||
# Upgrading Python 3
|
||||
|
||||
This guide describes how to upgrade an existing Alliance Auth (AA) installation to a newer Python 3 version.
|
||||
|
||||
```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.
|
||||
```
|
||||
|
||||
```eval_rst
|
||||
.. note::
|
||||
This guide will upgrade the software components only but not change any data or configuration.
|
||||
```
|
||||
|
||||
## Install a new Python version
|
||||
|
||||
To run AA with a newer Python 3 version than your system's default you need to install it first. Technically it would be possible to upgrade your system's default Python 3, but since many of your system's tools have been tested to work with that specific version we would not recommend it. Instead we recommend to install an additional Python 3 version alongside your default version and use that for AA.
|
||||
|
||||
```eval_rst
|
||||
.. note::
|
||||
For stability and performance we currently recommend to run AA with Python 3.7. Since at the time of writing Python 3.7 was not available for CentOS through yum install this guide will upgrade to Python 3.6. For Ubuntu one can just replace "3.6" with "3.7" in the installation commands to get Python 3.7.
|
||||
```
|
||||
|
||||
To install other Python versions than come with your distro you need to add a new installation repository. Then you can install the specific Python 3 to your system.
|
||||
|
||||
Ubuntu:
|
||||
|
||||
```bash
|
||||
add-apt-repository ppa:deadsnakes/ppa
|
||||
```
|
||||
|
||||
```bash
|
||||
apt-get update
|
||||
```
|
||||
|
||||
```bash
|
||||
apt-get install python3.6 python3.6-dev python3.6-venv
|
||||
```
|
||||
|
||||
CentOS:
|
||||
|
||||
```bash
|
||||
yum install https://centos7.iuscommunity.org/ius-release.rpm
|
||||
```
|
||||
|
||||
```bash
|
||||
yum update
|
||||
```
|
||||
|
||||
```bash
|
||||
yum install python36u python36u-pip python36u-devel
|
||||
```
|
||||
|
||||
## Preparing your venv
|
||||
|
||||
Before updating your venv it is important to make sure that your current installation is stable. Otherwise your new venv might not be consistent with your data, which might create problems.
|
||||
|
||||
Start by navigating to your main project folder (the one that has `manage.py` in it). If you followed the default installation the path is: `/home/allianceserver/myauth`
|
||||
|
||||
Activate your venv:
|
||||
|
||||
```bash
|
||||
source /home/allianceserver/venv/auth/bin/activate
|
||||
```
|
||||
|
||||
### Upgrade AA
|
||||
|
||||
Make sure to upgrade AA to the newest version:
|
||||
|
||||
```bash
|
||||
pip install -U allianceauth
|
||||
```
|
||||
|
||||
Run migrations and collectstatic.
|
||||
|
||||
```bash
|
||||
python manage.py migrate
|
||||
```
|
||||
|
||||
```bash
|
||||
python manage.py collectstatic
|
||||
```
|
||||
|
||||
Restart your AA supervisor:
|
||||
|
||||
```bash
|
||||
supervisorctl restart myauth:
|
||||
```
|
||||
|
||||
### Upgrade your apps
|
||||
|
||||
You also need to upgrade all additional apps to their newest version that you have installed. And you need to make sure that you can reinstall all your apps later, e.g. you know from which repo they came. We recommend to make a list of all your apps, so you can just go through them later when you rebuild your venv.
|
||||
|
||||
If you unsure which apps you have installed from repos check `INSTALLED_APPS` in your settings. Alternatively run this command to get a list all apps in your venv.
|
||||
|
||||
```bash
|
||||
pip list
|
||||
```
|
||||
|
||||
Some AA installations might still be running an older version of django_celery_beat. We would recommend to upgrade to the current version before doing the Python update:
|
||||
|
||||
```bash
|
||||
pip install -U django_celery_beat
|
||||
```
|
||||
|
||||
```bash
|
||||
python manage.py migrate
|
||||
```
|
||||
|
||||
Make sure to run migrations and collect static files for all upgraded apps.
|
||||
|
||||
### Restart and final check
|
||||
|
||||
Do a final restart of your AA supervisors and make sure your installation is still running normally.
|
||||
|
||||
For a final check that they are no issues - e.g. any outstanding migrations - run this command:
|
||||
|
||||
```bash
|
||||
python manage.py check
|
||||
```
|
||||
|
||||
If you get the following result you are good to go. Otherwise make sure to fix any issues first before proceeding.
|
||||
|
||||
```bash
|
||||
System check identified no issues (0 silenced).
|
||||
```
|
||||
|
||||
## Backup current venv
|
||||
|
||||
Make sure you are in your venv!
|
||||
|
||||
First we create a list of all installed packages in your venv. You can use this list later as reference to see what packages should be installed.
|
||||
|
||||
```bash
|
||||
pip freeze > requirements.txt
|
||||
```
|
||||
|
||||
At this point we recommend creating a list of the additional packages that you need to manually reinstall later on top of AA:
|
||||
|
||||
- Community AA apps (e.g. aa-structures)
|
||||
- Additional tools you are using (e.g. flower, django-extensions)
|
||||
|
||||
```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.
|
||||
```
|
||||
|
||||
```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.
|
||||
```
|
||||
|
||||
Leave the venv and shutdown all AA services:
|
||||
|
||||
```bash
|
||||
deactivate
|
||||
```
|
||||
|
||||
```bash
|
||||
supervisorctl stop myauth:
|
||||
```
|
||||
|
||||
Rename and keep your old venv so we have a fallback in case of some unforeseeable issues:
|
||||
|
||||
```bash
|
||||
mv /home/allianceserver/venv/auth /home/allianceserver/venv/auth_old
|
||||
```
|
||||
|
||||
## Create your new venv
|
||||
|
||||
Now let's create our new venv with Python 3.6 and activate it:
|
||||
|
||||
```bash
|
||||
python3.6 -m venv /home/allianceserver/venv/auth
|
||||
```
|
||||
|
||||
```bash
|
||||
source /home/allianceserver/venv/auth/bin/activate
|
||||
```
|
||||
|
||||
## Reinstall packages
|
||||
|
||||
Now we need to reinstall all packages into your new venv.
|
||||
|
||||
### Install basic packages
|
||||
|
||||
```bash
|
||||
pip install --upgrade pip
|
||||
```
|
||||
|
||||
```bash
|
||||
pip install --upgrade setuptools
|
||||
```
|
||||
|
||||
```bash
|
||||
pip install wheel
|
||||
```
|
||||
|
||||
### Installing AA & Gunicorn
|
||||
|
||||
```bash
|
||||
pip install allianceauth
|
||||
```
|
||||
|
||||
```bash
|
||||
pip install gunicorn
|
||||
```
|
||||
|
||||
### Install all other packages
|
||||
|
||||
Last, but not least you need to reinstall all other packages, e.g. for AA community apps or additional tools.
|
||||
|
||||
Use the list of packages you created earlier as a checklist. Alternatively you use the `requirements.txt` file we created earlier to see what you need. During the installation process you can run `pip list` to see what you already got installed.
|
||||
|
||||
To check whether you are missing any apps you can also run the check command:
|
||||
|
||||
```bash
|
||||
python manage.py check
|
||||
```
|
||||
|
||||
Note: In case you forget to install an app you will get this error
|
||||
|
||||
```bash
|
||||
ModuleNotFoundError: No module named 'xyz'
|
||||
```
|
||||
|
||||
Note that you should not need to run any migrations unless you forgot to upgrade one of your existing apps or you got the newer version of an app through a dependency. In that case you just migrations normally.
|
||||
|
||||
## Restart
|
||||
|
||||
After you have completed installing all packages just start your AA supervisor again.
|
||||
|
||||
```bash
|
||||
supervisorctl start myauth:
|
||||
```
|
||||
|
||||
We recommend to keep your old venv copy for a couple of days so you have a fallback just in case. After that you should be fine to remove it.
|
||||
|
||||
## Fallback
|
||||
|
||||
In case you run into any major issue you can always switch back to your initial venv.
|
||||
|
||||
Before you start double-check that you still have your old venv for auth:
|
||||
|
||||
```bash
|
||||
ls /home/allianceserver/venv/auth /home/allianceserver/venv
|
||||
```
|
||||
|
||||
If the output shows these two folders you should be safe to proceed:
|
||||
|
||||
- `auth`
|
||||
- `auth_old`
|
||||
|
||||
Run these commands to remove your current venv and switch back to the old venv for auth:
|
||||
|
||||
```bash
|
||||
supervisorctl stop myauth:
|
||||
```
|
||||
|
||||
```bash
|
||||
rm -rf /home/allianceserver/venv/auth
|
||||
```
|
||||
|
||||
```bash
|
||||
mv /home/allianceserver/venv/auth_old /home/allianceserver/venv/auth
|
||||
```
|
||||
|
||||
```bash
|
||||
supervisorctl start myauth:
|
||||
```
|
||||
@@ -1,87 +0,0 @@
|
||||
# Upgrading from AA v1.15
|
||||
|
||||
It's possible to preserve a v1 install's database and migrate it to v2. This will retain all service accounts, user accounts with their main character, but will purge API keys and alts.
|
||||
|
||||
## Preparing to Upgrade
|
||||
|
||||
Ensure your auth install is at least version 1.15 - it's preferred to be on v1.15.8 but any v1.15.x should work. If not, update following normal procedures and ensure you run migrations.
|
||||
|
||||
If you will not be using any apps (or they have been removed in v2) clear their database tables before beginning the v2 install procedure. From within your v1 install, `python manage.py migrate APPNAME zero`, replacing `APPNAME` with the appropriate name.
|
||||
|
||||
It's strongly encouraged to perform the upgrade with a **copy** of the original v1 database. If something goes wrong this allows you to roll back and try again. This can be achieved with:
|
||||
|
||||
mysqldump -u root -p v1_database_name_here | mysql -u root -p v2_database_name_here
|
||||
|
||||
Note this command will prompt you for the root password twice.
|
||||
|
||||
Alliance Auth v2 requires Python 3.4 or newer. If this is not available on your system be sure to install the [dependencies listed.](allianceauth.md#python)
|
||||
|
||||
## Installation
|
||||
|
||||
Follow the [normal install procedures for Alliance Auth v2](allianceauth.md). If you're coming from v1 you likely already have the user account and dependencies.
|
||||
|
||||
When configuring settings, ensure to enter the database information relating to the copy you made of the v1 database, but **do not run migrations**. See below before continuing.
|
||||
|
||||
Do not start Celery yet.
|
||||
|
||||
## Migration
|
||||
|
||||
During the upgrade process a migration is run which ports data to the new system. Its behaviour can be configured through some optional settings.
|
||||
|
||||
### User Accounts
|
||||
|
||||
A database migration is included to port users to the new SSO-based login system. It will automatically assign states and main characters.
|
||||
|
||||
Password for non-staff accounts are destroyed so they cannot be used to log in - only SSO is available for regular members. Staff can login using username and password through the admin site or by SSO.
|
||||
|
||||
### EVE Characters
|
||||
|
||||
Character ownership is now tracked by periodically validating a refreshable SSO token. When migrating from v1 not all users may have such a refreshable token: to allow these users to retain their existing user account their main character is set to the one present in v1, bypassing this validation mechanism.
|
||||
|
||||
It is essential to get your users to log in via SSO soon after migration to ensure their accounts are managed properly. Any user who does not log in will not lose their main character under any circumstance, even character sale. During a sale characters are transferred to an NPC corp - get celery tasks running within 24 hours of migration so that during a sale the user loses their state (and hence permissions). This can be an issue if you've granted service access permissions to a user or their groups: it's strongly encouraged to grant service access by state from now on.
|
||||
|
||||
Because character ownership is tracked separately of main character it is not possible to preserve alts unless a refreshable SSO token is present for them.
|
||||
|
||||
### Members and Blues
|
||||
|
||||
The new [state system](../../features/core/states.md) allows configuring dynamic membership states through the admin page. Unfortunately if you make a change after migrating it will immediately assess user states and see that no one should be a member. You can add additional settings to your auth project's settings file to generate the member and blue states as you have them defined in v1:
|
||||
|
||||
- `ALLIANCE_IDS = []` a list of member alliance IDs
|
||||
- `CORP_IDS = []` a list of member corporation IDs
|
||||
- `BLUE_ALLIANCE_IDS = []` a list of blue alliance IDs
|
||||
- `BLUE_CORP_IDS = []` a list of blue corporation IDs
|
||||
|
||||
Put comma-separated IDs into the brackets and the migration will create states with the members and blues you had before. This will prevent unexpected state purging when you edit states via the admin site.
|
||||
|
||||
### Default Groups
|
||||
|
||||
If you used member/blue group names other than the standard "Member" and "Blue" you can enter settings to have the member/blue states created through this migration take these names.
|
||||
|
||||
- `DEFAULT_AUTH_GROUP = ""` the desired name of the "Member" state
|
||||
- `DEFAULT_BLUE_GROUP = ""` the desired name of the "Blue" state
|
||||
|
||||
Any permissions assigned to these groups will be copied to the state replacing them. Because these groups are no longer managed they pose a security risk and so are deleted at the end of the migration automatically.
|
||||
|
||||
### Run Migrations
|
||||
|
||||
Once you've configured any optional settings it is now safe to run the included migrations.
|
||||
|
||||
## Validating Upgrade
|
||||
|
||||
Before starting the Celery workers it's a good idea to validate the states were created and assigned correctly. Any mistakes now will trigger deletion of service accounts: if Celery workers aren't running these tasks aren't yet processed. States can be checked through the admin site.
|
||||
|
||||
The site (and not Celery) can be started with `supervisorctl start myauth:gunicorn`. Then navigate to the admin site and log in with your v1 username and password. States and User Profiles can be found under the Authentication app.
|
||||
|
||||
Once you have confirmed states are correctly configured (or adjusted them as needed) clear the Celery task queue: from within your auth project folder, `celery -A myauth purge`
|
||||
|
||||
It should now be safe to bring workers online (`supervisorctl start myauth:`) and invite users to use the site.
|
||||
|
||||
## Securing User Accounts
|
||||
|
||||
After migration users will have main characters without a method to check for character sales. After a brief period to allow your users to log in (and provide a refreshable token to use), it's a good idea to clear main characters of users who haven't yet logged in. This can be achieved with an included command: `python manage.py checkmains`
|
||||
|
||||
A similar process can be used to ensure users who may have lost service permissions during the migration do not have active service accounts. This is done using `python manage.py validate_service_accounts`.
|
||||
|
||||
## Help
|
||||
|
||||
If something goes wrong during the migration reach out for help on [Gitter](https://gitter.im/R4stl1n/allianceauth) or open an [issue](https://gitlab.com/allianceauth/allianceauth/issues).
|
||||
@@ -11,6 +11,15 @@ app = Celery('devauth')
|
||||
# Using a string here means the worker don't have to serialize
|
||||
# the configuration object to child processes.
|
||||
app.config_from_object('django.conf:settings')
|
||||
|
||||
# setup priorities ( 0 Highest, 9 Lowest )
|
||||
app.conf.broker_transport_options = {
|
||||
'priority_steps': list(range(10)), # setup que to have 10 steps
|
||||
'queue_order_strategy': 'priority', # setup que to use prio sorting
|
||||
}
|
||||
app.conf.task_default_priority = 5 # anything called with the task.delay() will be given normal priority (5)
|
||||
app.conf.worker_prefetch_multiplier = 1 # only prefetch single tasks at a time on the workers so that prio tasks happen
|
||||
|
||||
app.conf.ONCE = {
|
||||
'backend': 'allianceauth.services.tasks.DjangoBackend',
|
||||
'settings': {}
|
||||
|
||||
Reference in New Issue
Block a user