mirror of
https://gitlab.com/allianceauth/allianceauth.git
synced 2026-02-04 06:06:19 +01:00
Compare commits
29 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7f8ca4fad2 | ||
|
|
4bb9a7155d | ||
|
|
2ac79954f3 | ||
|
|
585e1f47f3 | ||
|
|
a33c474b35 | ||
|
|
61c3d8964b | ||
|
|
1c927c5820 | ||
|
|
ff0fa0329d | ||
|
|
e51ea439ca | ||
|
|
8f39b50b6d | ||
|
|
95b309c358 | ||
|
|
cf3df3b715 | ||
|
|
d815028c4d | ||
|
|
ac5570abe2 | ||
|
|
84ad571aa4 | ||
|
|
38e7705ae7 | ||
|
|
0b6af014fa | ||
|
|
2401f2299d | ||
|
|
919768c8bb | ||
|
|
24db21463b | ||
|
|
1e029af83a | ||
|
|
53dd8ce606 | ||
|
|
0f4003366d | ||
|
|
2b31be789d | ||
|
|
bf1b4bb549 | ||
|
|
dd42b807f0 | ||
|
|
542fbafd98 | ||
|
|
37b9f5c882 | ||
|
|
5bde9a6952 |
@@ -5,16 +5,16 @@
|
||||
- merge_requests
|
||||
|
||||
stages:
|
||||
- pre-commit
|
||||
- gitlab
|
||||
- test
|
||||
- deploy
|
||||
- docker
|
||||
- pre-commit
|
||||
- gitlab
|
||||
- test
|
||||
- deploy
|
||||
- docker
|
||||
|
||||
include:
|
||||
- template: Dependency-Scanning.gitlab-ci.yml
|
||||
- template: Security/SAST.gitlab-ci.yml
|
||||
- template: Security/Secret-Detection.gitlab-ci.yml
|
||||
- template: Dependency-Scanning.gitlab-ci.yml
|
||||
- template: Security/SAST.gitlab-ci.yml
|
||||
- template: Security/Secret-Detection.gitlab-ci.yml
|
||||
|
||||
before_script:
|
||||
- apt-get update && apt-get install redis-server -y
|
||||
@@ -42,16 +42,20 @@ sast:
|
||||
dependency_scanning:
|
||||
stage: gitlab
|
||||
before_script:
|
||||
- apt-get update && apt-get install redis-server libmariadb-dev -y
|
||||
- redis-server --daemonize yes
|
||||
- python -V
|
||||
- pip install wheel tox
|
||||
- apt-get update && apt-get install redis-server libmariadb-dev -y
|
||||
- redis-server --daemonize yes
|
||||
- python -V
|
||||
- pip install wheel tox
|
||||
|
||||
secret_detection:
|
||||
stage: gitlab
|
||||
before_script: []
|
||||
|
||||
test-3.8-core:
|
||||
<<: *only-default
|
||||
image: python:3.8-bullseye
|
||||
script:
|
||||
- tox -e py38-core
|
||||
- tox -e py38-core
|
||||
artifacts:
|
||||
when: always
|
||||
reports:
|
||||
@@ -63,7 +67,7 @@ test-3.9-core:
|
||||
<<: *only-default
|
||||
image: python:3.9-bullseye
|
||||
script:
|
||||
- tox -e py39-core
|
||||
- tox -e py39-core
|
||||
artifacts:
|
||||
when: always
|
||||
reports:
|
||||
@@ -75,7 +79,7 @@ test-3.10-core:
|
||||
<<: *only-default
|
||||
image: python:3.10-bullseye
|
||||
script:
|
||||
- tox -e py310-core
|
||||
- tox -e py310-core
|
||||
artifacts:
|
||||
when: always
|
||||
reports:
|
||||
@@ -87,7 +91,7 @@ test-3.11-core:
|
||||
<<: *only-default
|
||||
image: python:3.11-rc-bullseye
|
||||
script:
|
||||
- tox -e py311-core
|
||||
- tox -e py311-core
|
||||
artifacts:
|
||||
when: always
|
||||
reports:
|
||||
@@ -100,7 +104,7 @@ test-3.8-all:
|
||||
<<: *only-default
|
||||
image: python:3.8-bullseye
|
||||
script:
|
||||
- tox -e py38-all
|
||||
- tox -e py38-all
|
||||
artifacts:
|
||||
when: always
|
||||
reports:
|
||||
@@ -112,7 +116,7 @@ test-3.9-all:
|
||||
<<: *only-default
|
||||
image: python:3.9-bullseye
|
||||
script:
|
||||
- tox -e py39-all
|
||||
- tox -e py39-all
|
||||
artifacts:
|
||||
when: always
|
||||
reports:
|
||||
@@ -124,7 +128,7 @@ test-3.10-all:
|
||||
<<: *only-default
|
||||
image: python:3.10-bullseye
|
||||
script:
|
||||
- tox -e py310-all
|
||||
- tox -e py310-all
|
||||
artifacts:
|
||||
when: always
|
||||
reports:
|
||||
@@ -136,7 +140,7 @@ test-3.11-all:
|
||||
<<: *only-default
|
||||
image: python:3.11-rc-bullseye
|
||||
script:
|
||||
- tox -e py311-all
|
||||
- tox -e py311-all
|
||||
artifacts:
|
||||
when: always
|
||||
reports:
|
||||
@@ -145,6 +149,31 @@ test-3.11-all:
|
||||
path: coverage.xml
|
||||
allow_failure: true
|
||||
|
||||
build-test:
|
||||
stage: test
|
||||
image: python:3.10-bullseye
|
||||
|
||||
before_script:
|
||||
- python -m pip install --upgrade pip
|
||||
- python -m pip install --upgrade build
|
||||
- python -m pip install --upgrade setuptools wheel
|
||||
|
||||
script:
|
||||
- python -m build
|
||||
|
||||
artifacts:
|
||||
when: always
|
||||
name: "$CI_JOB_NAME-$CI_COMMIT_REF_SLUG"
|
||||
paths:
|
||||
- dist/*
|
||||
expire_in: 1 year
|
||||
|
||||
test-docs:
|
||||
<<: *only-default
|
||||
image: python:3.10-bullseye
|
||||
script:
|
||||
- tox -e docs
|
||||
|
||||
deploy_production:
|
||||
stage: deploy
|
||||
image: python:3.10-bullseye
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
repos:
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: v4.1.0
|
||||
rev: v4.3.0
|
||||
hooks:
|
||||
- id: check-case-conflict
|
||||
- id: check-json
|
||||
@@ -28,12 +28,12 @@ repos:
|
||||
exclude: ^(LICENSE|allianceauth\/static\/css\/themes\/bootstrap-locals.less|allianceauth\/eveonline\/swagger.json|(.*.po)|(.*.mo))
|
||||
|
||||
- repo: https://github.com/asottile/pyupgrade
|
||||
rev: v2.31.0
|
||||
rev: v2.34.0
|
||||
hooks:
|
||||
- id: pyupgrade
|
||||
args: [ --py38-plus ]
|
||||
|
||||
- repo: https://github.com/asottile/setup-cfg-fmt
|
||||
rev: v1.20.0
|
||||
rev: v1.20.1
|
||||
hooks:
|
||||
- id: setup-cfg-fmt
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# This will make sure the app is always imported when
|
||||
# Django starts so that shared_task will use this app.
|
||||
|
||||
__version__ = '3.0.0a5'
|
||||
__version__ = '3.0.0b1'
|
||||
__title__ = 'Alliance Auth'
|
||||
__url__ = 'https://gitlab.com/allianceauth/allianceauth'
|
||||
NAME = f'{__title__} v{__version__}'
|
||||
|
||||
@@ -1,27 +1,62 @@
|
||||
import datetime as dt
|
||||
from typing import Optional, List
|
||||
import logging
|
||||
from typing import List, Optional
|
||||
|
||||
from redis import Redis
|
||||
from pytz import utc
|
||||
from redis import Redis, RedisError
|
||||
|
||||
from django_redis import get_redis_connection
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class _RedisStub:
|
||||
"""Stub of a Redis client.
|
||||
|
||||
It's purpose is to prevent EventSeries objects from trying to access Redis
|
||||
when it is not available. e.g. when the Sphinx docs are rendered by readthedocs.org.
|
||||
"""
|
||||
|
||||
def delete(self, *args, **kwargs):
|
||||
pass
|
||||
|
||||
def incr(self, *args, **kwargs):
|
||||
return 0
|
||||
|
||||
def zadd(self, *args, **kwargs):
|
||||
pass
|
||||
|
||||
def zcount(self, *args, **kwargs):
|
||||
pass
|
||||
|
||||
def zrangebyscore(self, *args, **kwargs):
|
||||
pass
|
||||
|
||||
|
||||
class EventSeries:
|
||||
"""API for recording and analysing a series of events."""
|
||||
"""API for recording and analyzing a series of events."""
|
||||
|
||||
_ROOT_KEY = "ALLIANCEAUTH_EVENT_SERIES"
|
||||
|
||||
def __init__(self, key_id: str, redis: Redis = None) -> None:
|
||||
self._redis = get_redis_connection("default") if not redis else redis
|
||||
if not isinstance(self._redis, Redis):
|
||||
raise TypeError(
|
||||
"This class requires a Redis client, but none was provided "
|
||||
"and the default Django cache backend is not Redis either."
|
||||
try:
|
||||
if not self._redis.ping():
|
||||
raise RuntimeError()
|
||||
except (AttributeError, RedisError, RuntimeError):
|
||||
logger.exception(
|
||||
"Failed to establish a connection with Redis. "
|
||||
"This EventSeries object is disabled.",
|
||||
)
|
||||
self._redis = _RedisStub()
|
||||
self._key_id = str(key_id)
|
||||
self.clear()
|
||||
|
||||
@property
|
||||
def is_disabled(self):
|
||||
"""True when this object is disabled, e.g. Redis was not available at startup."""
|
||||
return isinstance(self._redis, _RedisStub)
|
||||
|
||||
@property
|
||||
def _key_counter(self):
|
||||
return f"{self._ROOT_KEY}_{self._key_id}_COUNTER"
|
||||
|
||||
@@ -1,13 +1,48 @@
|
||||
import datetime as dt
|
||||
from unittest.mock import patch
|
||||
|
||||
from pytz import utc
|
||||
from redis import RedisError
|
||||
|
||||
from django.test import TestCase
|
||||
from django.utils.timezone import now
|
||||
|
||||
from allianceauth.authentication.task_statistics.event_series import EventSeries
|
||||
from allianceauth.authentication.task_statistics.event_series import (
|
||||
EventSeries,
|
||||
_RedisStub,
|
||||
)
|
||||
|
||||
MODULE_PATH = "allianceauth.authentication.task_statistics.event_series"
|
||||
|
||||
|
||||
class TestEventSeries(TestCase):
|
||||
def test_should_abort_without_redis_client(self):
|
||||
# when
|
||||
with patch(MODULE_PATH + ".get_redis_connection") as mock:
|
||||
mock.return_value = None
|
||||
events = EventSeries("dummy")
|
||||
# then
|
||||
self.assertTrue(events._redis, _RedisStub)
|
||||
self.assertTrue(events.is_disabled)
|
||||
|
||||
def test_should_disable_itself_if_redis_not_available_1(self):
|
||||
# when
|
||||
with patch(MODULE_PATH + ".get_redis_connection") as mock_get_redis_connection:
|
||||
mock_get_redis_connection.return_value.ping.side_effect = RedisError
|
||||
events = EventSeries("dummy")
|
||||
# then
|
||||
self.assertIsInstance(events._redis, _RedisStub)
|
||||
self.assertTrue(events.is_disabled)
|
||||
|
||||
def test_should_disable_itself_if_redis_not_available_2(self):
|
||||
# when
|
||||
with patch(MODULE_PATH + ".get_redis_connection") as mock_get_redis_connection:
|
||||
mock_get_redis_connection.return_value.ping.return_value = False
|
||||
events = EventSeries("dummy")
|
||||
# then
|
||||
self.assertIsInstance(events._redis, _RedisStub)
|
||||
self.assertTrue(events.is_disabled)
|
||||
|
||||
def test_should_add_event(self):
|
||||
# given
|
||||
events = EventSeries("dummy")
|
||||
|
||||
@@ -212,7 +212,14 @@ def fatlink_monthly_personal_statistics_view(request, year, month, char_id=None)
|
||||
start_of_previous_month = first_day_of_previous_month(year, month)
|
||||
|
||||
if request.user.has_perm('auth.fleetactivitytracking_statistics') and char_id:
|
||||
user = EveCharacter.objects.get(character_id=char_id).user
|
||||
try:
|
||||
user = EveCharacter.objects.get(character_id=char_id).character_ownership.user
|
||||
except EveCharacter.DoesNotExist:
|
||||
messages.error(request, _('Character does not exist'))
|
||||
return redirect('fatlink:view')
|
||||
except AttributeError:
|
||||
messages.error(request, _('User does not exist'))
|
||||
return redirect('fatlink:view')
|
||||
else:
|
||||
user = request.user
|
||||
logger.debug(f"Personal monthly statistics view for user {user} called by {request.user}")
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
from django.apps import apps
|
||||
from django.contrib import admin
|
||||
from django.contrib.auth.models import Group as BaseGroup
|
||||
from django.contrib.auth.models import Permission, User
|
||||
from django.db.models import Count
|
||||
|
||||
from django.contrib.auth.models import Group as BaseGroup, Permission, User
|
||||
from django.db.models import Count, Exists, OuterRef
|
||||
from django.db.models.functions import Lower
|
||||
from django.db.models.signals import (
|
||||
m2m_changed,
|
||||
@@ -15,6 +15,7 @@ from django.dispatch import receiver
|
||||
|
||||
from .forms import GroupAdminForm, ReservedGroupNameAdminForm
|
||||
from .models import AuthGroup, GroupRequest, ReservedGroupName
|
||||
from .tasks import remove_users_not_matching_states_from_group
|
||||
|
||||
if 'eve_autogroups' in apps.app_configs:
|
||||
_has_auto_groups = True
|
||||
@@ -106,14 +107,13 @@ class HasLeaderFilter(admin.SimpleListFilter):
|
||||
|
||||
class GroupAdmin(admin.ModelAdmin):
|
||||
form = GroupAdminForm
|
||||
list_select_related = ('authgroup',)
|
||||
ordering = ('name',)
|
||||
list_display = (
|
||||
'name',
|
||||
'_description',
|
||||
'_properties',
|
||||
'_member_count',
|
||||
'has_leader'
|
||||
'has_leader',
|
||||
)
|
||||
list_filter = [
|
||||
'authgroup__internal',
|
||||
@@ -129,31 +129,51 @@ class GroupAdmin(admin.ModelAdmin):
|
||||
|
||||
def get_queryset(self, request):
|
||||
qs = super().get_queryset(request)
|
||||
if _has_auto_groups:
|
||||
qs = qs.prefetch_related('managedalliancegroup_set', 'managedcorpgroup_set')
|
||||
qs = qs.prefetch_related('authgroup__group_leaders').select_related('authgroup')
|
||||
qs = qs.annotate(
|
||||
member_count=Count('user', distinct=True),
|
||||
has_leader_qs = (
|
||||
AuthGroup.objects.filter(group=OuterRef('pk'), group_leaders__isnull=False)
|
||||
)
|
||||
has_leader_groups_qs = (
|
||||
AuthGroup.objects.filter(
|
||||
group=OuterRef('pk'), group_leader_groups__isnull=False
|
||||
)
|
||||
)
|
||||
qs = (
|
||||
qs.select_related('authgroup')
|
||||
.annotate(member_count=Count('user', distinct=True))
|
||||
.annotate(has_leader=Exists(has_leader_qs))
|
||||
.annotate(has_leader_groups=Exists(has_leader_groups_qs))
|
||||
)
|
||||
if _has_auto_groups:
|
||||
is_autogroup_corp = (
|
||||
Group.objects.filter(
|
||||
pk=OuterRef('pk'), managedcorpgroup__isnull=False
|
||||
)
|
||||
)
|
||||
is_autogroup_alliance = (
|
||||
Group.objects.filter(
|
||||
pk=OuterRef('pk'), managedalliancegroup__isnull=False
|
||||
)
|
||||
)
|
||||
qs = (
|
||||
qs.annotate(is_autogroup_corp=Exists(is_autogroup_corp))
|
||||
.annotate(is_autogroup_alliance=Exists(is_autogroup_alliance))
|
||||
)
|
||||
return qs
|
||||
|
||||
def _description(self, obj):
|
||||
return obj.authgroup.description
|
||||
|
||||
@admin.display(description="Members", ordering="member_count")
|
||||
@admin.display(description='Members', ordering='member_count')
|
||||
def _member_count(self, obj):
|
||||
return obj.member_count
|
||||
|
||||
@admin.display(boolean=True)
|
||||
def has_leader(self, obj):
|
||||
return obj.authgroup.group_leaders.exists() or obj.authgroup.group_leader_groups.exists()
|
||||
return obj.has_leader or obj.has_leader_groups
|
||||
|
||||
def _properties(self, obj):
|
||||
properties = list()
|
||||
if _has_auto_groups and (
|
||||
obj.managedalliancegroup_set.exists()
|
||||
or obj.managedcorpgroup_set.exists()
|
||||
):
|
||||
if _has_auto_groups and (obj.is_autogroup_corp or obj.is_autogroup_alliance):
|
||||
properties.append('Auto Group')
|
||||
elif obj.authgroup.internal:
|
||||
properties.append('Internal')
|
||||
@@ -183,6 +203,8 @@ class GroupAdmin(admin.ModelAdmin):
|
||||
ag_instance = inline_form.save(commit=False)
|
||||
ag_instance.group = form.instance
|
||||
ag_instance.save()
|
||||
if ag_instance.states.exists():
|
||||
remove_users_not_matching_states_from_group.delay(ag_instance.group.pk)
|
||||
formset.save()
|
||||
|
||||
def get_readonly_fields(self, request, obj=None):
|
||||
|
||||
@@ -189,6 +189,15 @@ class AuthGroup(models.Model):
|
||||
| User.objects.filter(groups__in=list(self.group_leader_groups.all()))
|
||||
)
|
||||
|
||||
def remove_users_not_matching_states(self):
|
||||
"""Remove users not matching defined states from related group."""
|
||||
states_qs = self.states.all()
|
||||
if states_qs.exists():
|
||||
states = list(states_qs)
|
||||
non_compliant_users = self.group.user_set.exclude(profile__state__in=states)
|
||||
for user in non_compliant_users:
|
||||
self.group.user_set.remove(user)
|
||||
|
||||
|
||||
class ReservedGroupName(models.Model):
|
||||
"""Name that can not be used for groups.
|
||||
|
||||
10
allianceauth/groupmanagement/tasks.py
Normal file
10
allianceauth/groupmanagement/tasks.py
Normal file
@@ -0,0 +1,10 @@
|
||||
from celery import shared_task
|
||||
|
||||
from django.contrib.auth.models import Group
|
||||
|
||||
|
||||
@shared_task
|
||||
def remove_users_not_matching_states_from_group(group_pk: int) -> None:
|
||||
"""Remove users not matching defined states from related group."""
|
||||
group = Group.objects.get(pk=group_pk)
|
||||
group.authgroup.remove_users_not_matching_states()
|
||||
@@ -6,7 +6,7 @@ from django.conf import settings
|
||||
from django.contrib import admin
|
||||
from django.contrib.admin.sites import AdminSite
|
||||
from django.contrib.auth.models import User
|
||||
from django.test import TestCase, RequestFactory, Client
|
||||
from django.test import TestCase, RequestFactory, Client, override_settings
|
||||
|
||||
from allianceauth.authentication.models import CharacterOwnership, State
|
||||
from allianceauth.eveonline.models import (
|
||||
@@ -236,60 +236,104 @@ class TestGroupAdmin(TestCase):
|
||||
self.assertEqual(result, expected)
|
||||
|
||||
def test_member_count(self):
|
||||
expected = 1
|
||||
obj = self.modeladmin.get_queryset(MockRequest(user=self.user_1))\
|
||||
.get(pk=self.group_1.pk)
|
||||
# given
|
||||
request = MockRequest(user=self.user_1)
|
||||
obj = self.modeladmin.get_queryset(request).get(pk=self.group_1.pk)
|
||||
# when
|
||||
result = self.modeladmin._member_count(obj)
|
||||
self.assertEqual(result, expected)
|
||||
# then
|
||||
self.assertEqual(result, 1)
|
||||
|
||||
def test_has_leader_user(self):
|
||||
result = self.modeladmin.has_leader(self.group_1)
|
||||
# given
|
||||
request = MockRequest(user=self.user_1)
|
||||
obj = self.modeladmin.get_queryset(request).get(pk=self.group_1.pk)
|
||||
# when
|
||||
result = self.modeladmin.has_leader(obj)
|
||||
# then
|
||||
self.assertTrue(result)
|
||||
|
||||
def test_has_leader_group(self):
|
||||
result = self.modeladmin.has_leader(self.group_2)
|
||||
# given
|
||||
request = MockRequest(user=self.user_1)
|
||||
obj = self.modeladmin.get_queryset(request).get(pk=self.group_2.pk)
|
||||
# when
|
||||
result = self.modeladmin.has_leader(obj)
|
||||
# then
|
||||
self.assertTrue(result)
|
||||
|
||||
def test_properties_1(self):
|
||||
expected = ['Default']
|
||||
result = self.modeladmin._properties(self.group_1)
|
||||
self.assertListEqual(result, expected)
|
||||
# given
|
||||
request = MockRequest(user=self.user_1)
|
||||
obj = self.modeladmin.get_queryset(request).get(pk=self.group_1.pk)
|
||||
# when
|
||||
result = self.modeladmin._properties(obj)
|
||||
self.assertListEqual(result, ['Default'])
|
||||
|
||||
def test_properties_2(self):
|
||||
expected = ['Internal']
|
||||
result = self.modeladmin._properties(self.group_2)
|
||||
self.assertListEqual(result, expected)
|
||||
# given
|
||||
request = MockRequest(user=self.user_1)
|
||||
obj = self.modeladmin.get_queryset(request).get(pk=self.group_2.pk)
|
||||
# when
|
||||
result = self.modeladmin._properties(obj)
|
||||
self.assertListEqual(result, ['Internal'])
|
||||
|
||||
def test_properties_3(self):
|
||||
expected = ['Hidden']
|
||||
result = self.modeladmin._properties(self.group_3)
|
||||
self.assertListEqual(result, expected)
|
||||
# given
|
||||
request = MockRequest(user=self.user_1)
|
||||
obj = self.modeladmin.get_queryset(request).get(pk=self.group_3.pk)
|
||||
# when
|
||||
result = self.modeladmin._properties(obj)
|
||||
self.assertListEqual(result, ['Hidden'])
|
||||
|
||||
def test_properties_4(self):
|
||||
expected = ['Open']
|
||||
result = self.modeladmin._properties(self.group_4)
|
||||
self.assertListEqual(result, expected)
|
||||
# given
|
||||
request = MockRequest(user=self.user_1)
|
||||
obj = self.modeladmin.get_queryset(request).get(pk=self.group_4.pk)
|
||||
# when
|
||||
result = self.modeladmin._properties(obj)
|
||||
self.assertListEqual(result, ['Open'])
|
||||
|
||||
def test_properties_5(self):
|
||||
expected = ['Public']
|
||||
result = self.modeladmin._properties(self.group_5)
|
||||
self.assertListEqual(result, expected)
|
||||
# given
|
||||
request = MockRequest(user=self.user_1)
|
||||
obj = self.modeladmin.get_queryset(request).get(pk=self.group_5.pk)
|
||||
# when
|
||||
result = self.modeladmin._properties(obj)
|
||||
self.assertListEqual(result, ['Public'])
|
||||
|
||||
def test_properties_6(self):
|
||||
expected = ['Hidden', 'Open', 'Public']
|
||||
result = self.modeladmin._properties(self.group_6)
|
||||
self.assertListEqual(result, expected)
|
||||
# given
|
||||
request = MockRequest(user=self.user_1)
|
||||
obj = self.modeladmin.get_queryset(request).get(pk=self.group_6.pk)
|
||||
# when
|
||||
result = self.modeladmin._properties(obj)
|
||||
self.assertListEqual(result, ['Hidden', 'Open', 'Public'])
|
||||
|
||||
if _has_auto_groups:
|
||||
@patch(MODULE_PATH + '._has_auto_groups', True)
|
||||
def test_properties_7(self):
|
||||
def test_should_show_autogroup_for_corporation(self):
|
||||
# given
|
||||
self._create_autogroups()
|
||||
expected = ['Auto Group']
|
||||
my_group = Group.objects\
|
||||
.filter(managedcorpgroup__isnull=False)\
|
||||
.first()
|
||||
result = self.modeladmin._properties(my_group)
|
||||
self.assertListEqual(result, expected)
|
||||
request = MockRequest(user=self.user_1)
|
||||
queryset = self.modeladmin.get_queryset(request)
|
||||
obj = queryset.filter(managedcorpgroup__isnull=False).first()
|
||||
# when
|
||||
result = self.modeladmin._properties(obj)
|
||||
# then
|
||||
self.assertListEqual(result, ['Auto Group'])
|
||||
|
||||
@patch(MODULE_PATH + '._has_auto_groups', True)
|
||||
def test_should_show_autogroup_for_alliance(self):
|
||||
# given
|
||||
self._create_autogroups()
|
||||
request = MockRequest(user=self.user_1)
|
||||
queryset = self.modeladmin.get_queryset(request)
|
||||
obj = queryset.filter(managedalliancegroup__isnull=False).first()
|
||||
# when
|
||||
result = self.modeladmin._properties(obj)
|
||||
# then
|
||||
self.assertListEqual(result, ['Auto Group'])
|
||||
|
||||
# actions
|
||||
|
||||
@@ -539,6 +583,68 @@ class TestGroupAdminChangeFormSuperuserExclusiveEdits(WebTest):
|
||||
self.assertNotIn(field, form.fields)
|
||||
|
||||
|
||||
@override_settings(CELERY_ALWAYS_EAGER=True, CELERY_EAGER_PROPAGATES_EXCEPTIONS=True)
|
||||
class TestGroupAdmin2(TestCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
cls.superuser = User.objects.create_superuser("super")
|
||||
|
||||
def test_should_remove_users_from_state_groups(self):
|
||||
# given
|
||||
user_member = AuthUtils.create_user("Bruce Wayne")
|
||||
character_member = AuthUtils.add_main_character_2(
|
||||
user_member,
|
||||
name="Bruce Wayne",
|
||||
character_id=1001,
|
||||
corp_id=2001,
|
||||
corp_name="Wayne Technologies",
|
||||
)
|
||||
user_guest = AuthUtils.create_user("Lex Luthor")
|
||||
AuthUtils.add_main_character_2(
|
||||
user_guest,
|
||||
name="Lex Luthor",
|
||||
character_id=1011,
|
||||
corp_id=2011,
|
||||
corp_name="Luthor Corp",
|
||||
)
|
||||
member_state = AuthUtils.get_member_state()
|
||||
member_state.member_characters.add(character_member)
|
||||
user_member.refresh_from_db()
|
||||
user_guest.refresh_from_db()
|
||||
group = Group.objects.create(name="dummy")
|
||||
user_member.groups.add(group)
|
||||
user_guest.groups.add(group)
|
||||
group.authgroup.states.add(member_state)
|
||||
self.client.force_login(self.superuser)
|
||||
# when
|
||||
response = self.client.post(
|
||||
f"/admin/groupmanagement/group/{group.pk}/change/",
|
||||
data={
|
||||
"name": f"{group.name}",
|
||||
"authgroup-TOTAL_FORMS": "1",
|
||||
"authgroup-INITIAL_FORMS": "1",
|
||||
"authgroup-MIN_NUM_FORMS": "0",
|
||||
"authgroup-MAX_NUM_FORMS": "1",
|
||||
"authgroup-0-description": "",
|
||||
"authgroup-0-states": f"{member_state.pk}",
|
||||
"authgroup-0-internal": "on",
|
||||
"authgroup-0-hidden": "on",
|
||||
"authgroup-0-group": f"{group.pk}",
|
||||
"authgroup-__prefix__-description": "",
|
||||
"authgroup-__prefix__-internal": "on",
|
||||
"authgroup-__prefix__-hidden": "on",
|
||||
"authgroup-__prefix__-group": f"{group.pk}",
|
||||
"_save": "Save"
|
||||
}
|
||||
)
|
||||
# then
|
||||
self.assertEqual(response.status_code, 302)
|
||||
self.assertEqual(response.url, "/admin/groupmanagement/group/")
|
||||
self.assertIn(group, user_member.groups.all())
|
||||
self.assertNotIn(group, user_guest.groups.all())
|
||||
|
||||
|
||||
class TestReservedGroupNameAdmin(TestCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
|
||||
@@ -232,6 +232,38 @@ class TestAuthGroup(TestCase):
|
||||
expected = 'Superheros'
|
||||
self.assertEqual(str(group.authgroup), expected)
|
||||
|
||||
def test_should_remove_guests_from_group_when_restricted_to_members_only(self):
|
||||
# given
|
||||
user_member = AuthUtils.create_user("Bruce Wayne")
|
||||
character_member = AuthUtils.add_main_character_2(
|
||||
user_member,
|
||||
name="Bruce Wayne",
|
||||
character_id=1001,
|
||||
corp_id=2001,
|
||||
corp_name="Wayne Technologies",
|
||||
)
|
||||
user_guest = AuthUtils.create_user("Lex Luthor")
|
||||
AuthUtils.add_main_character_2(
|
||||
user_guest,
|
||||
name="Lex Luthor",
|
||||
character_id=1011,
|
||||
corp_id=2011,
|
||||
corp_name="Luthor Corp",
|
||||
)
|
||||
member_state = AuthUtils.get_member_state()
|
||||
member_state.member_characters.add(character_member)
|
||||
user_member.refresh_from_db()
|
||||
user_guest.refresh_from_db()
|
||||
group = Group.objects.create(name="dummy")
|
||||
user_member.groups.add(group)
|
||||
user_guest.groups.add(group)
|
||||
group.authgroup.states.add(member_state)
|
||||
# when
|
||||
group.authgroup.remove_users_not_matching_states()
|
||||
# then
|
||||
self.assertIn(group, user_member.groups.all())
|
||||
self.assertNotIn(group, user_guest.groups.all())
|
||||
|
||||
|
||||
class TestAuthGroupRequestApprovers(TestCase):
|
||||
def setUp(self) -> None:
|
||||
|
||||
Binary file not shown.
@@ -20,7 +20,7 @@ msgstr ""
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: es\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
"Plural-Forms: nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;\n"
|
||||
|
||||
#: allianceauth/analytics/models.py:29
|
||||
msgid "Google Analytics Universal"
|
||||
@@ -450,6 +450,7 @@ msgid "%(user)s has collected one link this month."
|
||||
msgid_plural "%(user)s has collected %(links)s links this month."
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
msgstr[2] ""
|
||||
|
||||
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkpersonalmonthlystatisticsview.html:28
|
||||
msgid "Times used"
|
||||
@@ -461,6 +462,7 @@ msgid "%(user)s has created one link this month."
|
||||
msgid_plural "%(user)s has created %(links)s links this month."
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
msgstr[2] ""
|
||||
|
||||
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkpersonalmonthlystatisticsview.html:48
|
||||
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkview.html:27
|
||||
@@ -2141,6 +2143,7 @@ msgid "%(tasks)s task"
|
||||
msgid_plural "%(tasks)s tasks"
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
msgstr[2] ""
|
||||
|
||||
#: allianceauth/templates/allianceauth/night-toggle.html:6
|
||||
msgid "Night Mode"
|
||||
|
||||
Binary file not shown.
@@ -5,11 +5,11 @@
|
||||
#
|
||||
# Translators:
|
||||
# François LACROIX-DURANT <umbre@fallenstarscreations.com>, 2020
|
||||
# Philippe Querin-Laporte <philippe.querin@hotmail.com>, 2020
|
||||
# Keven D. <theenarki@gmail.com>, 2020
|
||||
# Idea ., 2021
|
||||
# Mickael PATTE, 2021
|
||||
# Geoffrey Fabbro, 2021
|
||||
# Philippe Querin-Laporte <philippe.querin@hotmail.com>, 2022
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
@@ -18,13 +18,13 @@ msgstr ""
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2021-11-29 01:03+1000\n"
|
||||
"PO-Revision-Date: 2020-02-18 03:14+0000\n"
|
||||
"Last-Translator: Geoffrey Fabbro, 2021\n"
|
||||
"Last-Translator: Philippe Querin-Laporte <philippe.querin@hotmail.com>, 2022\n"
|
||||
"Language-Team: French (France) (https://www.transifex.com/alliance-auth/teams/107430/fr_FR/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: fr_FR\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
|
||||
"Plural-Forms: nplurals=3; plural=(n == 0 || n == 1) ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;\n"
|
||||
|
||||
#: allianceauth/analytics/models.py:29
|
||||
msgid "Google Analytics Universal"
|
||||
@@ -460,6 +460,7 @@ msgid "%(user)s has collected one link this month."
|
||||
msgid_plural "%(user)s has collected %(links)s links this month."
|
||||
msgstr[0] "%(user)s a obtenu un lien ce mois."
|
||||
msgstr[1] "%(user)s a obtenu %(links)s liens ce mois."
|
||||
msgstr[2] "%(user)s a obtenu %(links)s liens ce mois."
|
||||
|
||||
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkpersonalmonthlystatisticsview.html:28
|
||||
msgid "Times used"
|
||||
@@ -471,6 +472,7 @@ msgid "%(user)s has created one link this month."
|
||||
msgid_plural "%(user)s has created %(links)s links this month."
|
||||
msgstr[0] "%(user)s a créé un lien ce mois."
|
||||
msgstr[1] "%(user)s a créé %(links)s liens ce mois."
|
||||
msgstr[2] "%(user)s a créé %(links)s liens ce mois."
|
||||
|
||||
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkpersonalmonthlystatisticsview.html:48
|
||||
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkview.html:27
|
||||
@@ -2167,6 +2169,7 @@ msgid "%(tasks)s task"
|
||||
msgid_plural "%(tasks)s tasks"
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
msgstr[2] ""
|
||||
|
||||
#: allianceauth/templates/allianceauth/night-toggle.html:6
|
||||
msgid "Night Mode"
|
||||
|
||||
Binary file not shown.
@@ -5,7 +5,7 @@
|
||||
#
|
||||
# Translators:
|
||||
# Alessandro Cresti, 2021
|
||||
# Linus Hope, 2021
|
||||
# Linus Hope, 2022
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
@@ -14,13 +14,13 @@ msgstr ""
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2021-11-29 01:03+1000\n"
|
||||
"PO-Revision-Date: 2020-02-18 03:14+0000\n"
|
||||
"Last-Translator: Linus Hope, 2021\n"
|
||||
"Last-Translator: Linus Hope, 2022\n"
|
||||
"Language-Team: Italian (Italy) (https://www.transifex.com/alliance-auth/teams/107430/it_IT/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: it_IT\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
"Plural-Forms: nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;\n"
|
||||
|
||||
#: allianceauth/analytics/models.py:29
|
||||
msgid "Google Analytics Universal"
|
||||
@@ -460,6 +460,7 @@ msgid "%(user)s has collected one link this month."
|
||||
msgid_plural "%(user)s has collected %(links)s links this month."
|
||||
msgstr[0] "%(user)s ha ottenuto un link per questo mese."
|
||||
msgstr[1] "%(user)s ha ottenuto %(links)s links questo mese."
|
||||
msgstr[2] "%(user)s ha ottenuto %(links)s links questo mese."
|
||||
|
||||
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkpersonalmonthlystatisticsview.html:28
|
||||
msgid "Times used"
|
||||
@@ -471,6 +472,7 @@ msgid "%(user)s has created one link this month."
|
||||
msgid_plural "%(user)s has created %(links)s links this month."
|
||||
msgstr[0] "%(user)s ha creato un link questo mese."
|
||||
msgstr[1] "%(user)s ha creato %(links)s links questo mese."
|
||||
msgstr[2] "%(user)s ha creato %(links)s links questo mese."
|
||||
|
||||
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkpersonalmonthlystatisticsview.html:48
|
||||
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkview.html:27
|
||||
@@ -2155,6 +2157,7 @@ msgid "%(tasks)s task"
|
||||
msgid_plural "%(tasks)s tasks"
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
msgstr[2] ""
|
||||
|
||||
#: allianceauth/templates/allianceauth/night-toggle.html:6
|
||||
msgid "Night Mode"
|
||||
|
||||
Binary file not shown.
@@ -9,6 +9,7 @@
|
||||
# Olgeda Choi <undead.choi@gmail.com>, 2020
|
||||
# Lahty <js03js70@gmail.com>, 2020
|
||||
# Joel Falknau <ozirascal@gmail.com>, 2020
|
||||
# ThatRagingKid, 2022
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
@@ -17,7 +18,7 @@ msgstr ""
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2021-11-29 01:03+1000\n"
|
||||
"PO-Revision-Date: 2020-02-18 03:14+0000\n"
|
||||
"Last-Translator: Joel Falknau <ozirascal@gmail.com>, 2020\n"
|
||||
"Last-Translator: ThatRagingKid, 2022\n"
|
||||
"Language-Team: Korean (Korea) (https://www.transifex.com/alliance-auth/teams/107430/ko_KR/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
@@ -27,15 +28,15 @@ msgstr ""
|
||||
|
||||
#: allianceauth/analytics/models.py:29
|
||||
msgid "Google Analytics Universal"
|
||||
msgstr ""
|
||||
msgstr "구글 애널리틱스 유니버설"
|
||||
|
||||
#: allianceauth/analytics/models.py:30
|
||||
msgid "Google Analytics V4"
|
||||
msgstr ""
|
||||
msgstr "구글 애널리틱스 V4"
|
||||
|
||||
#: allianceauth/authentication/decorators.py:37
|
||||
msgid "A main character is required to perform that action. Add one below."
|
||||
msgstr "해당 기능을 수행하려면 주 캐릭터가 요구됨. 아래에 하나를 추가하시오."
|
||||
msgstr "해당 기능을 수행하려면 주 캐릭터가 요구됨. 아래에서 하나를 추가하시오."
|
||||
|
||||
#: allianceauth/authentication/forms.py:5
|
||||
msgid "Email"
|
||||
@@ -65,7 +66,7 @@ msgid ""
|
||||
" "
|
||||
msgstr ""
|
||||
"\n"
|
||||
" 메인 캐릭터 (상태: %(state)s)\n"
|
||||
" 주 캐릭터 (상태: %(state)s)\n"
|
||||
" "
|
||||
|
||||
#: allianceauth/authentication/templates/authentication/dashboard.html:102
|
||||
@@ -103,7 +104,7 @@ msgstr "이름"
|
||||
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkstatisticsview.html:23
|
||||
#: allianceauth/hrapplications/templates/hrapplications/view.html:46
|
||||
msgid "Corp"
|
||||
msgstr "콥"
|
||||
msgstr "코퍼레이션"
|
||||
|
||||
#: allianceauth/authentication/templates/authentication/dashboard.html:152
|
||||
#: allianceauth/corputils/templates/corputils/corpstats.html:76
|
||||
@@ -118,7 +119,7 @@ msgstr "로그인"
|
||||
|
||||
#: allianceauth/authentication/templates/public/register.html:7
|
||||
msgid "Registration"
|
||||
msgstr ""
|
||||
msgstr "가입"
|
||||
|
||||
#: allianceauth/authentication/templates/public/register.html:22
|
||||
#: allianceauth/authentication/templates/registration/registration_form.html:5
|
||||
@@ -137,7 +138,7 @@ msgstr "계정 패스워드 리셋을 요청하여 이 이메일을 보내드립
|
||||
|
||||
#: allianceauth/authentication/templates/registration/password_reset_email.html:5
|
||||
msgid "Please go to the following page and choose a new password:"
|
||||
msgstr "다음 페이지로 이동하여 새로운 패스워드를 입력하세요."
|
||||
msgstr "다음 페이지로 이동하여 새로운 패스워드를 입력하세요:"
|
||||
|
||||
#: allianceauth/authentication/templates/registration/password_reset_email.html:9
|
||||
msgid "Your username, in case you've forgotten:"
|
||||
@@ -176,7 +177,7 @@ msgstr "계정에 %(name)s를 추가했습니다."
|
||||
#: allianceauth/authentication/views.py:94
|
||||
#, python-format
|
||||
msgid "Failed to add %(name)s to your account: they already have an account."
|
||||
msgstr "계정에 %(name)s를 추가하지 못했습니다. 이미 추가된 계정입니다."
|
||||
msgstr "계정에 %(name)s를 추가하지 못했습니다. 이미 다른 계정에 추가되었습니다."
|
||||
|
||||
#: allianceauth/authentication/views.py:133
|
||||
msgid "Unable to authenticate as the selected character."
|
||||
@@ -184,7 +185,7 @@ msgstr "선택한 캐릭터로 인증을 수행할 수 없음"
|
||||
|
||||
#: allianceauth/authentication/views.py:197
|
||||
msgid "Registration token has expired."
|
||||
msgstr "등록토큰 만료"
|
||||
msgstr "가입 토큰이 만료되었습니다."
|
||||
|
||||
#: allianceauth/authentication/views.py:252
|
||||
msgid ""
|
||||
@@ -202,16 +203,16 @@ msgstr "현재 새로운 계정 등록은 받지않습니다."
|
||||
|
||||
#: allianceauth/corputils/auth_hooks.py:11
|
||||
msgid "Corporation Stats"
|
||||
msgstr "콥 상태"
|
||||
msgstr "코퍼레이션 상태"
|
||||
|
||||
#: allianceauth/corputils/templates/corputils/base.html:3
|
||||
#: allianceauth/corputils/templates/corputils/base.html:6
|
||||
msgid "Corporation Member Data"
|
||||
msgstr "콥 멤버 데이터"
|
||||
msgstr "코퍼레이션 멤버 정보"
|
||||
|
||||
#: allianceauth/corputils/templates/corputils/base.html:12
|
||||
msgid "Corporations"
|
||||
msgstr "콥"
|
||||
msgstr "코퍼레이션"
|
||||
|
||||
#: allianceauth/corputils/templates/corputils/base.html:23
|
||||
msgid "Add"
|
||||
@@ -219,7 +220,7 @@ msgstr "추가"
|
||||
|
||||
#: allianceauth/corputils/templates/corputils/base.html:29
|
||||
msgid "Search all corporations..."
|
||||
msgstr "모든 콥 검색"
|
||||
msgstr "모든 코퍼레이션 검색"
|
||||
|
||||
#: allianceauth/corputils/templates/corputils/corpstats.html:33
|
||||
msgid "Mains"
|
||||
@@ -237,7 +238,7 @@ msgstr "미등록"
|
||||
|
||||
#: allianceauth/corputils/templates/corputils/corpstats.html:38
|
||||
msgid "Last update:"
|
||||
msgstr "마지막 업데이트"
|
||||
msgstr "마지막 업데이트:"
|
||||
|
||||
#: allianceauth/corputils/templates/corputils/corpstats.html:74
|
||||
#: allianceauth/corputils/templates/corputils/corpstats.html:112
|
||||
@@ -260,7 +261,7 @@ msgstr "캐릭터"
|
||||
#: allianceauth/hrapplications/templates/hrapplications/management.html:126
|
||||
#: allianceauth/hrapplications/templates/hrapplications/searchview.html:26
|
||||
msgid "Corporation"
|
||||
msgstr "콥"
|
||||
msgstr "코퍼레이션"
|
||||
|
||||
#: allianceauth/corputils/templates/corputils/corpstats.html:91
|
||||
#: allianceauth/corputils/templates/corputils/corpstats.html:125
|
||||
@@ -268,7 +269,7 @@ msgstr "콥"
|
||||
#: allianceauth/corputils/templates/corputils/corpstats.html:167
|
||||
#: allianceauth/corputils/templates/corputils/search.html:27
|
||||
msgid "Killboard"
|
||||
msgstr "킬보드"
|
||||
msgstr "사살권"
|
||||
|
||||
#: allianceauth/corputils/templates/corputils/corpstats.html:114
|
||||
#: allianceauth/corputils/templates/corputils/search.html:16
|
||||
@@ -283,12 +284,12 @@ msgstr "주 캐릭터"
|
||||
#: allianceauth/corputils/templates/corputils/corpstats.html:115
|
||||
#: allianceauth/corputils/templates/corputils/search.html:17
|
||||
msgid "Main Corporation"
|
||||
msgstr "메인콥"
|
||||
msgstr "주 코퍼레이션"
|
||||
|
||||
#: allianceauth/corputils/templates/corputils/corpstats.html:116
|
||||
#: allianceauth/corputils/templates/corputils/search.html:18
|
||||
msgid "Main Alliance"
|
||||
msgstr "메인 얼라이언스"
|
||||
msgstr "주 얼라이언스"
|
||||
|
||||
#: allianceauth/corputils/templates/corputils/search.html:6
|
||||
msgid "Search Results"
|
||||
@@ -296,28 +297,28 @@ msgstr "검색결과"
|
||||
|
||||
#: allianceauth/corputils/templates/corputils/search.html:15
|
||||
msgid "zKillboard"
|
||||
msgstr "킬보드"
|
||||
msgstr "zKillboard"
|
||||
|
||||
#: allianceauth/corputils/views.py:54
|
||||
msgid "Selected corp already has a statistics module."
|
||||
msgstr "선택한 콥은 이미 통계 모듈을 갖고있습니다."
|
||||
msgstr "선택한 코퍼레이션은 이미 통계 모듈을 갖고 있습니다."
|
||||
|
||||
#: allianceauth/corputils/views.py:56
|
||||
msgid "Failed to gather corporation statistics with selected token."
|
||||
msgstr "선택한 토큰으로 콥 통계 수집 실패"
|
||||
msgstr "선택한 토큰으로 코퍼레이션 통계 수집에 실패했습니다."
|
||||
|
||||
#: allianceauth/fleetactivitytracking/auth_hooks.py:9
|
||||
msgid "Fleet Activity Tracking"
|
||||
msgstr "플릿활동 추적"
|
||||
msgstr "함대 활동"
|
||||
|
||||
#: allianceauth/fleetactivitytracking/forms.py:6 allianceauth/srp/form.py:8
|
||||
#: allianceauth/srp/templates/srp/management.html:37
|
||||
msgid "Fleet Name"
|
||||
msgstr "플릿 이름"
|
||||
msgstr "함대 이름"
|
||||
|
||||
#: allianceauth/fleetactivitytracking/forms.py:7
|
||||
msgid "Duration of fat-link"
|
||||
msgstr "플릿활동추적 링크 주기"
|
||||
msgstr "함대 활동 링크 주기"
|
||||
|
||||
#: allianceauth/fleetactivitytracking/forms.py:7
|
||||
msgid "minutes"
|
||||
@@ -325,7 +326,7 @@ msgstr "분"
|
||||
|
||||
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/characternotexisting.html:3
|
||||
msgid "Fleet Participation"
|
||||
msgstr "플릿 참여"
|
||||
msgstr "함대 참여"
|
||||
|
||||
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/characternotexisting.html:7
|
||||
msgid "Character not found!"
|
||||
@@ -337,25 +338,25 @@ msgstr "캐릭터가 등록되지 않음!"
|
||||
|
||||
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/characternotexisting.html:19
|
||||
msgid "This character is not associated with an auth account."
|
||||
msgstr "해당 캐릭터는 본 계정에 연결되어있지 않음."
|
||||
msgstr "해당 캐릭터는 본 계정에 연결되어 있지 않습니다."
|
||||
|
||||
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/characternotexisting.html:19
|
||||
msgid "Add it here"
|
||||
msgstr "여기서 추가"
|
||||
msgstr "여기에 추가하시오"
|
||||
|
||||
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/characternotexisting.html:19
|
||||
msgid "before attempting to click fleet attendance links."
|
||||
msgstr "플릿 참여 링크를 클릭하기 전에"
|
||||
msgstr "함대 참여 링크를 클릭하기 전"
|
||||
|
||||
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkformatter.html:6
|
||||
msgid "Create Fatlink"
|
||||
msgstr "플릿활동추적 생성"
|
||||
msgstr "함대 활동 링크 생성"
|
||||
|
||||
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkformatter.html:10
|
||||
#: allianceauth/optimer/templates/optimer/add.html:14
|
||||
#: allianceauth/optimer/templates/optimer/add.html:23
|
||||
msgid "Create Fleet Operation"
|
||||
msgstr "플릿 옵 생성"
|
||||
msgstr "함대 오퍼레이션 생성"
|
||||
|
||||
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkformatter.html:14
|
||||
msgid "Bad request!"
|
||||
@@ -364,20 +365,20 @@ msgstr "잘못된 요청!"
|
||||
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkformatter.html:25
|
||||
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkview.html:65
|
||||
msgid "Create fatlink"
|
||||
msgstr "플릿활동추적 링크 생성"
|
||||
msgstr "함대 활동 링크 생성"
|
||||
|
||||
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkmodify.html:5
|
||||
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkview.html:6
|
||||
msgid "Fatlink view"
|
||||
msgstr "플릿활동추적 링크 보기"
|
||||
msgstr "함대 활동 링크 보기"
|
||||
|
||||
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkmodify.html:9
|
||||
msgid "Edit fatlink"
|
||||
msgstr "플릿활동추적 수정"
|
||||
msgstr "함대 활동 링크 수정"
|
||||
|
||||
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkmodify.html:13
|
||||
msgid "Delete fat"
|
||||
msgstr "플릿활동추적 수정"
|
||||
msgstr "함대 활동 링크 삭제"
|
||||
|
||||
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkmodify.html:19
|
||||
msgid "Registered characters"
|
||||
@@ -401,7 +402,7 @@ msgstr "시스템"
|
||||
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkpersonalmonthlystatisticsview.html:27
|
||||
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkview.html:30
|
||||
msgid "Ship"
|
||||
msgstr "배"
|
||||
msgstr "함선"
|
||||
|
||||
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkmodify.html:27
|
||||
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkpersonalmonthlystatisticsview.html:50
|
||||
@@ -422,7 +423,7 @@ msgstr "도킹"
|
||||
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkpersonalmonthlystatisticsview.html:6
|
||||
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkpersonalstatisticsview.html:6
|
||||
msgid "Personal fatlink statistics"
|
||||
msgstr "개인별 플릿활동추적 통계"
|
||||
msgstr "개인별 함대 활동 링크 통계"
|
||||
|
||||
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkpersonalmonthlystatisticsview.html:10
|
||||
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkstatisticscorpview.html:10
|
||||
@@ -492,11 +493,11 @@ msgstr "%(year)s년 동안의 참여 통계자료"
|
||||
|
||||
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkpersonalstatisticsview.html:12
|
||||
msgid "Previous year"
|
||||
msgstr "지난 해"
|
||||
msgstr "작년"
|
||||
|
||||
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkpersonalstatisticsview.html:14
|
||||
msgid "Next year"
|
||||
msgstr "다음 해"
|
||||
msgstr "내년"
|
||||
|
||||
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkpersonalstatisticsview.html:21
|
||||
msgid "Month"
|
||||
@@ -506,20 +507,20 @@ msgstr "달"
|
||||
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkstatisticscorpview.html:24
|
||||
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkstatisticsview.html:25
|
||||
msgid "Fats"
|
||||
msgstr "플릿활동추적"
|
||||
msgstr "함대 활동"
|
||||
|
||||
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkstatisticscorpview.html:6
|
||||
msgid "Fatlink Corp Statistics"
|
||||
msgstr "콥별 플릿활동추적 통계"
|
||||
msgstr "코퍼레이션별 함대 활동 통계"
|
||||
|
||||
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkstatisticscorpview.html:25
|
||||
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkstatisticsview.html:26
|
||||
msgid "Average fats"
|
||||
msgstr "평균 플릿활동추적"
|
||||
msgstr "평균 함대 활동"
|
||||
|
||||
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkstatisticsview.html:6
|
||||
msgid "Fatlink statistics"
|
||||
msgstr "플릿활동추적 통계"
|
||||
msgstr "함대 활동 통계"
|
||||
|
||||
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkstatisticsview.html:22
|
||||
msgid "Ticker"
|
||||
@@ -531,7 +532,7 @@ msgstr "참여 자료"
|
||||
|
||||
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkview.html:14
|
||||
msgid "Most recent clicked fatlinks"
|
||||
msgstr "가장 최근에 클릭한 플릿활동추적 링크"
|
||||
msgstr "가장 최근에 클릭한 함대 활동 링크"
|
||||
|
||||
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkview.html:19
|
||||
msgid "Personal statistics"
|
||||
@@ -539,11 +540,11 @@ msgstr "개인별 통계"
|
||||
|
||||
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkview.html:48
|
||||
msgid "No fleet activity on record."
|
||||
msgstr "플릿 활동기록이 없음"
|
||||
msgstr "함대 활동 기록이 없음"
|
||||
|
||||
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkview.html:55
|
||||
msgid "Most recent fatlinks"
|
||||
msgstr "가장 최근의 플릿활동추적 링크"
|
||||
msgstr "가장 최근의 함대 활동 링크"
|
||||
|
||||
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkview.html:60
|
||||
msgid "View statistics"
|
||||
@@ -551,27 +552,27 @@ msgstr "통계 보기"
|
||||
|
||||
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkview.html:97
|
||||
msgid "No created fatlinks on record."
|
||||
msgstr "생성된 플릿활동추적 링크 기록이 없음"
|
||||
msgstr "생성된 함대 활동 링크 기록이 없음"
|
||||
|
||||
#: allianceauth/fleetactivitytracking/views.py:280
|
||||
msgid "Fleet participation registered."
|
||||
msgstr "플릿 참여 등록됨"
|
||||
msgstr "함대 참여 등록됨"
|
||||
|
||||
#: allianceauth/fleetactivitytracking/views.py:296
|
||||
msgid "FAT link has expired."
|
||||
msgstr "플릿활동추적 링크 기한만료"
|
||||
msgstr "함대 활동 링크 기한만료"
|
||||
|
||||
#: allianceauth/groupmanagement/admin.py:104
|
||||
msgid "This name has been reserved and can not be used for groups."
|
||||
msgstr ""
|
||||
msgstr "이 이름은 이미 할당되었고 그룹의 이름으로 사용될 수 없습니다."
|
||||
|
||||
#: allianceauth/groupmanagement/admin.py:230
|
||||
msgid "(auto)"
|
||||
msgstr ""
|
||||
msgstr "(자동)"
|
||||
|
||||
#: allianceauth/groupmanagement/admin.py:239
|
||||
msgid "There already exists a group with that name."
|
||||
msgstr ""
|
||||
msgstr "이 이름을 가진 그룹이 이미 있습니다."
|
||||
|
||||
#: allianceauth/groupmanagement/auth_hooks.py:17
|
||||
#: allianceauth/groupmanagement/templates/groupmanagement/menu.html:14
|
||||
@@ -584,10 +585,12 @@ msgid ""
|
||||
"group.<br>Used for groups such as Members, Corp_*, Alliance_* "
|
||||
"etc.<br><b>Overrides Hidden and Open options when selected.</b>"
|
||||
msgstr ""
|
||||
"시스템 그룹, 유저들은 이 그룹을 보거나, 참여하거나, 지원할 수 없습니다. <br>멤버, 코퍼레이션_*, 얼라이언스_* 등에 "
|
||||
"사용됨.<br><b>선택된 경우 비공개와 공개 옵션을 무시함.</b>"
|
||||
|
||||
#: allianceauth/groupmanagement/models.py:110
|
||||
msgid "Group is hidden from users but can still join with the correct link."
|
||||
msgstr ""
|
||||
msgstr "비공개 그룹이지만 링크를 통해 참여할 수 있음."
|
||||
|
||||
#: allianceauth/groupmanagement/models.py:116
|
||||
msgid ""
|
||||
@@ -670,7 +673,7 @@ msgstr "감사 기록"
|
||||
#: allianceauth/permissions_tool/templates/permissions_tool/audit.html:13
|
||||
#: allianceauth/timerboard/templates/timerboard/index_button.html:3
|
||||
msgid "Back"
|
||||
msgstr "돌아가기"
|
||||
msgstr "뒤로"
|
||||
|
||||
#: allianceauth/groupmanagement/templates/groupmanagement/audit.html:28
|
||||
msgid "Date/Time"
|
||||
@@ -984,15 +987,15 @@ msgstr "문자열 검색"
|
||||
#: allianceauth/hrapplications/templates/hrapplications/corpchoice.html:5
|
||||
#: allianceauth/hrapplications/templates/hrapplications/corpchoice.html:8
|
||||
msgid "Choose a Corp"
|
||||
msgstr "콥 선택"
|
||||
msgstr "코퍼레이션 선택"
|
||||
|
||||
#: allianceauth/hrapplications/templates/hrapplications/corpchoice.html:11
|
||||
msgid "Available Corps"
|
||||
msgstr "사용 가능한 콥"
|
||||
msgstr "사용 가능한 코퍼레이션"
|
||||
|
||||
#: allianceauth/hrapplications/templates/hrapplications/corpchoice.html:23
|
||||
msgid "No corps are accepting applications at this time."
|
||||
msgstr "현재 입사지원 가능한 콥이 없습니다."
|
||||
msgstr "현재 입사지원 가능한 코퍼레이션이 없습니다."
|
||||
|
||||
#: allianceauth/hrapplications/templates/hrapplications/create.html:5
|
||||
#: allianceauth/hrapplications/templates/hrapplications/create.html:8
|
||||
@@ -1222,7 +1225,7 @@ msgstr "모든 읽은 알림을 삭제했습니다."
|
||||
|
||||
#: allianceauth/optimer/auth_hooks.py:10
|
||||
msgid "Fleet Operations"
|
||||
msgstr "플릿 옵"
|
||||
msgstr "함대 옵"
|
||||
|
||||
#: allianceauth/optimer/form.py:12
|
||||
#: allianceauth/optimer/templates/optimer/fleetoptable.html:11
|
||||
@@ -1246,7 +1249,7 @@ msgstr ""
|
||||
#: allianceauth/optimer/form.py:17
|
||||
#: allianceauth/srp/templates/srp/management.html:40
|
||||
msgid "Fleet Commander"
|
||||
msgstr "플릿 커맨더"
|
||||
msgstr "함대 커맨더"
|
||||
|
||||
#: allianceauth/optimer/form.py:22 allianceauth/srp/form.py:14
|
||||
#: allianceauth/srp/templates/srp/data.html:93
|
||||
@@ -1279,11 +1282,11 @@ msgstr "FC"
|
||||
|
||||
#: allianceauth/optimer/templates/optimer/management.html:6
|
||||
msgid "Fleet Operation Management"
|
||||
msgstr "플릿 옵 관리"
|
||||
msgstr "함대 옵 관리"
|
||||
|
||||
#: allianceauth/optimer/templates/optimer/management.html:11
|
||||
msgid "Fleet Operation Timers"
|
||||
msgstr "플릿 옵 타이머"
|
||||
msgstr "함대 옵 타이머"
|
||||
|
||||
#: allianceauth/optimer/templates/optimer/management.html:21
|
||||
#: allianceauth/timerboard/templates/timerboard/view.html:23
|
||||
@@ -1312,11 +1315,11 @@ msgstr "최근 지나간 옵 타이머가 없습니다."
|
||||
#: allianceauth/optimer/templates/optimer/update.html:16
|
||||
#: allianceauth/optimer/templates/optimer/update.html:28
|
||||
msgid "Update Fleet Operation"
|
||||
msgstr "플릿 옵 수정"
|
||||
msgstr "함대 옵 수정"
|
||||
|
||||
#: allianceauth/optimer/templates/optimer/update.html:22
|
||||
msgid "Fleet Operation Does Not Exist"
|
||||
msgstr "존재하지 않는 플릿 옵"
|
||||
msgstr "존재하지 않는 함대 옵"
|
||||
|
||||
#: allianceauth/optimer/views.py:69
|
||||
#, python-format
|
||||
@@ -1434,23 +1437,23 @@ msgstr "서드파티"
|
||||
|
||||
#: allianceauth/services/forms.py:6
|
||||
msgid "Name of Fleet:"
|
||||
msgstr "플릿 이름:"
|
||||
msgstr "함대 이름:"
|
||||
|
||||
#: allianceauth/services/forms.py:7
|
||||
msgid "Fleet Commander:"
|
||||
msgstr "플릿 커맨더:"
|
||||
msgstr "함대 커맨더:"
|
||||
|
||||
#: allianceauth/services/forms.py:8
|
||||
msgid "Fleet Comms:"
|
||||
msgstr "플릿 음성 채널:"
|
||||
msgstr "함대 음성 채널:"
|
||||
|
||||
#: allianceauth/services/forms.py:9
|
||||
msgid "Fleet Type:"
|
||||
msgstr "플릿 타입:"
|
||||
msgstr "함대 타입:"
|
||||
|
||||
#: allianceauth/services/forms.py:10
|
||||
msgid "Ship Priorities:"
|
||||
msgstr "플릿 우선도:"
|
||||
msgstr "함대 우선도:"
|
||||
|
||||
#: allianceauth/services/forms.py:11
|
||||
msgid "Formup Location:"
|
||||
@@ -1595,7 +1598,7 @@ msgstr "재버 방송"
|
||||
|
||||
#: allianceauth/services/modules/openfire/auth_hooks.py:94
|
||||
msgid "Fleet Broadcast Formatter"
|
||||
msgstr "플릿 신호 설정"
|
||||
msgstr "함대 신호 설정"
|
||||
|
||||
#: allianceauth/services/modules/openfire/forms.py:7
|
||||
msgid "Message"
|
||||
@@ -1749,11 +1752,11 @@ msgstr "XenForo 비밀번호 변경 완료"
|
||||
|
||||
#: allianceauth/services/templates/services/fleetformattertool.html:6
|
||||
msgid "Fleet Formatter Tool"
|
||||
msgstr "플릿 구성 도구"
|
||||
msgstr "함대 구성 도구"
|
||||
|
||||
#: allianceauth/services/templates/services/fleetformattertool.html:11
|
||||
msgid "Fleet Broadcast Formatter Tool"
|
||||
msgstr "플릿 브로드캐스트 설정 도구"
|
||||
msgstr "함대 브로드캐스트 설정 도구"
|
||||
|
||||
#: allianceauth/services/templates/services/fleetformattertool.html:24
|
||||
msgid "Format"
|
||||
@@ -1814,12 +1817,12 @@ msgstr "SRP"
|
||||
#: allianceauth/srp/form.py:9
|
||||
#: allianceauth/srp/templates/srp/management.html:38
|
||||
msgid "Fleet Time"
|
||||
msgstr "플릿 시간"
|
||||
msgstr "함대 시간"
|
||||
|
||||
#: allianceauth/srp/form.py:10
|
||||
#: allianceauth/srp/templates/srp/management.html:39
|
||||
msgid "Fleet Doctrine"
|
||||
msgstr "플릿 독트린"
|
||||
msgstr "함대 독트린"
|
||||
|
||||
#: allianceauth/srp/form.py:16
|
||||
msgid "Killboard Link (zkillboard.com or kb.evetools.org)"
|
||||
@@ -1839,12 +1842,12 @@ msgstr "사후조치 보고서 링크"
|
||||
|
||||
#: allianceauth/srp/templates/srp/add.html:6
|
||||
msgid "SRP Fleet Create"
|
||||
msgstr "SRP 보상 플릿 생성"
|
||||
msgstr "SRP 보상 함대 생성"
|
||||
|
||||
#: allianceauth/srp/templates/srp/add.html:14
|
||||
#: allianceauth/srp/templates/srp/add.html:24
|
||||
msgid "Create SRP Fleet"
|
||||
msgstr "SRP 보상 플릿 생성"
|
||||
msgstr "SRP 보상 함대 생성"
|
||||
|
||||
#: allianceauth/srp/templates/srp/add.html:27
|
||||
msgid "Give this link to the line members"
|
||||
@@ -1852,7 +1855,7 @@ msgstr "이 링크를 직계 멤버들에게 전달"
|
||||
|
||||
#: allianceauth/srp/templates/srp/data.html:52
|
||||
msgid "SRP Fleet Data"
|
||||
msgstr "SRP 보상 플릿 데이터"
|
||||
msgstr "SRP 보상 함대 데이터"
|
||||
|
||||
#: allianceauth/srp/templates/srp/data.html:57
|
||||
msgid "Mark Incomplete"
|
||||
@@ -1908,7 +1911,7 @@ msgstr "작성 시간"
|
||||
|
||||
#: allianceauth/srp/templates/srp/data.html:178
|
||||
msgid "No SRP requests for this fleet."
|
||||
msgstr "이 플릿에는 SRP 보상 요청이 없습니다."
|
||||
msgstr "이 함대에는 SRP 보상 요청이 없습니다."
|
||||
|
||||
#: allianceauth/srp/templates/srp/management.html:8
|
||||
msgid "Srp Management"
|
||||
@@ -1924,19 +1927,19 @@ msgstr "모두 조회하기"
|
||||
|
||||
#: allianceauth/srp/templates/srp/management.html:23
|
||||
msgid "Add SRP Fleet"
|
||||
msgstr "SRP 보상 플릿 추가"
|
||||
msgstr "SRP 보상 함대 추가"
|
||||
|
||||
#: allianceauth/srp/templates/srp/management.html:41
|
||||
msgid "Fleet AAR"
|
||||
msgstr "플릿 사후처리 보고서"
|
||||
msgstr "함대 사후처리 보고서"
|
||||
|
||||
#: allianceauth/srp/templates/srp/management.html:42
|
||||
msgid "Fleet SRP Code"
|
||||
msgstr "플릿 SRP 보상 코드"
|
||||
msgstr "함대 SRP 보상 코드"
|
||||
|
||||
#: allianceauth/srp/templates/srp/management.html:43
|
||||
msgid "Fleet ISK Cost"
|
||||
msgstr "플릿 ISK 비용"
|
||||
msgstr "함대 ISK 비용"
|
||||
|
||||
#: allianceauth/srp/templates/srp/management.html:44
|
||||
msgid "SRP Status"
|
||||
@@ -1983,37 +1986,37 @@ msgstr "사후처리 보고서 링크 업데이트"
|
||||
|
||||
#: allianceauth/srp/templates/srp/update.html:17
|
||||
msgid "SRP Fleet Does Not Exist"
|
||||
msgstr "SRP 보상 플릿이 존재하지 않습니다."
|
||||
msgstr "SRP 보상 함대이 존재하지 않습니다."
|
||||
|
||||
#: allianceauth/srp/views.py:85
|
||||
#, python-format
|
||||
msgid "Created SRP fleet %(fleetname)s."
|
||||
msgstr "SRP 보상 플릿 %(fleetname)s 생성 완료"
|
||||
msgstr "SRP 보상 함대 %(fleetname)s 생성 완료"
|
||||
|
||||
#: allianceauth/srp/views.py:103
|
||||
#, python-format
|
||||
msgid "Removed SRP fleet %(fleetname)s."
|
||||
msgstr "SRP 보상 플릿 %(fleetname)s삭제 완료"
|
||||
msgstr "SRP 보상 함대 %(fleetname)s삭제 완료"
|
||||
|
||||
#: allianceauth/srp/views.py:115
|
||||
#, python-format
|
||||
msgid "Disabled SRP fleet %(fleetname)s."
|
||||
msgstr "SRP 보상 플릿 %(fleetname)s비활성화 완료"
|
||||
msgstr "SRP 보상 함대 %(fleetname)s비활성화 완료"
|
||||
|
||||
#: allianceauth/srp/views.py:127
|
||||
#, python-format
|
||||
msgid "Enabled SRP fleet %(fleetname)s."
|
||||
msgstr "SRP 보상 플릿 %(fleetname)s 활성화 완료"
|
||||
msgstr "SRP 보상 함대 %(fleetname)s 활성화 완료"
|
||||
|
||||
#: allianceauth/srp/views.py:140
|
||||
#, python-format
|
||||
msgid "Marked SRP fleet %(fleetname)s as completed."
|
||||
msgstr "SRP 보상 플릿 %(fleetname)s 을 완료된 것으로 표시"
|
||||
msgstr "SRP 보상 함대 %(fleetname)s 을 완료된 것으로 표시"
|
||||
|
||||
#: allianceauth/srp/views.py:153
|
||||
#, python-format
|
||||
msgid "Marked SRP fleet %(fleetname)s as incomplete."
|
||||
msgstr "SRP 보상 플릿 %(fleetname)s 을 미완료된 것으로 표시"
|
||||
msgstr "SRP 보상 함대 %(fleetname)s 을 미완료된 것으로 표시"
|
||||
|
||||
#: allianceauth/srp/views.py:165
|
||||
#, python-format
|
||||
@@ -2079,7 +2082,7 @@ msgstr "SRP 보상 요청 %(requestid)s을 찾을 수 없습니다. "
|
||||
#: allianceauth/srp/views.py:360
|
||||
#, python-format
|
||||
msgid "Saved changes to SRP fleet %(fleetname)s"
|
||||
msgstr "SRP 보상 요청 플릿 %(fleetname)s의 변경 사항이 저장되었습니다."
|
||||
msgstr "SRP 보상 요청 함대 %(fleetname)s의 변경 사항이 저장되었습니다."
|
||||
|
||||
#: allianceauth/templates/allianceauth/admin-status/overview.html:6
|
||||
msgid "Alliance Auth Notifications"
|
||||
@@ -2229,7 +2232,7 @@ msgstr "중요"
|
||||
|
||||
#: allianceauth/timerboard/form.py:70
|
||||
msgid "Corp-Restricted"
|
||||
msgstr "콥 제한"
|
||||
msgstr "코퍼레이션 제한"
|
||||
|
||||
#: allianceauth/timerboard/models.py:14
|
||||
msgid "Not Specified"
|
||||
@@ -2294,7 +2297,7 @@ msgstr "스트럭처 타이머"
|
||||
|
||||
#: allianceauth/timerboard/templates/timerboard/view.html:28
|
||||
msgid "Corp Timers"
|
||||
msgstr "콥 타이머"
|
||||
msgstr "코퍼레이션 타이머"
|
||||
|
||||
#: allianceauth/timerboard/templates/timerboard/view.html:35
|
||||
#: allianceauth/timerboard/templates/timerboard/view.html:202
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import logging
|
||||
from functools import partial
|
||||
|
||||
from django.contrib.auth.models import User, Group, Permission
|
||||
from django.core.exceptions import ObjectDoesNotExist
|
||||
@@ -8,7 +9,7 @@ from django.db.models.signals import pre_delete
|
||||
from django.db.models.signals import pre_save
|
||||
from django.dispatch import receiver
|
||||
from .hooks import ServicesHook
|
||||
from .tasks import disable_user
|
||||
from .tasks import disable_user, update_groups_for_user
|
||||
|
||||
from allianceauth.authentication.models import State, UserProfile
|
||||
from allianceauth.authentication.signals import state_changed
|
||||
@@ -19,21 +20,27 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
@receiver(m2m_changed, sender=User.groups.through)
|
||||
def m2m_changed_user_groups(sender, instance, action, *args, **kwargs):
|
||||
logger.debug(f"Received m2m_changed from {instance} groups with action {action}")
|
||||
|
||||
def trigger_service_group_update():
|
||||
logger.debug("Triggering service group update for %s" % instance)
|
||||
# Iterate through Service hooks
|
||||
for svc in ServicesHook.get_services():
|
||||
try:
|
||||
svc.validate_user(instance)
|
||||
svc.update_groups(instance)
|
||||
except:
|
||||
logger.exception(f'Exception running update_groups for services module {svc} on user {instance}')
|
||||
|
||||
if instance.pk and (action == "post_add" or action == "post_remove" or action == "post_clear"):
|
||||
logger.debug("Waiting for commit to trigger service group update for %s" % instance)
|
||||
transaction.on_commit(trigger_service_group_update)
|
||||
logger.debug(
|
||||
"%s: Received m2m_changed from groups with action %s", instance, action
|
||||
)
|
||||
if instance.pk and (
|
||||
action == "post_add" or action == "post_remove" or action == "post_clear"
|
||||
):
|
||||
if isinstance(instance, User):
|
||||
logger.debug(
|
||||
"Waiting for commit to trigger service group update for %s", instance
|
||||
)
|
||||
transaction.on_commit(partial(update_groups_for_user.delay, instance.pk))
|
||||
elif (
|
||||
isinstance(instance, Group)
|
||||
and kwargs.get("model") is User
|
||||
and "pk_set" in kwargs
|
||||
):
|
||||
for user_pk in kwargs["pk_set"]:
|
||||
logger.debug(
|
||||
"%s: Waiting for commit to trigger service group update for user", user_pk
|
||||
)
|
||||
transaction.on_commit(partial(update_groups_for_user.delay, user_pk))
|
||||
|
||||
|
||||
@receiver(m2m_changed, sender=User.user_permissions.through)
|
||||
|
||||
@@ -47,3 +47,20 @@ def disable_user(user):
|
||||
for svc in ServicesHook.get_services():
|
||||
if svc.service_active_for_user(user):
|
||||
svc.delete_user(user)
|
||||
|
||||
|
||||
@shared_task
|
||||
def update_groups_for_user(user_pk: int) -> None:
|
||||
"""Update groups for all services registered to a user."""
|
||||
user = User.objects.get(pk=user_pk)
|
||||
logger.debug("%s: Triggering service group update for user", user)
|
||||
for svc in ServicesHook.get_services():
|
||||
try:
|
||||
svc.validate_user(user)
|
||||
svc.update_groups(user)
|
||||
except Exception:
|
||||
logger.exception(
|
||||
'Exception running update_groups for services module %s on user %s',
|
||||
svc,
|
||||
user
|
||||
)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
from copy import deepcopy
|
||||
from unittest import mock
|
||||
|
||||
from django.test import TestCase
|
||||
from django.test import override_settings, TestCase, TransactionTestCase
|
||||
from django.contrib.auth.models import Group, Permission
|
||||
|
||||
from allianceauth.authentication.models import State
|
||||
@@ -9,6 +9,9 @@ from allianceauth.eveonline.models import EveCharacter
|
||||
from allianceauth.tests.auth_utils import AuthUtils
|
||||
|
||||
|
||||
MODULE_PATH = 'allianceauth.services.signals'
|
||||
|
||||
|
||||
class ServicesSignalsTestCase(TestCase):
|
||||
def setUp(self):
|
||||
self.member = AuthUtils.create_user('auth_member', disconnect_signals=True)
|
||||
@@ -17,17 +20,12 @@ class ServicesSignalsTestCase(TestCase):
|
||||
)
|
||||
self.none_user = AuthUtils.create_user('none_user', disconnect_signals=True)
|
||||
|
||||
@mock.patch('allianceauth.services.signals.transaction')
|
||||
@mock.patch('allianceauth.services.signals.ServicesHook')
|
||||
def test_m2m_changed_user_groups(self, services_hook, transaction):
|
||||
@mock.patch(MODULE_PATH + '.transaction', spec=True)
|
||||
@mock.patch(MODULE_PATH + '.update_groups_for_user', spec=True)
|
||||
def test_m2m_changed_user_groups(self, update_groups_for_user, transaction):
|
||||
"""
|
||||
Test that update_groups hook function is called on user groups change
|
||||
"""
|
||||
svc = mock.Mock()
|
||||
svc.update_groups.return_value = None
|
||||
svc.validate_user.return_value = None
|
||||
|
||||
services_hook.get_services.return_value = [svc]
|
||||
|
||||
# Overload transaction.on_commit so everything happens synchronously
|
||||
transaction.on_commit = lambda fn: fn()
|
||||
@@ -39,17 +37,11 @@ class ServicesSignalsTestCase(TestCase):
|
||||
self.member.save()
|
||||
|
||||
# Assert
|
||||
self.assertTrue(services_hook.get_services.called)
|
||||
self.assertTrue(update_groups_for_user.delay.called)
|
||||
args, _ = update_groups_for_user.delay.call_args
|
||||
self.assertEqual(self.member.pk, args[0])
|
||||
|
||||
self.assertTrue(svc.update_groups.called)
|
||||
args, kwargs = svc.update_groups.call_args
|
||||
self.assertEqual(self.member, args[0])
|
||||
|
||||
self.assertTrue(svc.validate_user.called)
|
||||
args, kwargs = svc.validate_user.call_args
|
||||
self.assertEqual(self.member, args[0])
|
||||
|
||||
@mock.patch('allianceauth.services.signals.disable_user')
|
||||
@mock.patch(MODULE_PATH + '.disable_user')
|
||||
def test_pre_delete_user(self, disable_user):
|
||||
"""
|
||||
Test that disable_member is called when a user is deleted
|
||||
@@ -60,7 +52,7 @@ class ServicesSignalsTestCase(TestCase):
|
||||
args, kwargs = disable_user.call_args
|
||||
self.assertEqual(self.none_user, args[0])
|
||||
|
||||
@mock.patch('allianceauth.services.signals.disable_user')
|
||||
@mock.patch(MODULE_PATH + '.disable_user')
|
||||
def test_pre_save_user_inactivation(self, disable_user):
|
||||
"""
|
||||
Test a user set inactive has disable_member called
|
||||
@@ -72,7 +64,7 @@ class ServicesSignalsTestCase(TestCase):
|
||||
args, kwargs = disable_user.call_args
|
||||
self.assertEqual(self.member, args[0])
|
||||
|
||||
@mock.patch('allianceauth.services.signals.disable_user')
|
||||
@mock.patch(MODULE_PATH + '.disable_user')
|
||||
def test_disable_services_on_loss_of_main_character(self, disable_user):
|
||||
"""
|
||||
Test a user set inactive has disable_member called
|
||||
@@ -84,8 +76,8 @@ class ServicesSignalsTestCase(TestCase):
|
||||
args, kwargs = disable_user.call_args
|
||||
self.assertEqual(self.member, args[0])
|
||||
|
||||
@mock.patch('allianceauth.services.signals.transaction')
|
||||
@mock.patch('allianceauth.services.signals.ServicesHook')
|
||||
@mock.patch(MODULE_PATH + '.transaction')
|
||||
@mock.patch(MODULE_PATH + '.ServicesHook')
|
||||
def test_m2m_changed_group_permissions(self, services_hook, transaction):
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
svc = mock.Mock()
|
||||
@@ -116,8 +108,8 @@ class ServicesSignalsTestCase(TestCase):
|
||||
args, kwargs = svc.validate_user.call_args
|
||||
self.assertEqual(self.member, args[0])
|
||||
|
||||
@mock.patch('allianceauth.services.signals.transaction')
|
||||
@mock.patch('allianceauth.services.signals.ServicesHook')
|
||||
@mock.patch(MODULE_PATH + '.transaction')
|
||||
@mock.patch(MODULE_PATH + '.ServicesHook')
|
||||
def test_m2m_changed_user_permissions(self, services_hook, transaction):
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
svc = mock.Mock()
|
||||
@@ -145,8 +137,8 @@ class ServicesSignalsTestCase(TestCase):
|
||||
args, kwargs = svc.validate_user.call_args
|
||||
self.assertEqual(self.member, args[0])
|
||||
|
||||
@mock.patch('allianceauth.services.signals.transaction')
|
||||
@mock.patch('allianceauth.services.signals.ServicesHook')
|
||||
@mock.patch(MODULE_PATH + '.transaction')
|
||||
@mock.patch(MODULE_PATH + '.ServicesHook')
|
||||
def test_m2m_changed_user_state_permissions(self, services_hook, transaction):
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
svc = mock.Mock()
|
||||
@@ -180,7 +172,7 @@ class ServicesSignalsTestCase(TestCase):
|
||||
args, kwargs = svc.validate_user.call_args
|
||||
self.assertEqual(self.member, args[0])
|
||||
|
||||
@mock.patch('allianceauth.services.signals.ServicesHook')
|
||||
@mock.patch(MODULE_PATH + '.ServicesHook')
|
||||
def test_state_changed_services_validation_and_groups_update(self, services_hook):
|
||||
"""Test a user changing state has service accounts validated and groups updated
|
||||
"""
|
||||
@@ -206,8 +198,7 @@ class ServicesSignalsTestCase(TestCase):
|
||||
args, kwargs = svc.update_groups.call_args
|
||||
self.assertEqual(self.member, args[0])
|
||||
|
||||
|
||||
@mock.patch('allianceauth.services.signals.ServicesHook')
|
||||
@mock.patch(MODULE_PATH + '.ServicesHook')
|
||||
def test_state_changed_services_validation_and_groups_update_1(self, services_hook):
|
||||
"""Test a user changing main has service accounts validated and sync updated
|
||||
"""
|
||||
@@ -238,7 +229,7 @@ class ServicesSignalsTestCase(TestCase):
|
||||
args, kwargs = svc.sync_nickname.call_args
|
||||
self.assertEqual(self.member, args[0])
|
||||
|
||||
@mock.patch('allianceauth.services.signals.ServicesHook')
|
||||
@mock.patch(MODULE_PATH + '.ServicesHook')
|
||||
def test_state_changed_services_validation_and_groups_update_2(self, services_hook):
|
||||
"""Test a user changing main has service does not have accounts validated
|
||||
and sync updated if the new main is equal to the old main
|
||||
@@ -260,3 +251,71 @@ class ServicesSignalsTestCase(TestCase):
|
||||
self.assertFalse(services_hook.get_services.called)
|
||||
self.assertFalse(svc.validate_user.called)
|
||||
self.assertFalse(svc.sync_nickname.called)
|
||||
|
||||
|
||||
@mock.patch(
|
||||
"allianceauth.services.modules.mumble.auth_hooks.MumbleService.update_groups"
|
||||
)
|
||||
@override_settings(CELERY_ALWAYS_EAGER=True, CELERY_EAGER_PROPAGATES_EXCEPTIONS=True)
|
||||
class TestUserGroupBulkUpdate(TransactionTestCase):
|
||||
def test_should_run_user_service_check_when_group_added_to_user(
|
||||
self, mock_update_groups
|
||||
):
|
||||
# given
|
||||
user = AuthUtils.create_user("Bruce Wayne")
|
||||
AuthUtils.add_main_character_2(user, "Bruce Wayne", 1001)
|
||||
group = Group.objects.create(name="Group")
|
||||
mock_update_groups.reset_mock()
|
||||
# when
|
||||
user.groups.add(group)
|
||||
# then
|
||||
users_updated = {obj[0][0] for obj in mock_update_groups.call_args_list}
|
||||
self.assertSetEqual(users_updated, {user})
|
||||
|
||||
def test_should_run_user_service_check_when_multiple_groups_are_added_to_user(
|
||||
self, mock_update_groups
|
||||
):
|
||||
# given
|
||||
user = AuthUtils.create_user("Bruce Wayne")
|
||||
AuthUtils.add_main_character_2(user, "Bruce Wayne", 1001)
|
||||
group_1 = Group.objects.create(name="Group 1")
|
||||
group_2 = Group.objects.create(name="Group 2")
|
||||
mock_update_groups.reset_mock()
|
||||
# when
|
||||
user.groups.add(group_1, group_2)
|
||||
# then
|
||||
users_updated = {obj[0][0] for obj in mock_update_groups.call_args_list}
|
||||
self.assertSetEqual(users_updated, {user})
|
||||
|
||||
def test_should_run_user_service_check_when_user_added_to_group(
|
||||
self, mock_update_groups
|
||||
):
|
||||
# given
|
||||
user = AuthUtils.create_user("Bruce Wayne")
|
||||
AuthUtils.add_main_character_2(user, "Bruce Wayne", 1001)
|
||||
group = Group.objects.create(name="Group")
|
||||
mock_update_groups.reset_mock()
|
||||
# when
|
||||
group.user_set.add(user)
|
||||
# then
|
||||
users_updated = {obj[0][0] for obj in mock_update_groups.call_args_list}
|
||||
self.assertSetEqual(users_updated, {user})
|
||||
|
||||
def test_should_run_user_service_check_when_multiple_users_are_added_to_group(
|
||||
self, mock_update_groups
|
||||
):
|
||||
# given
|
||||
user_1 = AuthUtils.create_user("Bruce Wayne")
|
||||
AuthUtils.add_main_character_2(user_1, "Bruce Wayne", 1001)
|
||||
user_2 = AuthUtils.create_user("Peter Parker")
|
||||
AuthUtils.add_main_character_2(user_2, "Peter Parker", 1002)
|
||||
user_3 = AuthUtils.create_user("Lex Luthor")
|
||||
AuthUtils.add_main_character_2(user_3, "Lex Luthor", 1011)
|
||||
group = Group.objects.create(name="Group")
|
||||
user_1.groups.add(group)
|
||||
mock_update_groups.reset_mock()
|
||||
# when
|
||||
group.user_set.add(user_2, user_3)
|
||||
# then
|
||||
users_updated = {obj[0][0] for obj in mock_update_groups.call_args_list}
|
||||
self.assertSetEqual(users_updated, {user_2, user_3})
|
||||
|
||||
@@ -3,32 +3,50 @@ from unittest import mock
|
||||
from celery_once import AlreadyQueued
|
||||
|
||||
from django.core.cache import cache
|
||||
from django.test import TestCase
|
||||
from django.test import override_settings, TestCase
|
||||
|
||||
from allianceauth.tests.auth_utils import AuthUtils
|
||||
from allianceauth.services.tasks import validate_services
|
||||
from allianceauth.services.tasks import validate_services, update_groups_for_user
|
||||
|
||||
from ..tasks import DjangoBackend
|
||||
|
||||
|
||||
@override_settings(CELERY_ALWAYS_EAGER=True, CELERY_EAGER_PROPAGATES_EXCEPTIONS=True)
|
||||
class ServicesTasksTestCase(TestCase):
|
||||
def setUp(self):
|
||||
self.member = AuthUtils.create_user('auth_member')
|
||||
|
||||
@mock.patch('allianceauth.services.tasks.ServicesHook')
|
||||
def test_validate_services(self, services_hook):
|
||||
# given
|
||||
svc = mock.Mock()
|
||||
svc.validate_user.return_value = None
|
||||
|
||||
services_hook.get_services.return_value = [svc]
|
||||
|
||||
# when
|
||||
validate_services.delay(self.member.pk)
|
||||
|
||||
# then
|
||||
self.assertTrue(services_hook.get_services.called)
|
||||
self.assertTrue(svc.validate_user.called)
|
||||
args, kwargs = svc.validate_user.call_args
|
||||
args, _ = svc.validate_user.call_args
|
||||
self.assertEqual(self.member, args[0]) # Assert correct user is passed to service hook function
|
||||
|
||||
@mock.patch('allianceauth.services.tasks.ServicesHook')
|
||||
def test_update_groups_for_user(self, services_hook):
|
||||
# given
|
||||
svc = mock.Mock()
|
||||
svc.validate_user.return_value = None
|
||||
services_hook.get_services.return_value = [svc]
|
||||
# when
|
||||
update_groups_for_user.delay(self.member.pk)
|
||||
# then
|
||||
self.assertTrue(services_hook.get_services.called)
|
||||
self.assertTrue(svc.validate_user.called)
|
||||
args, _ = svc.validate_user.call_args
|
||||
self.assertEqual(self.member, args[0]) # Assert correct user
|
||||
self.assertTrue(svc.update_groups.called)
|
||||
args, _ = svc.update_groups.call_args
|
||||
self.assertEqual(self.member, args[0]) # Assert correct user
|
||||
|
||||
|
||||
class TestDjangoBackend(TestCase):
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
PROTOCOL=https://
|
||||
AUTH_SUBDOMAIN=%AUTH_SUBDOMAIN%
|
||||
DOMAIN=%DOMAIN%
|
||||
AA_DOCKER_TAG=registry.gitlab.com/allianceauth/allianceauth/auth:v3.0.0a5
|
||||
AA_DOCKER_TAG=registry.gitlab.com/allianceauth/allianceauth/auth:v3.0.0b1
|
||||
|
||||
# Nginx Proxy Manager
|
||||
PROXY_HTTP_PORT=80
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
FROM python:3.9-slim
|
||||
ARG AUTH_VERSION=v3.0.0a5
|
||||
ARG AUTH_VERSION=v3.0.0b1
|
||||
ARG AUTH_PACKAGE=allianceauth==${AUTH_VERSION}
|
||||
ENV VIRTUAL_ENV=/opt/venv
|
||||
ENV AUTH_USER=allianceauth
|
||||
|
||||
@@ -8,7 +8,7 @@ You should have the following available on the system you are using to set this
|
||||
|
||||
## Setup Guide
|
||||
|
||||
1. run `bash <(curl -s https://gitlab.com/allianceauth/allianceauth/-/raw/v2.11.x/docker/scripts/download.sh)`. This will download all the files you need to install auth and place them in a directory named `aa-docker`. Feel free to rename/move this folder.
|
||||
1. run `bash <(curl -s https://gitlab.com/allianceauth/allianceauth/-/raw/master/docker/scripts/download.sh)`. This will download all the files you need to install auth and place them in a directory named `aa-docker`. Feel free to rename/move this folder.
|
||||
1. run `./scripts/prepare-env.sh` to set up your environment
|
||||
1. (optional) Change `PROTOCOL` to `http://` if not using SSL in `.env`
|
||||
1. run `docker-compose --env-file=.env up -d` (NOTE: if this command hangs, follow the instructions [here](https://www.digitalocean.com/community/tutorials/how-to-setup-additional-entropy-for-cloud-servers-using-haveged))
|
||||
|
||||
114
docs/_static/css/rtd_dark.css
vendored
Normal file
114
docs/_static/css/rtd_dark.css
vendored
Normal file
@@ -0,0 +1,114 @@
|
||||
/*!
|
||||
* @name Readthedocs
|
||||
* @namespace http://userstyles.org
|
||||
* @description Styles the documentation pages hosted on Readthedocs.io
|
||||
* @author Anthony Post
|
||||
* @homepage https://userstyles.org/styles/142968
|
||||
* @version 0.20170529055029
|
||||
*
|
||||
* Modified by Aloïs Dreyfus: 20200527-1037
|
||||
* Modified by Erik Kalkoken: 20220615
|
||||
*/
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
a:visited {
|
||||
color: #bf84d8;
|
||||
}
|
||||
|
||||
pre {
|
||||
background-color: #2d2d2d !important;
|
||||
}
|
||||
|
||||
.wy-nav-content {
|
||||
background: #3c3c3c;
|
||||
color: aliceblue;
|
||||
}
|
||||
|
||||
.method dt, .class dt, .data dt, .attribute dt, .function dt,
|
||||
.descclassname, .descname {
|
||||
background-color: #525252 !important;
|
||||
color: white !important;
|
||||
}
|
||||
|
||||
.toc-backref {
|
||||
color: grey !important;
|
||||
}
|
||||
|
||||
code.literal {
|
||||
background-color: #2d2d2d !important;
|
||||
border: 1px solid #6d6d6d !important;
|
||||
}
|
||||
|
||||
.wy-nav-content-wrap {
|
||||
background-color: rgba(0, 0, 0, 0.6) !important;
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
background-color: #191919 !important;
|
||||
}
|
||||
|
||||
.sidebar-title {
|
||||
background-color: #2b2b2b !important;
|
||||
}
|
||||
|
||||
.xref, .py-meth {
|
||||
color: #7ec3e6 !important;
|
||||
}
|
||||
|
||||
.admonition, .note {
|
||||
background-color: #2d2d2d !important;
|
||||
}
|
||||
|
||||
.wy-side-nav-search {
|
||||
background-color: inherit;
|
||||
border-bottom: 1px solid #fcfcfc;
|
||||
}
|
||||
|
||||
.wy-table thead, .rst-content table.docutils thead, .rst-content table.field-list thead {
|
||||
background-color: #b9b9b9;
|
||||
}
|
||||
|
||||
.wy-table thead th, .rst-content table.docutils thead th, .rst-content table.field-list thead th {
|
||||
border: solid 2px #e1e4e5;
|
||||
}
|
||||
|
||||
.wy-table thead p, .rst-content table.docutils thead p, .rst-content table.field-list thead p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.wy-table-odd td, .wy-table-striped tr:nth-child(2n-1) td, .rst-content table.docutils:not(.field-list) tr:nth-child(2n-1) td {
|
||||
background-color: #343131;
|
||||
}
|
||||
|
||||
.highlight .m {
|
||||
color: inherit
|
||||
}
|
||||
|
||||
/* Literal.Number */
|
||||
.highlight .nv {
|
||||
color: #3a7ca8
|
||||
}
|
||||
|
||||
/* Name.Variable */
|
||||
|
||||
body {
|
||||
text-align: justify;
|
||||
}
|
||||
|
||||
.rst-content .section .admonition ul {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
li.toctree-l1 {
|
||||
margin-top: 5px;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.wy-menu-vertical li code {
|
||||
color: #E74C3C;
|
||||
}
|
||||
|
||||
.wy-menu-vertical .xref {
|
||||
color: #2980B9 !important;
|
||||
}
|
||||
}
|
||||
@@ -111,6 +111,7 @@ html_theme_options = {
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
html_static_path = ['_static']
|
||||
html_css_files = ["css/rtd_dark.css"]
|
||||
|
||||
|
||||
# -- Options for HTMLHelp output ------------------------------------------
|
||||
|
||||
@@ -150,12 +150,14 @@ sudo redis-server --daemonize yes
|
||||
|
||||
```eval_rst
|
||||
.. note::
|
||||
WSL does not have an init.d service, so it will not automatically start your services such as MySQL and Redis when you boot your Windows machine. For convenience we recommend putting the commands for starting these services in a bash script. Here is an example: ::
|
||||
WSL does not have an init.d service, so it will not automatically start your services such as MySQL and Redis when you boot your Windows machine. For convenience we recommend putting the commands for starting these services in a bash script. Here is an example:
|
||||
|
||||
#/bin/bash
|
||||
# start services for AA dev
|
||||
sudo service mysql start
|
||||
sudo redis-server --daemonize yes
|
||||
::
|
||||
|
||||
#/bin/bash
|
||||
# start services for AA dev
|
||||
sudo service mysql start
|
||||
sudo redis-server --daemonize yes
|
||||
|
||||
In addition it is possible to configure Windows to automatically start WSL services, but that procedure goes beyond the scopes of this guide.
|
||||
```
|
||||
|
||||
@@ -1,15 +1,27 @@
|
||||
=============
|
||||
Template Tags
|
||||
=============
|
||||
=======================
|
||||
Template tags & filters
|
||||
=======================
|
||||
|
||||
The following template tags are available to be used by all apps. To use them just load the respeetive template tag in your template like so:
|
||||
The following template tags and filters are available to be used by all apps. To use them just load them into your template like so:
|
||||
|
||||
.. code-block:: html
|
||||
.. code-block:: html+django
|
||||
|
||||
{% load evelinks %}
|
||||
|
||||
|
||||
Template Filters
|
||||
================
|
||||
|
||||
evelinks
|
||||
========
|
||||
--------
|
||||
|
||||
Example for using an evelinks filter to render an alliance logo:
|
||||
|
||||
|
||||
.. code-block:: html+django
|
||||
|
||||
<img src="{{ alliance_id|alliance_logo_url }}">
|
||||
|
||||
|
||||
.. automodule:: allianceauth.eveonline.templatetags.evelinks
|
||||
:members:
|
||||
|
||||
@@ -2,15 +2,17 @@
|
||||
sphinx>=4.4.0,<5.0.0
|
||||
sphinx_rtd_theme>=1.0.0,<2.0.0
|
||||
recommonmark==0.7.1
|
||||
Jinja2<3.1
|
||||
docutils==0.16
|
||||
|
||||
# Autodoc dependencies
|
||||
django>=4.0.2,<5.0.0
|
||||
django-celery-beat>=2.0.0
|
||||
django-bootstrap-form
|
||||
django-sortedm2m
|
||||
django-esi>=4.0.0a1,<5
|
||||
django-redis>=5.2.0<6.0.0
|
||||
celery>=5.2.0,<6.0.0
|
||||
celery_once>=3.0.1
|
||||
django>=4.0.5,<5.0.0
|
||||
django-bootstrap-form
|
||||
django-celery-beat>=2.3.0
|
||||
django-esi>=4.0.1
|
||||
django-redis>=5.2.0,<6.0.0
|
||||
django-sortedm2m
|
||||
passlib
|
||||
redis>=4.0.0,<5.0.0
|
||||
|
||||
10
tox.ini
10
tox.ini
@@ -2,7 +2,7 @@
|
||||
isolated_build = True
|
||||
skipsdist = true
|
||||
usedevelop = true
|
||||
envlist = py{38,39,310,311}-{all,core}
|
||||
envlist = py{38,39,310,311}-{all,core}, docs
|
||||
|
||||
[testenv]
|
||||
setenv =
|
||||
@@ -22,3 +22,11 @@ commands =
|
||||
core: coverage run runtests.py allianceauth.authentication.tests.test_app_settings -v 2 --debug-mode
|
||||
all: coverage report -m
|
||||
all: coverage xml
|
||||
|
||||
[testenv:docs]
|
||||
description = invoke sphinx-build to build the HTML docs
|
||||
basepython = python3.9
|
||||
deps = -r{toxinidir}/docs/requirements.txt
|
||||
install_command =
|
||||
commands =
|
||||
sphinx-build -T -E -b html -d "{toxworkdir}/docs_doctree" -D language=en docs "{toxworkdir}/docs_out" {posargs}
|
||||
|
||||
Reference in New Issue
Block a user