Compare commits

..

57 Commits
v3.7.0 ... v3.x

Author SHA1 Message Date
Ariel Rin
054ef27fa4 Version Bump 3.8.1 2024-02-17 19:39:14 +10:00
Ariel Rin
97e224b8e6 Merge branch 'translations_7f31a07ccd4e4a66b1dd7b6bc2dbddb5' into 'master'
Updates for project Alliance Auth

See merge request allianceauth/allianceauth!1593
2024-02-17 09:30:43 +00:00
Ariel Rin
3b8fa415bc Updates for project Alliance Auth 2024-02-17 09:30:43 +00:00
Ariel Rin
b94fd7ed19 I18N Maintenance 2024-02-17 18:52:42 +10:00
Ariel Rin
d1dac61135 Merge branch 'translations_7f31a07ccd4e4a66b1dd7b6bc2dbddb5' into 'master'
Updates for project Alliance Auth

See merge request allianceauth/allianceauth!1563
2024-02-17 08:48:55 +00:00
Ariel Rin
d2a095217f Updates for project Alliance Auth 2024-02-17 08:48:55 +00:00
Ariel Rin
5e9b47cf79 Merge branch 'docs-improvements' into 'master'
Docs improvements

See merge request allianceauth/allianceauth!1574
2024-01-15 05:25:51 +00:00
Ariel Rin
853826c140 Merge branch 'add-email-timeout' into 'master'
Add email timeout

See merge request allianceauth/allianceauth!1580
2024-01-15 05:19:57 +00:00
ErikKalkoken
9c7de58989 Add email timeout 2024-01-02 11:48:27 +01:00
Ariel Rin
3de988369f Merge branch 'fix-orphan-tokens' into 'master'
Fix orphan tokens and remove unused messages from backends

Closes #1391

See merge request allianceauth/allianceauth!1570
2023-12-25 09:48:15 +00:00
Peter Pfeufer
6e3219fd1b [FIX] Grammar and spelling 2023-12-17 20:21:11 +01:00
Peter Pfeufer
8aeb061635 [ADD] Remark on how to stop Gunicorn when testing 2023-12-17 17:45:29 +01:00
Peter Pfeufer
84e2107b62 [CHANGE] Switch to adduser for Ubuntu
This will create the users' hoe directory and make it a no-login user in one command.
2023-12-17 17:42:08 +01:00
Ariel Rin
20fcf5efa4 Merge branch 'docs' into 'master'
Docs fixes

See merge request allianceauth/allianceauth!1569
2023-12-17 03:49:41 +00:00
colcrunch
c15b955d5e Make pre-commit happy 2023-12-11 18:37:35 -05:00
colcrunch
65e1545a66 Remove all references to messages as they are never relayed to the user. 2023-12-11 18:16:34 -05:00
colcrunch
c558a980e1 Add more detail to error message displayed on failed alt login. 2023-12-11 18:14:09 -05:00
colcrunch
bd8ef84862 Delete tokens that can not be used for logins. 2023-12-11 18:13:24 -05:00
Ariel Rin
42e96d2f14 close the python section to fix mysql tabs/steps 2023-12-11 22:15:12 +10:00
Ariel Rin
23a3dd1ab9 Merge branch 'fantabular' into 'master'
Doc Modernisation

Closes #1331

See merge request allianceauth/allianceauth!1550
2023-12-05 13:00:50 +00:00
Ariel Rin
81e5bc5337 Merge branch 'master' into 'fantabular'
# Conflicts:
#   docs/maintenance/tuning/index.md
2023-12-02 01:38:18 +00:00
Ariel Rin
a8ef844fe7 Merge branch 'tuning' into 'master'
Docs: Sql Tuning and python version comparison

See merge request allianceauth/allianceauth!1545
2023-12-02 01:31:52 +00:00
Ariel Rin
9ce1939040 Version Bump 3.8.0 2023-11-09 00:00:28 +10:00
Ariel Rin
322131cd4f Update source language strings 2023-11-08 23:56:16 +10:00
Ariel Rin
55e6e92da5 Merge branch 'transifex' into 'master'
Update from Transifex

See merge request allianceauth/allianceauth!1562
2023-11-08 13:48:26 +00:00
Ariel Rin
e5d29629a5 Update from Transifex 2023-11-08 13:48:26 +00:00
Ariel Rin
26e187e4c8 Merge branch 'assign-users-on-group-form' into 'master'
New Feature: Assign/remove users on group form

See merge request allianceauth/allianceauth!1543
2023-11-08 13:05:25 +00:00
Erik Kalkoken
3480c4e0e8 New Feature: Assign/remove users on group form 2023-11-08 13:05:24 +00:00
Ariel Rin
1544f097e0 Merge branch 'fix-leave-tab-for-autoleave' into 'master'
Fix leave tab for autoleave

See merge request allianceauth/allianceauth!1536
2023-11-08 13:04:27 +00:00
Erik Kalkoken
2477c31656 Fix leave tab for autoleave 2023-11-08 13:04:26 +00:00
Ariel Rin
0dc631d69e Merge branch 'master' into 'master'
Stop renaming discord nick when setting has it disabled

See merge request allianceauth/allianceauth!1540
2023-11-08 13:04:12 +00:00
Dusty Meg
2a9981cdb9 Stop renaming discord nick when setting has it disabled 2023-11-08 13:04:11 +00:00
Ariel Rin
004c48b8ad mild formatting changes 2023-11-08 13:45:43 +10:00
Ariel Rin
4d66b7d456 and gitlab ci update for new docs 2023-11-01 13:28:32 +10:00
Ariel Rin
77e5747a23 move tox tests to new dependency format 2023-11-01 13:15:18 +10:00
Ariel Rin
6118c0ddec override non compatible dark mode check css 2023-11-01 01:10:39 +10:00
Ariel Rin
ce25deeca1 minor formatting 2023-10-31 23:52:34 +10:00
Ariel Rin
60084de3db Pygments lexer name 'math' is not known 2023-10-31 23:43:52 +10:00
Ariel Rin
e16c68e255 increase anchor generation 2023-10-31 23:43:45 +10:00
Ariel Rin
bf14e9c7c3 merged back into sphinxcontrib-django 2023-10-31 23:36:42 +10:00
Ariel Rin
98e91fe207 MyST conversion 2023-10-31 23:31:41 +10:00
Ariel Rin
7024552c4e remove ubuntu 1804 2023-10-27 22:20:27 +10:00
Ariel Rin
a0719e4b86 tabify 2023-10-27 22:20:11 +10:00
Ariel Rin
906c589f14 more automated upgrades 2023-10-27 22:19:28 +10:00
Ariel Rin
ffb526ab0c find and replace fixes, will introduce errors 2023-10-27 16:37:53 +10:00
Ariel Rin
b9d128259e correct path 2023-10-27 16:37:30 +10:00
Ariel Rin
13d866bd0d RST to MyST, pyproject doc dependencies, add sphinx tabs 2023-10-27 16:37:09 +10:00
Ariel Rin
ea1887b9ec mild clarifications 2023-10-26 11:26:39 +10:00
Ariel Rin
d2f8c2a42f Merge branch 'master' of gitlab.com:allianceauth/allianceauth into tuning 2023-10-26 10:49:29 +10:00
Ariel Rin
424246df26 Version Bump 3.7.1 2023-10-19 14:00:29 +10:00
Ariel Rin
563e2210ef Bump Django-ESI to >=5.0.0 2023-10-19 13:11:35 +10:00
Ariel Rin
02a1078005 Merge branch 'remove-thirdparty' into 'master'
Remove outdated supervisor configs - refer to docs

See merge request allianceauth/allianceauth!1533
2023-10-19 03:03:35 +00:00
Ariel Rin
30107de44e Merge branch 'docs-precommit' into 'master'
Add code-style docs

Closes #1379

See merge request allianceauth/allianceauth!1534
2023-10-19 03:03:14 +00:00
Ariel Rin
200e8f2ff1 initial sql tuning and python version comparison 2023-10-11 12:33:17 +10:00
Ariel Rin
77a08cd218 Add code-style docs 2023-10-07 22:32:19 +10:00
Ariel Rin
e5a09027e5 Remove outdated supervisor configs - refer to docs 2023-10-07 21:53:03 +10:00
Ariel Rin
52b6c5d341 Rework default celery configuration and documentation 2023-10-07 19:31:53 +10:00
112 changed files with 4579 additions and 3135 deletions

View File

@@ -195,7 +195,7 @@ build-test:
test-docs:
<<: *only-default
image: python:3.10-bullseye
image: python:3.11-bullseye
script:
- tox -e docs

View File

@@ -7,11 +7,11 @@ version: 2
# Set the version of Python and other tools you might need
build:
os: ubuntu-20.04
os: ubuntu-22.04
apt_packages:
- redis
tools:
python: "3.8"
python: "3.11"
# Build documentation in the docs/ directory with Sphinx
sphinx:
@@ -20,7 +20,10 @@ sphinx:
# Optionally build your docs in additional formats such as PDF and ePub
formats: all
# Optionally set the version of Python and requirements required to build your docs
# Python requirements required to build your docs
python:
install:
- requirements: docs/requirements.txt
- method: pip
path: .
extra_requirements:
- docs

View File

@@ -1,5 +1,5 @@
[main]
host = https://www.transifex.com
host = https://app.transifex.com
lang_map = zh-Hans: zh_Hans
[o:alliance-auth:p:alliance-auth:r:django-po]

View File

@@ -1,10 +0,0 @@
[main]
host = https://www.transifex.com
lang_map = zh-Hans:zh_Hans
[alliance-auth.django-po]
file_filter = allianceauth/locale/<lang>/LC_MESSAGES/django.po
minimum_perc = 0
source_file = allianceauth/locale/en/LC_MESSAGES/django.po
source_lang = en
type = PO

10
.tx/transifex.yml Normal file
View File

@@ -0,0 +1,10 @@
filters:
- filter_type: file
file_format: PO
source_file: allianceauth/locale/en/LC_MESSAGES/django.po
source_language: en
translation_files_expression: allianceauth/locale/<lang>/LC_MESSAGES/django.po
settings:
language_mapping:
zh-Hans: zh_Hans

View File

@@ -17,7 +17,7 @@ An auth system for EVE Online to help in-game organizations manage online servic
- [Documentation](http://allianceauth.rtfd.io)
- [Support](#support)
- [Release Notes](https://gitlab.com/allianceauth/allianceauth/-/releases)
- [Developer Team](#developer-team)
- [Developer Team](#development-team)
- [Contributing](#contributing)
## Overview

View File

@@ -5,7 +5,7 @@ manage online service access.
# This will make sure the app is always imported when
# Django starts so that shared_task will use this app.
__version__ = '3.7.0'
__version__ = '3.8.1'
__title__ = 'Alliance Auth'
__url__ = 'https://gitlab.com/allianceauth/allianceauth'
NAME = f'{__title__} v{__version__}'

View File

@@ -2,7 +2,6 @@ import logging
from django.contrib.auth.backends import ModelBackend
from django.contrib.auth.models import User, Permission
from django.contrib import messages
from .models import UserProfile, CharacterOwnership, OwnershipRecord
@@ -41,9 +40,7 @@ class StateBackend(ModelBackend):
if ownership.user.profile.main_character:
if ownership.user.profile.main_character.character_id == token.character_id:
return ownership.user
else: ## this is an alt, enforce main only.
if request:
messages.error("Unable to authenticate with this Character, Please log in with the main character associated with this account.")
else: # this is an alt, enforce main only.
return None
else:
logger.debug(f'{token.character_name} has changed ownership. Creating new user account.')
@@ -66,9 +63,7 @@ class StateBackend(ModelBackend):
user = records[0].user
if user.profile.main_character:
if user.profile.main_character.character_id != token.character_id:
## this is an alt, enforce main only due to trust issues in SSO.
if request:
messages.error("Unable to authenticate with this Character, Please log in with the main character associated with this account. Then add this character from the dashboard.")
# this is an alt, enforce main only due to trust issues in SSO.
return None
token.user = user

View File

@@ -171,7 +171,13 @@ def sso_login(request, token):
request.session['registration_uid'] = user.pk
# Go to Step 2
return redirect('registration_register')
messages.error(request, _('Unable to authenticate as the selected character.'))
# Logging in with an alt is not allowed due to security concerns.
token.delete()
messages.error(
request,
_('Unable to authenticate as the selected character. '
'Please log in with the main character associated with this account.')
)
return redirect(settings.LOGIN_URL)

View File

@@ -1,6 +1,10 @@
import functools
from django import forms
from django.contrib.auth.models import Group
from django.contrib.admin.widgets import FilteredSelectMultiple
from django.contrib.auth.models import Group, User
from django.core.exceptions import ValidationError
from django.db.models.functions import Lower
from django.utils.timezone import now
from django.utils.translation import gettext_lazy as _
@@ -8,6 +12,39 @@ from .models import ReservedGroupName
class GroupAdminForm(forms.ModelForm):
users = forms.ModelMultipleChoiceField(
queryset=User.objects.order_by(Lower('username')),
required=False,
widget=FilteredSelectMultiple(verbose_name=_("Users"), is_stacked=False),
)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
if self.instance and self.instance.pk:
self.fields["users"].initial = self.instance.user_set.all()
def save(self, commit=True):
group: Group = super().save(commit=False)
if commit:
group.save()
users = self.cleaned_data["users"]
if group.pk:
self._save_m2m_and_users(group, users)
else:
self.save_m2m = functools.partial(
self._save_m2m_and_users, group=group, users=users
)
return group
def _save_m2m_and_users(self, group, users):
"""Save m2m relations incl. users."""
group.user_set.set(users)
self._save_m2m()
def clean_name(self):
my_name = self.cleaned_data['name']
if ReservedGroupName.objects.filter(name__iexact=my_name).exists():

View File

@@ -1,8 +1,7 @@
from typing import Set
from django.conf import settings
from django.contrib.auth.models import Group
from django.contrib.auth.models import User
from django.contrib.auth.models import Group, User
from django.db import models
from django.utils.timezone import now
from django.utils.translation import gettext_lazy as _
@@ -14,7 +13,7 @@ from allianceauth.notifications import notify
class GroupRequest(models.Model):
"""Request from a user for joining or leaving a group."""
leave_request = models.BooleanField(default=0)
leave_request = models.BooleanField(default=False)
user = models.ForeignKey(User, on_delete=models.CASCADE)
group = models.ForeignKey(Group, on_delete=models.CASCADE)
@@ -49,7 +48,7 @@ class RequestLog(models.Model):
request_type = models.BooleanField(null=True)
group = models.ForeignKey(Group, on_delete=models.CASCADE)
request_info = models.CharField(max_length=254)
action = models.BooleanField(default=0)
action = models.BooleanField(default=False)
request_actor = models.ForeignKey(User, on_delete=models.CASCADE)
date = models.DateTimeField(auto_now_add=True)

View File

@@ -29,7 +29,7 @@
</a>
</li>
{% if not auto_leave %}
{% if not show_leave_tab %}
<li>
<a data-toggle="tab" href="#leave">
{% translate "Leave Requests" %}
@@ -102,7 +102,7 @@
{% endif %}
</div>
{% if not auto_leave %}
{% if not show_leave_tab %}
<div id="leave" class="tab-pane">
{% if leaverequests %}
<div class="table-responsive">

View File

@@ -6,22 +6,22 @@ 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, override_settings
from django.test import Client, RequestFactory, TestCase, override_settings
from allianceauth.authentication.models import CharacterOwnership, State
from allianceauth.eveonline.models import (
EveCharacter, EveCorporationInfo, EveAllianceInfo
EveAllianceInfo, EveCharacter, EveCorporationInfo,
)
from allianceauth.tests.auth_utils import AuthUtils
from . import get_admin_change_view_url
from ..admin import HasLeaderFilter, GroupAdmin, Group
from ..admin import Group, GroupAdmin, HasLeaderFilter
from ..models import ReservedGroupName
from . import get_admin_change_view_url
if 'allianceauth.eveonline.autogroups' in settings.INSTALLED_APPS:
_has_auto_groups = True
from allianceauth.eveonline.autogroups.models import AutogroupsConfig
from ..admin import IsAutoGroupFilter
else:
_has_auto_groups = False
@@ -621,21 +621,16 @@ class TestGroupAdmin2(TestCase):
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}",
"name": group.name,
"users": [user_member.pk, user_guest.pk],
"authgroup-TOTAL_FORMS": 1,
"authgroup-INITIAL_FORMS": 1,
"authgroup-MIN_NUM_FORMS": 0,
"authgroup-MAX_NUM_FORMS": 1,
"authgroup-0-states": 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"
"authgroup-0-group": group.pk,
}
)
# then
@@ -644,6 +639,85 @@ class TestGroupAdmin2(TestCase):
self.assertIn(group, user_member.groups.all())
self.assertNotIn(group, user_guest.groups.all())
def test_should_add_user_to_existing_group(self):
# given
user_bruce = AuthUtils.create_user("Bruce Wayne")
user_lex = AuthUtils.create_user("Lex Luthor")
group = Group.objects.create(name="dummy")
user_bruce.groups.add(group)
self.client.force_login(self.superuser)
# when
response = self.client.post(
f"/admin/groupmanagement/group/{group.pk}/change/",
data={
"name": group.name,
"users": [user_bruce.pk, user_lex.pk],
"authgroup-TOTAL_FORMS": 1,
"authgroup-INITIAL_FORMS": 1,
"authgroup-MIN_NUM_FORMS": 0,
"authgroup-MAX_NUM_FORMS": 1,
"authgroup-0-internal": "on",
"authgroup-0-hidden": "on",
"authgroup-0-group": group.pk,
}
)
# then
self.assertEqual(response.status_code, 302)
self.assertEqual(response.url, "/admin/groupmanagement/group/")
self.assertIn(group, user_bruce.groups.all())
self.assertIn(group, user_lex.groups.all())
def test_should_remove_user_from_existing_group(self):
# given
user_bruce = AuthUtils.create_user("Bruce Wayne")
user_lex = AuthUtils.create_user("Lex Luthor")
group = Group.objects.create(name="dummy")
user_bruce.groups.add(group)
user_lex.groups.add(group)
self.client.force_login(self.superuser)
# when
response = self.client.post(
f"/admin/groupmanagement/group/{group.pk}/change/",
data={
"name": group.name,
"users": user_bruce.pk,
"authgroup-TOTAL_FORMS": 1,
"authgroup-INITIAL_FORMS": 1,
"authgroup-MIN_NUM_FORMS": 0,
"authgroup-MAX_NUM_FORMS": 1,
"authgroup-0-internal": "on",
"authgroup-0-hidden": "on",
"authgroup-0-group": group.pk,
}
)
# then
self.assertEqual(response.status_code, 302)
self.assertEqual(response.url, "/admin/groupmanagement/group/")
self.assertIn(group, user_bruce.groups.all())
self.assertNotIn(group, user_lex.groups.all())
def test_should_include_user_when_creating_group(self):
# given
user_bruce = AuthUtils.create_user("Bruce Wayne")
self.client.force_login(self.superuser)
# when
response = self.client.post(
"/admin/groupmanagement/group/add/",
data={
"name": "new group",
"users": user_bruce.pk,
"authgroup-TOTAL_FORMS": 1,
"authgroup-INITIAL_FORMS": 0,
"authgroup-MIN_NUM_FORMS": 0,
"authgroup-MAX_NUM_FORMS": 1,
}
)
# then
self.assertEqual(response.status_code, 302)
self.assertEqual(response.url, "/admin/groupmanagement/group/")
group = Group.objects.get(name="new group")
self.assertIn(group, user_bruce.groups.all())
class TestReservedGroupNameAdmin(TestCase):
@classmethod

View File

@@ -1,6 +1,7 @@
from django.test import RequestFactory, TestCase, override_settings
from django.urls import reverse
from allianceauth.groupmanagement.models import Group, GroupRequest
from allianceauth.tests.auth_utils import AuthUtils
from .. import views
@@ -16,6 +17,7 @@ class TestViews(TestCase):
self.factory = RequestFactory()
self.user = AuthUtils.create_user('Peter Parker')
self.user_with_manage_permission = AuthUtils.create_user('Bruce Wayne')
self.group = Group.objects.create(name="Example group")
# set permissions
AuthUtils.add_permission_to_user_by_name(
@@ -83,3 +85,19 @@ class TestViews(TestCase):
self.assertEqual(response.status_code, 200)
self.assertNotIn('<a data-toggle="tab" href="#leave">', content)
self.assertNotIn('<div id="leave" class="tab-pane">', content)
@override_settings(GROUPMANAGEMENT_AUTO_LEAVE=True)
def test_should_not_hide_leave_requests_tab_when_there_are_open_requests(self):
# given
request = self.factory.get(reverse('groupmanagement:management'))
request.user = self.user_with_manage_permission
GroupRequest.objects.create(user=self.user, group=self.group, leave_request=True)
# when
response = views.group_management(request)
# then
content = response_content_to_str(response)
self.assertEqual(response.status_code, 200)
self.assertIn('<a data-toggle="tab" href="#leave">', content)
self.assertIn('<div id="leave" class="tab-pane">', content)

View File

@@ -2,13 +2,12 @@ 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
from django.contrib.auth.decorators import login_required, user_passes_test
from django.contrib.auth.models import Group
from django.core.exceptions import ObjectDoesNotExist, PermissionDenied
from django.db.models import Count
from django.http import Http404
from django.shortcuts import render, redirect, get_object_or_404
from django.shortcuts import get_object_or_404, redirect, render
from django.utils.translation import gettext_lazy as _
from allianceauth.notifications import notify
@@ -16,7 +15,6 @@ from allianceauth.notifications import notify
from .managers import GroupManager
from .models import GroupRequest, RequestLog
logger = logging.getLogger(__name__)
@@ -45,10 +43,15 @@ def group_management(request):
logger.debug("Providing user {} with {} acceptrequests and {} leaverequests.".format(
request.user, len(acceptrequests), len(leaverequests)))
show_leave_tab = (
getattr(settings, 'GROUPMANAGEMENT_AUTO_LEAVE', False)
and not GroupRequest.objects.filter(leave_request=True).exists()
)
render_items = {
'acceptrequests': acceptrequests,
'leaverequests': leaverequests,
'auto_leave': getattr(settings, 'GROUPMANAGEMENT_AUTO_LEAVE', False),
'show_leave_tab': show_leave_tab,
}
return render(request, 'groupmanagement/index.html', context=render_items)

File diff suppressed because it is too large Load Diff

View File

@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-10-09 18:20+1000\n"
"POT-Creation-Date: 2024-02-17 18:50+1000\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"
@@ -26,7 +26,7 @@ msgstr ""
msgid "Google Analytics V4"
msgstr ""
#: allianceauth/authentication/decorators.py:37
#: allianceauth/authentication/decorators.py:49
msgid "A main character is required to perform that action. Add one below."
msgstr ""
@@ -39,63 +39,68 @@ msgstr ""
msgid "You are not allowed to add or remove these restricted groups: %s"
msgstr ""
#: allianceauth/authentication/models.py:80
#: allianceauth/authentication/models.py:71
msgid "English"
msgstr ""
#: allianceauth/authentication/models.py:81
#: allianceauth/authentication/models.py:72
msgid "German"
msgstr ""
#: allianceauth/authentication/models.py:82
#: allianceauth/authentication/models.py:73
msgid "Spanish"
msgstr ""
#: allianceauth/authentication/models.py:83
#: allianceauth/authentication/models.py:74
msgid "Chinese Simplified"
msgstr ""
#: allianceauth/authentication/models.py:84
#: allianceauth/authentication/models.py:75
msgid "Russian"
msgstr ""
#: allianceauth/authentication/models.py:85
#: allianceauth/authentication/models.py:76
msgid "Korean"
msgstr ""
#: allianceauth/authentication/models.py:86
#: allianceauth/authentication/models.py:77
msgid "French"
msgstr ""
#: allianceauth/authentication/models.py:87
#: allianceauth/authentication/models.py:78
msgid "Japanese"
msgstr ""
#: allianceauth/authentication/models.py:88
#: allianceauth/authentication/models.py:79
msgid "Italian"
msgstr ""
#: allianceauth/authentication/models.py:91
msgid "Language"
#: allianceauth/authentication/models.py:80
msgid "Ukrainian"
msgstr ""
#: allianceauth/authentication/models.py:96
msgid "Language"
msgstr ""
#: allianceauth/authentication/models.py:101
#: allianceauth/templates/allianceauth/night-toggle.html:6
msgid "Night Mode"
msgstr ""
#: allianceauth/authentication/models.py:110
#: allianceauth/authentication/models.py:115
#, python-format
msgid "State changed to: %s"
msgstr ""
#: allianceauth/authentication/models.py:111
#: allianceauth/authentication/models.py:116
#, python-format
msgid "Your user's state is now: %(state)s"
msgstr ""
#: allianceauth/authentication/templates/authentication/dashboard.html:4
#: allianceauth/authentication/templates/authentication/dashboard.html:7
#: allianceauth/authentication/templates/authentication/tokens.html:4
#: allianceauth/templates/allianceauth/side-menu.html:10
msgid "Dashboard"
msgstr ""
@@ -151,8 +156,49 @@ msgstr ""
msgid "Alliance"
msgstr ""
#: allianceauth/authentication/templates/authentication/tokens.html:7
#: allianceauth/templates/allianceauth/top-menu-user-dropdown.html:62
msgid "Token Management"
msgstr ""
#: allianceauth/authentication/templates/authentication/tokens.html:12
msgid "Scopes"
msgstr ""
#: allianceauth/authentication/templates/authentication/tokens.html:13
#: allianceauth/hrapplications/templates/hrapplications/management.html:28
#: allianceauth/hrapplications/templates/hrapplications/management.html:83
#: allianceauth/hrapplications/templates/hrapplications/management.html:127
#: allianceauth/hrapplications/templates/hrapplications/searchview.html:27
#: allianceauth/hrapplications/templates/hrapplications/view.html:73
#: allianceauth/srp/templates/srp/data.html:101
#: allianceauth/srp/templates/srp/management.html:44
msgid "Actions"
msgstr ""
#: allianceauth/authentication/templates/authentication/tokens.html:14
#: allianceauth/corputils/templates/corputils/corpstats.html:74
#: allianceauth/corputils/templates/corputils/corpstats.html:112
#: allianceauth/corputils/templates/corputils/corpstats.html:156
#: allianceauth/corputils/templates/corputils/search.html:13
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkmodify.html:22
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkview.html:26
#: allianceauth/groupmanagement/templates/groupmanagement/audit.html:30
#: allianceauth/groupmanagement/templates/groupmanagement/groupmembers.html:29
#: allianceauth/groupmanagement/templates/groupmanagement/index.html:55
#: allianceauth/groupmanagement/templates/groupmanagement/index.html:112
msgid "Character"
msgstr ""
#: allianceauth/authentication/templates/authentication/tokens.html:28
msgid ""
"This page is a best attempt, but backups or database logs can still contain "
"your tokens. Always revoke tokens on https://community.eveonline.com/support/"
"third-party-applications/ where possible."
msgstr ""
#: allianceauth/authentication/templates/public/login.html:6
#: allianceauth/templates/allianceauth/top-menu-user-dropdown.html:58
#: allianceauth/templates/allianceauth/top-menu-user-dropdown.html:69
msgid "Login"
msgstr ""
@@ -184,47 +230,49 @@ msgstr ""
msgid "Invalid or expired activation link."
msgstr ""
#: allianceauth/authentication/views.py:77
#: allianceauth/authentication/views.py:118
#, python-format
msgid ""
"Cannot change main character to %(char)s: character owned by a different "
"account."
msgstr ""
#: allianceauth/authentication/views.py:83
#: allianceauth/authentication/views.py:124
#, python-format
msgid "Changed main character to %(char)s"
msgstr ""
#: allianceauth/authentication/views.py:92
#: allianceauth/authentication/views.py:133
#, python-format
msgid "Added %(name)s to your account."
msgstr ""
#: allianceauth/authentication/views.py:94
#: allianceauth/authentication/views.py:135
#, python-format
msgid "Failed to add %(name)s to your account: they already have an account."
msgstr ""
#: allianceauth/authentication/views.py:133
msgid "Unable to authenticate as the selected character."
#: allianceauth/authentication/views.py:178
msgid ""
"Unable to authenticate as the selected character. Please log in with the "
"main character associated with this account."
msgstr ""
#: allianceauth/authentication/views.py:197
#: allianceauth/authentication/views.py:244
msgid "Registration token has expired."
msgstr ""
#: allianceauth/authentication/views.py:252
#: allianceauth/authentication/views.py:302
msgid ""
"Sent confirmation email. Please follow the link to confirm your email "
"address."
msgstr ""
#: allianceauth/authentication/views.py:257
#: allianceauth/authentication/views.py:307
msgid "Confirmed your email address. Please login to continue."
msgstr ""
#: allianceauth/authentication/views.py:262
#: allianceauth/authentication/views.py:312
msgid "Registration of new accounts is not allowed at this time."
msgstr ""
@@ -267,19 +315,6 @@ msgstr ""
msgid "Last update:"
msgstr ""
#: allianceauth/corputils/templates/corputils/corpstats.html:74
#: allianceauth/corputils/templates/corputils/corpstats.html:112
#: allianceauth/corputils/templates/corputils/corpstats.html:156
#: allianceauth/corputils/templates/corputils/search.html:13
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkmodify.html:22
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkview.html:26
#: allianceauth/groupmanagement/templates/groupmanagement/audit.html:30
#: allianceauth/groupmanagement/templates/groupmanagement/groupmembers.html:29
#: allianceauth/groupmanagement/templates/groupmanagement/index.html:55
#: allianceauth/groupmanagement/templates/groupmanagement/index.html:112
msgid "Character"
msgstr ""
#: allianceauth/corputils/templates/corputils/corpstats.html:75
#: allianceauth/corputils/templates/corputils/search.html:14
#: allianceauth/groupmanagement/templates/groupmanagement/audit.html:31
@@ -611,36 +646,41 @@ msgstr ""
msgid "Group Management"
msgstr ""
#: allianceauth/groupmanagement/forms.py:15
#: allianceauth/groupmanagement/forms.py:18
#: allianceauth/permissions_tool/templates/permissions_tool/overview.html:35
msgid "Users"
msgstr ""
#: allianceauth/groupmanagement/forms.py:52
msgid "This name has been reserved and can not be used for groups."
msgstr ""
#: allianceauth/groupmanagement/forms.py:25
#: allianceauth/groupmanagement/forms.py:62
msgid "(auto)"
msgstr ""
#: allianceauth/groupmanagement/forms.py:34
#: allianceauth/groupmanagement/forms.py:71
msgid "There already exists a group with that name."
msgstr ""
#: allianceauth/groupmanagement/models.py:105
#: allianceauth/groupmanagement/models.py:104
msgid ""
"Internal group, users cannot see, join or request to join this group."
"<br>Used for groups such as Members, Corp_*, Alliance_* etc.<br><b>Overrides "
"Hidden and Open options when selected.</b>"
msgstr ""
#: allianceauth/groupmanagement/models.py:113
#: allianceauth/groupmanagement/models.py:112
msgid "Group is hidden from users but can still join with the correct link."
msgstr ""
#: allianceauth/groupmanagement/models.py:119
#: allianceauth/groupmanagement/models.py:118
msgid ""
"Group is open and users will be automatically added upon request.<br>If the "
"group is not open users will need their request manually approved."
msgstr ""
#: allianceauth/groupmanagement/models.py:126
#: allianceauth/groupmanagement/models.py:125
msgid ""
"Group is public. Any registered user is able to join this group, with "
"visibility based on the other options set for this group.<br>Auth will not "
@@ -648,65 +688,65 @@ msgid ""
"authenticated."
msgstr ""
#: allianceauth/groupmanagement/models.py:135
#: allianceauth/groupmanagement/models.py:134
msgid ""
"Group is restricted. This means that adding or removing users for this group "
"requires a superuser admin."
msgstr ""
#: allianceauth/groupmanagement/models.py:144
#: allianceauth/groupmanagement/models.py:143
msgid ""
"Group leaders can process requests for this group. Use the <code>auth."
"group_management</code> permission to allow a user to manage all groups.<br>"
msgstr ""
#: allianceauth/groupmanagement/models.py:154
#: allianceauth/groupmanagement/models.py:153
msgid ""
"Members of leader groups can process requests for this group. Use the "
"<code>auth.group_management</code> permission to allow a user to manage all "
"groups.<br>"
msgstr ""
#: allianceauth/groupmanagement/models.py:163
#: allianceauth/groupmanagement/models.py:162
msgid ""
"States listed here will have the ability to join this group provided they "
"have the proper permissions.<br>"
msgstr ""
#: allianceauth/groupmanagement/models.py:171
#: allianceauth/groupmanagement/models.py:170
msgid ""
"Short description <i>(max. 512 characters)</i> of the group shown to users."
msgstr ""
#: allianceauth/groupmanagement/models.py:178
#: allianceauth/groupmanagement/models.py:177
msgid "Can request non-public groups"
msgstr ""
#: allianceauth/groupmanagement/models.py:209
#: allianceauth/groupmanagement/models.py:208
msgid "name"
msgstr ""
#: allianceauth/groupmanagement/models.py:212
#: allianceauth/groupmanagement/models.py:211
msgid "Name that can not be used for groups."
msgstr ""
#: allianceauth/groupmanagement/models.py:215
#: allianceauth/groupmanagement/models.py:214
msgid "reason"
msgstr ""
#: allianceauth/groupmanagement/models.py:215
#: allianceauth/groupmanagement/models.py:214
msgid "Reason why this name is reserved."
msgstr ""
#: allianceauth/groupmanagement/models.py:218
#: allianceauth/groupmanagement/models.py:217
msgid "created by"
msgstr ""
#: allianceauth/groupmanagement/models.py:223
#: allianceauth/groupmanagement/models.py:222
msgid "created at"
msgstr ""
#: allianceauth/groupmanagement/models.py:223
#: allianceauth/groupmanagement/models.py:222
msgid "Date when this entry was created"
msgstr ""
@@ -933,86 +973,86 @@ msgstr ""
msgid "Group Membership"
msgstr ""
#: allianceauth/groupmanagement/views.py:163
#: allianceauth/groupmanagement/views.py:166
#, python-format
msgid "Removed user %(user)s from group %(group)s."
msgstr ""
#: allianceauth/groupmanagement/views.py:165
#: allianceauth/groupmanagement/views.py:168
msgid "User does not exist in that group"
msgstr ""
#: allianceauth/groupmanagement/views.py:168
#: allianceauth/groupmanagement/views.py:171
msgid "Group does not exist"
msgstr ""
#: allianceauth/groupmanagement/views.py:195
#: allianceauth/groupmanagement/views.py:198
#, python-format
msgid "Accepted application from %(mainchar)s to %(group)s."
msgstr ""
#: allianceauth/groupmanagement/views.py:201
#: allianceauth/groupmanagement/views.py:232
#: allianceauth/groupmanagement/views.py:204
#: allianceauth/groupmanagement/views.py:235
#, python-format
msgid ""
"An unhandled error occurred while processing the application from "
"%(mainchar)s to %(group)s."
msgstr ""
#: allianceauth/groupmanagement/views.py:226
#: allianceauth/groupmanagement/views.py:229
#, python-format
msgid "Rejected application from %(mainchar)s to %(group)s."
msgstr ""
#: allianceauth/groupmanagement/views.py:261
#: allianceauth/groupmanagement/views.py:264
#, python-format
msgid "Accepted application from %(mainchar)s to leave %(group)s."
msgstr ""
#: allianceauth/groupmanagement/views.py:266
#: allianceauth/groupmanagement/views.py:298
#: allianceauth/groupmanagement/views.py:269
#: allianceauth/groupmanagement/views.py:301
#, python-format
msgid ""
"An unhandled error occurred while processing the application from "
"%(mainchar)s to leave %(group)s."
msgstr ""
#: allianceauth/groupmanagement/views.py:292
#: allianceauth/groupmanagement/views.py:295
#, python-format
msgid "Rejected application from %(mainchar)s to leave %(group)s."
msgstr ""
#: allianceauth/groupmanagement/views.py:336
#: allianceauth/groupmanagement/views.py:346
#: allianceauth/groupmanagement/views.py:339
#: allianceauth/groupmanagement/views.py:349
msgid "You cannot join that group"
msgstr ""
#: allianceauth/groupmanagement/views.py:341
#: allianceauth/groupmanagement/views.py:344
msgid "You are already a member of that group."
msgstr ""
#: allianceauth/groupmanagement/views.py:358
#: allianceauth/groupmanagement/views.py:361
msgid "You already have a pending application for that group."
msgstr ""
#: allianceauth/groupmanagement/views.py:367
#: allianceauth/groupmanagement/views.py:370
#, python-format
msgid "Applied to group %(group)s."
msgstr ""
#: allianceauth/groupmanagement/views.py:377
#: allianceauth/groupmanagement/views.py:380
msgid "You cannot leave that group"
msgstr ""
#: allianceauth/groupmanagement/views.py:381
#: allianceauth/groupmanagement/views.py:384
msgid "You are not a member of that group"
msgstr ""
#: allianceauth/groupmanagement/views.py:393
#: allianceauth/groupmanagement/views.py:396
msgid "You already have a pending leave request for that group."
msgstr ""
#: allianceauth/groupmanagement/views.py:409
#: allianceauth/groupmanagement/views.py:412
#, python-format
msgid "Applied to leave group %(group)s."
msgstr ""
@@ -1074,16 +1114,6 @@ msgstr ""
msgid "Username"
msgstr ""
#: allianceauth/hrapplications/templates/hrapplications/management.html:28
#: allianceauth/hrapplications/templates/hrapplications/management.html:83
#: allianceauth/hrapplications/templates/hrapplications/management.html:127
#: allianceauth/hrapplications/templates/hrapplications/searchview.html:27
#: allianceauth/hrapplications/templates/hrapplications/view.html:73
#: allianceauth/srp/templates/srp/data.html:101
#: allianceauth/srp/templates/srp/management.html:44
msgid "Actions"
msgstr ""
#: allianceauth/hrapplications/templates/hrapplications/management.html:38
#: allianceauth/hrapplications/templates/hrapplications/management.html:99
#: allianceauth/hrapplications/templates/hrapplications/management.html:143
@@ -1422,10 +1452,6 @@ msgstr ""
msgid "Code Name"
msgstr ""
#: allianceauth/permissions_tool/templates/permissions_tool/overview.html:35
msgid "Users"
msgstr ""
#: allianceauth/permissions_tool/templates/permissions_tool/overview.html:41
msgid "States"
msgstr ""
@@ -2146,11 +2172,11 @@ msgid ""
msgstr ""
#: allianceauth/templates/allianceauth/admin-status/overview.html:95
#, python-format
msgid ""
"\n"
" %(queue_length)s queued tasks\n"
" "
msgid "running"
msgstr ""
#: allianceauth/templates/allianceauth/admin-status/overview.html:96
msgid "queued"
msgstr ""
#: allianceauth/templates/allianceauth/top-menu-admin.html:9
@@ -2166,11 +2192,11 @@ msgid "AA Support Discord"
msgstr ""
#: allianceauth/templates/allianceauth/top-menu-user-dropdown.html:10
#: allianceauth/templates/allianceauth/top-menu-user-dropdown.html:14
#: allianceauth/templates/allianceauth/top-menu-user-dropdown.html:16
msgid "User Menu"
msgstr ""
#: allianceauth/templates/allianceauth/top-menu-user-dropdown.html:56
#: allianceauth/templates/allianceauth/top-menu-user-dropdown.html:67
msgid "Logout"
msgstr ""
@@ -2226,22 +2252,30 @@ msgid "Objective"
msgstr ""
#: allianceauth/timerboard/form.py:64
msgid "Days Remaining"
msgid "Absolute Timer"
msgstr ""
#: allianceauth/timerboard/form.py:65
msgid "Hours Remaining"
msgid "Date and Time"
msgstr ""
#: allianceauth/timerboard/form.py:66
msgid "Days Remaining"
msgstr ""
#: allianceauth/timerboard/form.py:67
msgid "Minutes Remaining"
msgid "Hours Remaining"
msgstr ""
#: allianceauth/timerboard/form.py:69
msgid "Minutes Remaining"
msgstr ""
#: allianceauth/timerboard/form.py:71
msgid "Important"
msgstr ""
#: allianceauth/timerboard/form.py:70
#: allianceauth/timerboard/form.py:72
msgid "Corp-Restricted"
msgstr ""

View File

@@ -4,10 +4,10 @@
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
# Translators:
# frank1210 <francolopez_16@hotmail.com>, 2021
# Joel Falknau <ozirascal@gmail.com>, 2021
# Young Anexo, 2023
# Fegpawn Kaundur, 2023
# frank1210 <francolopez_16@hotmail.com>, 2023
# Young Anexo, 2023
# Joel Falknau <ozirascal@gmail.com>, 2023
# trenus, 2023
#
#, fuzzy
@@ -15,8 +15,8 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-10-09 18:20+1000\n"
"PO-Revision-Date: 2020-02-18 03:14+0000\n"
"POT-Creation-Date: 2024-02-17 18:50+1000\n"
"PO-Revision-Date: 2023-11-08 13:50+0000\n"
"Last-Translator: trenus, 2023\n"
"Language-Team: Spanish (https://app.transifex.com/alliance-auth/teams/107430/es/)\n"
"MIME-Version: 1.0\n"
@@ -33,7 +33,7 @@ msgstr "Google Analytics Universal"
msgid "Google Analytics V4"
msgstr "Google Analytics V4"
#: allianceauth/authentication/decorators.py:37
#: allianceauth/authentication/decorators.py:49
msgid "A main character is required to perform that action. Add one below."
msgstr ""
"Se necesita un personaje principal para realizar esa acción. Añade uno a "
@@ -48,63 +48,68 @@ msgstr "E-mail"
msgid "You are not allowed to add or remove these restricted groups: %s"
msgstr "No puedes añadir o eliminar estos grupos restringidos: %s"
#: allianceauth/authentication/models.py:80
#: allianceauth/authentication/models.py:71
msgid "English"
msgstr "Inglés"
#: allianceauth/authentication/models.py:81
#: allianceauth/authentication/models.py:72
msgid "German"
msgstr "Alemán"
#: allianceauth/authentication/models.py:82
#: allianceauth/authentication/models.py:73
msgid "Spanish"
msgstr "Español"
#: allianceauth/authentication/models.py:83
#: allianceauth/authentication/models.py:74
msgid "Chinese Simplified"
msgstr "Chino Simplificado"
#: allianceauth/authentication/models.py:84
#: allianceauth/authentication/models.py:75
msgid "Russian"
msgstr "Ruso"
#: allianceauth/authentication/models.py:85
#: allianceauth/authentication/models.py:76
msgid "Korean"
msgstr "Coreano"
#: allianceauth/authentication/models.py:86
#: allianceauth/authentication/models.py:77
msgid "French"
msgstr "Francés"
#: allianceauth/authentication/models.py:87
#: allianceauth/authentication/models.py:78
msgid "Japanese"
msgstr "Japonés"
#: allianceauth/authentication/models.py:88
#: allianceauth/authentication/models.py:79
msgid "Italian"
msgstr "Italiano"
#: allianceauth/authentication/models.py:91
#: allianceauth/authentication/models.py:80
msgid "Ukrainian"
msgstr ""
#: allianceauth/authentication/models.py:96
msgid "Language"
msgstr "Idioma"
#: allianceauth/authentication/models.py:96
#: allianceauth/authentication/models.py:101
#: allianceauth/templates/allianceauth/night-toggle.html:6
msgid "Night Mode"
msgstr "Modo Nocturno"
#: allianceauth/authentication/models.py:110
#: allianceauth/authentication/models.py:115
#, python-format
msgid "State changed to: %s"
msgstr "Estado cambiado a: %s"
#: allianceauth/authentication/models.py:111
#: allianceauth/authentication/models.py:116
#, python-format
msgid "Your user's state is now: %(state)s"
msgstr "El estado de su usuario es ahora: %(state)s"
#: allianceauth/authentication/templates/authentication/dashboard.html:4
#: allianceauth/authentication/templates/authentication/dashboard.html:7
#: allianceauth/authentication/templates/authentication/tokens.html:4
#: allianceauth/templates/allianceauth/side-menu.html:10
msgid "Dashboard"
msgstr "Página principal"
@@ -162,8 +167,50 @@ msgstr "Corporación"
msgid "Alliance"
msgstr "Allianza"
#: allianceauth/authentication/templates/authentication/tokens.html:7
#: allianceauth/templates/allianceauth/top-menu-user-dropdown.html:62
msgid "Token Management"
msgstr ""
#: allianceauth/authentication/templates/authentication/tokens.html:12
msgid "Scopes"
msgstr ""
#: allianceauth/authentication/templates/authentication/tokens.html:13
#: allianceauth/hrapplications/templates/hrapplications/management.html:28
#: allianceauth/hrapplications/templates/hrapplications/management.html:83
#: allianceauth/hrapplications/templates/hrapplications/management.html:127
#: allianceauth/hrapplications/templates/hrapplications/searchview.html:27
#: allianceauth/hrapplications/templates/hrapplications/view.html:73
#: allianceauth/srp/templates/srp/data.html:101
#: allianceauth/srp/templates/srp/management.html:44
msgid "Actions"
msgstr "Acciones"
#: allianceauth/authentication/templates/authentication/tokens.html:14
#: allianceauth/corputils/templates/corputils/corpstats.html:74
#: allianceauth/corputils/templates/corputils/corpstats.html:112
#: allianceauth/corputils/templates/corputils/corpstats.html:156
#: allianceauth/corputils/templates/corputils/search.html:13
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkmodify.html:22
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkview.html:26
#: allianceauth/groupmanagement/templates/groupmanagement/audit.html:30
#: allianceauth/groupmanagement/templates/groupmanagement/groupmembers.html:29
#: allianceauth/groupmanagement/templates/groupmanagement/index.html:55
#: allianceauth/groupmanagement/templates/groupmanagement/index.html:112
msgid "Character"
msgstr "Personaje"
#: allianceauth/authentication/templates/authentication/tokens.html:28
msgid ""
"This page is a best attempt, but backups or database logs can still contain "
"your tokens. Always revoke tokens on "
"https://community.eveonline.com/support/third-party-applications/ where "
"possible."
msgstr ""
#: allianceauth/authentication/templates/public/login.html:6
#: allianceauth/templates/allianceauth/top-menu-user-dropdown.html:58
#: allianceauth/templates/allianceauth/top-menu-user-dropdown.html:69
msgid "Login"
msgstr "Ingresar"
@@ -197,7 +244,7 @@ msgstr "Registrar"
msgid "Invalid or expired activation link."
msgstr "Enlace de activacion expirado o invalido"
#: allianceauth/authentication/views.py:77
#: allianceauth/authentication/views.py:118
#, python-format
msgid ""
"Cannot change main character to %(char)s: character owned by a different "
@@ -206,45 +253,47 @@ msgstr ""
"No se puede cambiar de personaje principal a %(char)s: personaje "
"perteneciente a otra cuenta."
#: allianceauth/authentication/views.py:83
#: allianceauth/authentication/views.py:124
#, python-format
msgid "Changed main character to %(char)s"
msgstr "Se ha cambiado tu personaje principal ha %(char)s"
#: allianceauth/authentication/views.py:92
#: allianceauth/authentication/views.py:133
#, python-format
msgid "Added %(name)s to your account."
msgstr "Se ha agregado a %(name)s a tu cuenta"
#: allianceauth/authentication/views.py:94
#: allianceauth/authentication/views.py:135
#, 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:133
msgid "Unable to authenticate as the selected character."
msgstr "Imposible validar con el personaje seleccionado."
#: allianceauth/authentication/views.py:178
msgid ""
"Unable to authenticate as the selected character. Please log in with the "
"main character associated with this account."
msgstr ""
#: allianceauth/authentication/views.py:197
#: allianceauth/authentication/views.py:244
msgid "Registration token has expired."
msgstr "El token de registracion expiro."
#: allianceauth/authentication/views.py:252
#: allianceauth/authentication/views.py:302
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:257
#: allianceauth/authentication/views.py:307
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:262
#: allianceauth/authentication/views.py:312
msgid "Registration of new accounts is not allowed at this time."
msgstr "En este momento no se permite el registro de nuevas cuentas."
@@ -287,19 +336,6 @@ msgstr "Sin registro"
msgid "Last update:"
msgstr "Ultima Actualizacion:"
#: allianceauth/corputils/templates/corputils/corpstats.html:74
#: allianceauth/corputils/templates/corputils/corpstats.html:112
#: allianceauth/corputils/templates/corputils/corpstats.html:156
#: allianceauth/corputils/templates/corputils/search.html:13
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkmodify.html:22
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkview.html:26
#: allianceauth/groupmanagement/templates/groupmanagement/audit.html:30
#: allianceauth/groupmanagement/templates/groupmanagement/groupmembers.html:29
#: allianceauth/groupmanagement/templates/groupmanagement/index.html:55
#: allianceauth/groupmanagement/templates/groupmanagement/index.html:112
msgid "Character"
msgstr "Personaje"
#: allianceauth/corputils/templates/corputils/corpstats.html:75
#: allianceauth/corputils/templates/corputils/search.html:14
#: allianceauth/groupmanagement/templates/groupmanagement/audit.html:31
@@ -636,19 +672,24 @@ msgstr ""
msgid "Group Management"
msgstr "Manejo de Grupo"
#: allianceauth/groupmanagement/forms.py:15
#: allianceauth/groupmanagement/forms.py:18
#: allianceauth/permissions_tool/templates/permissions_tool/overview.html:35
msgid "Users"
msgstr "Usuarios"
#: allianceauth/groupmanagement/forms.py:52
msgid "This name has been reserved and can not be used for groups."
msgstr "Este nombre ha sido reservado y no puede utilizarse para grupos."
#: allianceauth/groupmanagement/forms.py:25
#: allianceauth/groupmanagement/forms.py:62
msgid "(auto)"
msgstr "(auto)"
#: allianceauth/groupmanagement/forms.py:34
#: allianceauth/groupmanagement/forms.py:71
msgid "There already exists a group with that name."
msgstr "Ya existe un grupo con ese nombre."
#: allianceauth/groupmanagement/models.py:105
#: allianceauth/groupmanagement/models.py:104
msgid ""
"Internal group, users cannot see, join or request to join this "
"group.<br>Used for groups such as Members, Corp_*, Alliance_* "
@@ -658,13 +699,13 @@ msgstr ""
"grupo.<br>Se utiliza para grupos como Miembros, Corp_*, Alliance_*, "
"etc.<br><b>Anula las opciones Oculto y Abierto cuando se selecciona.</b>"
#: allianceauth/groupmanagement/models.py:113
#: allianceauth/groupmanagement/models.py:112
msgid "Group is hidden from users but can still join with the correct link."
msgstr ""
"El grupo está oculto para los usuarios, pero aún pueden unirse con el enlace"
" correcto."
#: allianceauth/groupmanagement/models.py:119
#: allianceauth/groupmanagement/models.py:118
msgid ""
"Group is open and users will be automatically added upon request.<br>If the "
"group is not open users will need their request manually approved."
@@ -673,7 +714,7 @@ msgstr ""
"soliciten.<br>Si el grupo no está abierto, los usuarios necesitarán que su "
"solicitud sea aprobada manualmente."
#: allianceauth/groupmanagement/models.py:126
#: allianceauth/groupmanagement/models.py:125
msgid ""
"Group is public. Any registered user is able to join this group, with "
"visibility based on the other options set for this group.<br>Auth will not "
@@ -685,7 +726,7 @@ msgstr ""
"grupo.<br>Auth no eliminará automáticamente a los usuarios de este grupo "
"cuando ya no estén autenticados."
#: allianceauth/groupmanagement/models.py:135
#: allianceauth/groupmanagement/models.py:134
msgid ""
"Group is restricted. This means that adding or removing users for this group"
" requires a superuser admin."
@@ -693,7 +734,7 @@ msgstr ""
"El grupo está restringido. Esto significa que para añadir o eliminar "
"usuarios de este grupo se requiere un superusuario administrador."
#: allianceauth/groupmanagement/models.py:144
#: allianceauth/groupmanagement/models.py:143
msgid ""
"Group leaders can process requests for this group. Use the "
"<code>auth.group_management</code> permission to allow a user to manage all "
@@ -703,7 +744,7 @@ msgstr ""
" permiso <code>auth.group_management</code> para permitir que un usuario "
"gestione todos los grupos.<br>"
#: allianceauth/groupmanagement/models.py:154
#: allianceauth/groupmanagement/models.py:153
msgid ""
"Members of leader groups can process requests for this group. Use the "
"<code>auth.group_management</code> permission to allow a user to manage all "
@@ -713,7 +754,7 @@ msgstr ""
"grupo. Utilice el <code>permiso auth.group_management</code> para permitir "
"que un usuario gestione todos los grupos.<br>"
#: allianceauth/groupmanagement/models.py:163
#: allianceauth/groupmanagement/models.py:162
msgid ""
"States listed here will have the ability to join this group provided they "
"have the proper permissions.<br>"
@@ -721,42 +762,42 @@ msgstr ""
"Los estados que figuren en esta lista podrán unirse a este grupo siempre que"
" dispongan de los permisos adecuados.<br>"
#: allianceauth/groupmanagement/models.py:171
#: allianceauth/groupmanagement/models.py:170
msgid ""
"Short description <i>(max. 512 characters)</i> of the group shown to users."
msgstr ""
"Breve descripción <i>(máx. 512 caracteres)</i> del grupo que se muestra a "
"los usuarios."
#: allianceauth/groupmanagement/models.py:178
#: allianceauth/groupmanagement/models.py:177
msgid "Can request non-public groups"
msgstr "Se pueden solicitar grupos no públicos"
#: allianceauth/groupmanagement/models.py:209
#: allianceauth/groupmanagement/models.py:208
msgid "name"
msgstr "nombre"
#: allianceauth/groupmanagement/models.py:212
#: allianceauth/groupmanagement/models.py:211
msgid "Name that can not be used for groups."
msgstr "Nombre que no se puede utilizar para los grupos."
#: allianceauth/groupmanagement/models.py:215
#: allianceauth/groupmanagement/models.py:214
msgid "reason"
msgstr "razón"
#: allianceauth/groupmanagement/models.py:215
#: allianceauth/groupmanagement/models.py:214
msgid "Reason why this name is reserved."
msgstr "Razón por la que este nombre está reservado."
#: allianceauth/groupmanagement/models.py:218
#: allianceauth/groupmanagement/models.py:217
msgid "created by"
msgstr "creado por"
#: allianceauth/groupmanagement/models.py:223
#: allianceauth/groupmanagement/models.py:222
msgid "created at"
msgstr "creado en"
#: allianceauth/groupmanagement/models.py:223
#: allianceauth/groupmanagement/models.py:222
msgid "Date when this entry was created"
msgstr "Fecha de creación de esta entrada"
@@ -983,26 +1024,26 @@ msgstr "Solicitudes de Grupo"
msgid "Group Membership"
msgstr "Membresia de Grupo"
#: allianceauth/groupmanagement/views.py:163
#: 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:165
#: 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:168
#: allianceauth/groupmanagement/views.py:171
msgid "Group does not exist"
msgstr "El grupo no existe"
#: allianceauth/groupmanagement/views.py:195
#: 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:201
#: allianceauth/groupmanagement/views.py:232
#: allianceauth/groupmanagement/views.py:204
#: allianceauth/groupmanagement/views.py:235
#, python-format
msgid ""
"An unhandled error occurred while processing the application from "
@@ -1011,18 +1052,18 @@ msgstr ""
"Ocurrio un error cuando se intento procesar la informacion de %(mainchar)s "
"al grupo %(group)s."
#: allianceauth/groupmanagement/views.py:226
#: allianceauth/groupmanagement/views.py:229
#, 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:261
#: allianceauth/groupmanagement/views.py:264
#, 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:266
#: allianceauth/groupmanagement/views.py:298
#: allianceauth/groupmanagement/views.py:269
#: allianceauth/groupmanagement/views.py:301
#, python-format
msgid ""
"An unhandled error occurred while processing the application from "
@@ -1031,43 +1072,43 @@ msgstr ""
"Se ha producido un error al procesar la solicitud de %(mainchar)s para "
"abandonar %(group)s."
#: allianceauth/groupmanagement/views.py:292
#: allianceauth/groupmanagement/views.py:295
#, 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:336
#: allianceauth/groupmanagement/views.py:346
#: allianceauth/groupmanagement/views.py:339
#: allianceauth/groupmanagement/views.py:349
msgid "You cannot join that group"
msgstr "No puedes unirte a ese grupo"
#: allianceauth/groupmanagement/views.py:341
#: allianceauth/groupmanagement/views.py:344
msgid "You are already a member of that group."
msgstr "Ya eres miembro de ese grupo."
#: allianceauth/groupmanagement/views.py:358
#: allianceauth/groupmanagement/views.py:361
msgid "You already have a pending application for that group."
msgstr "Ya tiene una solicitud pendiente para ese grupo."
#: allianceauth/groupmanagement/views.py:367
#: allianceauth/groupmanagement/views.py:370
#, python-format
msgid "Applied to group %(group)s."
msgstr "Solicitud enviada al grupo %(group)s."
#: allianceauth/groupmanagement/views.py:377
#: allianceauth/groupmanagement/views.py:380
msgid "You cannot leave that group"
msgstr "No puedes dejar el grupos"
#: allianceauth/groupmanagement/views.py:381
#: allianceauth/groupmanagement/views.py:384
msgid "You are not a member of that group"
msgstr "No eres miembro de ese grupo"
#: allianceauth/groupmanagement/views.py:393
#: allianceauth/groupmanagement/views.py:396
msgid "You already have a pending leave request for that group."
msgstr "Ya tiene una solicitud de baja pendiente para ese grupo."
#: allianceauth/groupmanagement/views.py:409
#: allianceauth/groupmanagement/views.py:412
#, python-format
msgid "Applied to leave group %(group)s."
msgstr "Solicitaste dejar el grupo %(group)s."
@@ -1129,16 +1170,6 @@ msgstr "Crear Solicitud"
msgid "Username"
msgstr "Usuario"
#: allianceauth/hrapplications/templates/hrapplications/management.html:28
#: allianceauth/hrapplications/templates/hrapplications/management.html:83
#: allianceauth/hrapplications/templates/hrapplications/management.html:127
#: allianceauth/hrapplications/templates/hrapplications/searchview.html:27
#: allianceauth/hrapplications/templates/hrapplications/view.html:73
#: allianceauth/srp/templates/srp/data.html:101
#: allianceauth/srp/templates/srp/management.html:44
msgid "Actions"
msgstr "Acciones"
#: allianceauth/hrapplications/templates/hrapplications/management.html:38
#: allianceauth/hrapplications/templates/hrapplications/management.html:99
#: allianceauth/hrapplications/templates/hrapplications/management.html:143
@@ -1477,10 +1508,6 @@ msgstr "Modelo"
msgid "Code Name"
msgstr "Nombre codigo"
#: allianceauth/permissions_tool/templates/permissions_tool/overview.html:35
msgid "Users"
msgstr "Usuarios"
#: allianceauth/permissions_tool/templates/permissions_tool/overview.html:41
msgid "States"
msgstr "Estados"
@@ -2219,14 +2246,12 @@ msgstr ""
"Estado de %(total)s tareas procesadas • últimos %(latest)s"
#: allianceauth/templates/allianceauth/admin-status/overview.html:95
#, python-format
msgid ""
"\n"
" %(queue_length)s queued tasks\n"
" "
msgid "running"
msgstr ""
#: allianceauth/templates/allianceauth/admin-status/overview.html:96
msgid "queued"
msgstr ""
"\n"
"%(queue_length)s tareas en cola"
#: allianceauth/templates/allianceauth/top-menu-admin.html:9
msgid "Admin"
@@ -2241,11 +2266,11 @@ msgid "AA Support Discord"
msgstr "Soporte Discord AA"
#: allianceauth/templates/allianceauth/top-menu-user-dropdown.html:10
#: allianceauth/templates/allianceauth/top-menu-user-dropdown.html:14
#: allianceauth/templates/allianceauth/top-menu-user-dropdown.html:16
msgid "User Menu"
msgstr "Menú de usuario"
#: allianceauth/templates/allianceauth/top-menu-user-dropdown.html:56
#: allianceauth/templates/allianceauth/top-menu-user-dropdown.html:67
msgid "Logout"
msgstr "Salir"
@@ -2301,22 +2326,30 @@ msgid "Objective"
msgstr "Objetivo"
#: allianceauth/timerboard/form.py:64
msgid "Absolute Timer"
msgstr ""
#: allianceauth/timerboard/form.py:65
msgid "Date and Time"
msgstr ""
#: allianceauth/timerboard/form.py:66
msgid "Days Remaining"
msgstr "Dias restantes"
#: allianceauth/timerboard/form.py:65
#: allianceauth/timerboard/form.py:67
msgid "Hours Remaining"
msgstr "Horas Restantes"
#: allianceauth/timerboard/form.py:67
#: allianceauth/timerboard/form.py:69
msgid "Minutes Remaining"
msgstr "Minutos Restantes"
#: allianceauth/timerboard/form.py:69
#: allianceauth/timerboard/form.py:71
msgid "Important"
msgstr "Importante"
#: allianceauth/timerboard/form.py:70
#: allianceauth/timerboard/form.py:72
msgid "Corp-Restricted"
msgstr "Restringido a Corp"

View File

@@ -4,23 +4,23 @@
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
# 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
# Mickael Gr4vity, 2023
# Idea ., 2023
# rockclodbuster, 2023
# Keven D. <theenarki@gmail.com>, 2023
# Mohssine Daghghar, 2023
# Ludovick Fortin, 2023
# Philippe Querin-Laporte <philippe.querin@hotmail.com>, 2023
# draktanar KarazGrong <umbre@fallenstarscreations.com>, 2023
# Geoffrey Fabbro, 2023
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-10-09 18:20+1000\n"
"PO-Revision-Date: 2020-02-18 03:14+0000\n"
"Last-Translator: Ludovick Fortin, 2023\n"
"POT-Creation-Date: 2024-02-17 18:50+1000\n"
"PO-Revision-Date: 2023-11-08 13:50+0000\n"
"Last-Translator: Geoffrey Fabbro, 2023\n"
"Language-Team: French (France) (https://app.transifex.com/alliance-auth/teams/107430/fr_FR/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@@ -36,7 +36,7 @@ msgstr "Google Analytique Universelle"
msgid "Google Analytics V4"
msgstr "Google Analytics V4"
#: allianceauth/authentication/decorators.py:37
#: allianceauth/authentication/decorators.py:49
msgid "A main character is required to perform that action. Add one below."
msgstr ""
"Un personnage principal est nécessaire pour effectuer cette action. Ajoutez-"
@@ -53,63 +53,68 @@ msgstr ""
"Vous n'avez pas lautorisation d'ajouter ou d'enlever ces groupes "
"restreints: %s"
#: allianceauth/authentication/models.py:80
#: allianceauth/authentication/models.py:71
msgid "English"
msgstr "Anglais"
#: allianceauth/authentication/models.py:81
#: allianceauth/authentication/models.py:72
msgid "German"
msgstr "Allemand"
#: allianceauth/authentication/models.py:82
#: allianceauth/authentication/models.py:73
msgid "Spanish"
msgstr "Espagnol"
#: allianceauth/authentication/models.py:83
#: allianceauth/authentication/models.py:74
msgid "Chinese Simplified"
msgstr "Chinois simplifié"
#: allianceauth/authentication/models.py:84
#: allianceauth/authentication/models.py:75
msgid "Russian"
msgstr "Russe"
#: allianceauth/authentication/models.py:85
#: allianceauth/authentication/models.py:76
msgid "Korean"
msgstr "Coréen"
#: allianceauth/authentication/models.py:86
#: allianceauth/authentication/models.py:77
msgid "French"
msgstr "Français"
#: allianceauth/authentication/models.py:87
#: allianceauth/authentication/models.py:78
msgid "Japanese"
msgstr "Japonais"
#: allianceauth/authentication/models.py:88
#: allianceauth/authentication/models.py:79
msgid "Italian"
msgstr "Italien"
#: allianceauth/authentication/models.py:91
#: allianceauth/authentication/models.py:80
msgid "Ukrainian"
msgstr ""
#: allianceauth/authentication/models.py:96
msgid "Language"
msgstr "Langue"
#: allianceauth/authentication/models.py:96
#: allianceauth/authentication/models.py:101
#: allianceauth/templates/allianceauth/night-toggle.html:6
msgid "Night Mode"
msgstr "Mode Nuit"
#: allianceauth/authentication/models.py:110
#: allianceauth/authentication/models.py:115
#, python-format
msgid "State changed to: %s"
msgstr "État changé à: %s"
#: allianceauth/authentication/models.py:111
#: allianceauth/authentication/models.py:116
#, python-format
msgid "Your user's state is now: %(state)s"
msgstr "L'état de votre personnage est maintenant: %(state)s"
#: allianceauth/authentication/templates/authentication/dashboard.html:4
#: allianceauth/authentication/templates/authentication/dashboard.html:7
#: allianceauth/authentication/templates/authentication/tokens.html:4
#: allianceauth/templates/allianceauth/side-menu.html:10
msgid "Dashboard"
msgstr "Écran de bord"
@@ -167,8 +172,50 @@ msgstr "Corpo"
msgid "Alliance"
msgstr "Alliance"
#: allianceauth/authentication/templates/authentication/tokens.html:7
#: allianceauth/templates/allianceauth/top-menu-user-dropdown.html:62
msgid "Token Management"
msgstr ""
#: allianceauth/authentication/templates/authentication/tokens.html:12
msgid "Scopes"
msgstr ""
#: allianceauth/authentication/templates/authentication/tokens.html:13
#: allianceauth/hrapplications/templates/hrapplications/management.html:28
#: allianceauth/hrapplications/templates/hrapplications/management.html:83
#: allianceauth/hrapplications/templates/hrapplications/management.html:127
#: allianceauth/hrapplications/templates/hrapplications/searchview.html:27
#: allianceauth/hrapplications/templates/hrapplications/view.html:73
#: allianceauth/srp/templates/srp/data.html:101
#: allianceauth/srp/templates/srp/management.html:44
msgid "Actions"
msgstr "Actions"
#: allianceauth/authentication/templates/authentication/tokens.html:14
#: allianceauth/corputils/templates/corputils/corpstats.html:74
#: allianceauth/corputils/templates/corputils/corpstats.html:112
#: allianceauth/corputils/templates/corputils/corpstats.html:156
#: allianceauth/corputils/templates/corputils/search.html:13
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkmodify.html:22
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkview.html:26
#: allianceauth/groupmanagement/templates/groupmanagement/audit.html:30
#: allianceauth/groupmanagement/templates/groupmanagement/groupmembers.html:29
#: allianceauth/groupmanagement/templates/groupmanagement/index.html:55
#: allianceauth/groupmanagement/templates/groupmanagement/index.html:112
msgid "Character"
msgstr "Personnage"
#: allianceauth/authentication/templates/authentication/tokens.html:28
msgid ""
"This page is a best attempt, but backups or database logs can still contain "
"your tokens. Always revoke tokens on "
"https://community.eveonline.com/support/third-party-applications/ where "
"possible."
msgstr ""
#: allianceauth/authentication/templates/public/login.html:6
#: allianceauth/templates/allianceauth/top-menu-user-dropdown.html:58
#: allianceauth/templates/allianceauth/top-menu-user-dropdown.html:69
msgid "Login"
msgstr "Connexion"
@@ -202,7 +249,7 @@ msgstr "S'inscrire"
msgid "Invalid or expired activation link."
msgstr "Lien d'activation invalide ou expiré."
#: allianceauth/authentication/views.py:77
#: allianceauth/authentication/views.py:118
#, python-format
msgid ""
"Cannot change main character to %(char)s: character owned by a different "
@@ -211,30 +258,32 @@ msgstr ""
"Impossible de changer le personnage principal à %(char)s. Le personnage "
"appartient à un autre compte."
#: allianceauth/authentication/views.py:83
#: allianceauth/authentication/views.py:124
#, python-format
msgid "Changed main character to %(char)s"
msgstr "Changé le personnage principal à %(char)s"
#: allianceauth/authentication/views.py:92
#: allianceauth/authentication/views.py:133
#, python-format
msgid "Added %(name)s to your account."
msgstr "Ajouté %(name)s à votre compte."
#: allianceauth/authentication/views.py:94
#: allianceauth/authentication/views.py:135
#, python-format
msgid "Failed to add %(name)s to your account: they already have an account."
msgstr "Impossible d'ajouter %(name)s à votre compte: ils ont déjà un compte."
#: allianceauth/authentication/views.py:133
msgid "Unable to authenticate as the selected character."
msgstr "Personnage principal : échec de l'identification."
#: allianceauth/authentication/views.py:178
msgid ""
"Unable to authenticate as the selected character. Please log in with the "
"main character associated with this account."
msgstr ""
#: allianceauth/authentication/views.py:197
#: allianceauth/authentication/views.py:244
msgid "Registration token has expired."
msgstr "Le token d'enregistrement est expiré."
#: allianceauth/authentication/views.py:252
#: allianceauth/authentication/views.py:302
msgid ""
"Sent confirmation email. Please follow the link to confirm your email "
"address."
@@ -242,12 +291,12 @@ msgstr ""
"Email de confirmation envoyé. Cliquez sur le lien pour valider votre adresse"
" email."
#: allianceauth/authentication/views.py:257
#: allianceauth/authentication/views.py:307
msgid "Confirmed your email address. Please login to continue."
msgstr ""
"Votre adresse email a été confirmé. Veuillez vous connecter pour continuer."
#: allianceauth/authentication/views.py:262
#: allianceauth/authentication/views.py:312
msgid "Registration of new accounts is not allowed at this time."
msgstr "La création de nouveaux comptes n'est pas actuellement permise."
@@ -290,19 +339,6 @@ msgstr "Pas inscrit"
msgid "Last update:"
msgstr "Dernière mise à jour:"
#: allianceauth/corputils/templates/corputils/corpstats.html:74
#: allianceauth/corputils/templates/corputils/corpstats.html:112
#: allianceauth/corputils/templates/corputils/corpstats.html:156
#: allianceauth/corputils/templates/corputils/search.html:13
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkmodify.html:22
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkview.html:26
#: allianceauth/groupmanagement/templates/groupmanagement/audit.html:30
#: allianceauth/groupmanagement/templates/groupmanagement/groupmembers.html:29
#: allianceauth/groupmanagement/templates/groupmanagement/index.html:55
#: allianceauth/groupmanagement/templates/groupmanagement/index.html:112
msgid "Character"
msgstr "Personnage"
#: allianceauth/corputils/templates/corputils/corpstats.html:75
#: allianceauth/corputils/templates/corputils/search.html:14
#: allianceauth/groupmanagement/templates/groupmanagement/audit.html:31
@@ -639,19 +675,24 @@ msgstr ""
msgid "Group Management"
msgstr "Gestion de groupe"
#: allianceauth/groupmanagement/forms.py:15
#: allianceauth/groupmanagement/forms.py:18
#: allianceauth/permissions_tool/templates/permissions_tool/overview.html:35
msgid "Users"
msgstr "Utilisateurs"
#: allianceauth/groupmanagement/forms.py:52
msgid "This name has been reserved and can not be used for groups."
msgstr "Ce nom a été réserver et il ne peut être utilisé pour les groupes."
#: allianceauth/groupmanagement/forms.py:25
#: allianceauth/groupmanagement/forms.py:62
msgid "(auto)"
msgstr "(automatique)"
#: allianceauth/groupmanagement/forms.py:34
#: allianceauth/groupmanagement/forms.py:71
msgid "There already exists a group with that name."
msgstr "Il existe déjà un groupe portant ce nom."
#: allianceauth/groupmanagement/models.py:105
#: allianceauth/groupmanagement/models.py:104
msgid ""
"Internal group, users cannot see, join or request to join this "
"group.<br>Used for groups such as Members, Corp_*, Alliance_* "
@@ -662,13 +703,13 @@ msgstr ""
"Corporations _*, Alliance etc.<br><b> Annule les options masquer et exposer "
"quand sélectionner."
#: allianceauth/groupmanagement/models.py:113
#: allianceauth/groupmanagement/models.py:112
msgid "Group is hidden from users but can still join with the correct link."
msgstr ""
"Le groupe est caché aux utilisateurs, mais ils peuvent toujours rejoindre "
"avec le bon lien."
#: allianceauth/groupmanagement/models.py:119
#: allianceauth/groupmanagement/models.py:118
msgid ""
"Group is open and users will be automatically added upon request.<br>If the "
"group is not open users will need their request manually approved."
@@ -677,7 +718,7 @@ msgstr ""
" demande. <br> Si le groupe nest pas ouvert, les utilisateurs auront besoin"
" que leurs demandes soit approuvées manuellement."
#: allianceauth/groupmanagement/models.py:126
#: allianceauth/groupmanagement/models.py:125
msgid ""
"Group is public. Any registered user is able to join this group, with "
"visibility based on the other options set for this group.<br>Auth will not "
@@ -689,7 +730,7 @@ msgstr ""
"groupe.<br> L' Auth ne supprimera pas automatiquement les utilisateurs de ce"
" groupe lorsquils ne seront plus authentifiés."
#: allianceauth/groupmanagement/models.py:135
#: allianceauth/groupmanagement/models.py:134
msgid ""
"Group is restricted. This means that adding or removing users for this group"
" requires a superuser admin."
@@ -697,62 +738,62 @@ msgstr ""
"Le groupe est restreint. Cela signifie que lajout ou la suppression "
"dutilisateurs pour ce groupe nécessite un administrateur superutilisateur."
#: allianceauth/groupmanagement/models.py:144
#: allianceauth/groupmanagement/models.py:143
msgid ""
"Group leaders can process requests for this group. Use the "
"<code>auth.group_management</code> permission to allow a user to manage all "
"groups.<br>"
msgstr ""
#: allianceauth/groupmanagement/models.py:154
#: allianceauth/groupmanagement/models.py:153
msgid ""
"Members of leader groups can process requests for this group. Use the "
"<code>auth.group_management</code> permission to allow a user to manage all "
"groups.<br>"
msgstr ""
#: allianceauth/groupmanagement/models.py:163
#: allianceauth/groupmanagement/models.py:162
msgid ""
"States listed here will have the ability to join this group provided they "
"have the proper permissions.<br>"
msgstr ""
#: allianceauth/groupmanagement/models.py:171
#: allianceauth/groupmanagement/models.py:170
msgid ""
"Short description <i>(max. 512 characters)</i> of the group shown to users."
msgstr ""
"Brève description <i> (512 caractères maximum) </i> du groupe présenté aux "
"utilisateurs."
#: allianceauth/groupmanagement/models.py:178
#: allianceauth/groupmanagement/models.py:177
msgid "Can request non-public groups"
msgstr "Peut demander des groupes non publics"
#: allianceauth/groupmanagement/models.py:209
#: allianceauth/groupmanagement/models.py:208
msgid "name"
msgstr "Nom"
#: allianceauth/groupmanagement/models.py:212
#: allianceauth/groupmanagement/models.py:211
msgid "Name that can not be used for groups."
msgstr "Nom qui ne peut pas être utilisé pour les groupes."
#: allianceauth/groupmanagement/models.py:215
#: allianceauth/groupmanagement/models.py:214
msgid "reason"
msgstr "raison"
#: allianceauth/groupmanagement/models.py:215
#: allianceauth/groupmanagement/models.py:214
msgid "Reason why this name is reserved."
msgstr "Raison pour laquelle ce nom est réservé."
#: allianceauth/groupmanagement/models.py:218
#: allianceauth/groupmanagement/models.py:217
msgid "created by"
msgstr "créé par"
#: allianceauth/groupmanagement/models.py:223
#: allianceauth/groupmanagement/models.py:222
msgid "created at"
msgstr "créé à"
#: allianceauth/groupmanagement/models.py:223
#: allianceauth/groupmanagement/models.py:222
msgid "Date when this entry was created"
msgstr "Date de création de cette entrée"
@@ -979,26 +1020,26 @@ msgstr "Demandes de groupe"
msgid "Group Membership"
msgstr "Groupe appartenance "
#: allianceauth/groupmanagement/views.py:163
#: allianceauth/groupmanagement/views.py:166
#, python-format
msgid "Removed user %(user)s from group %(group)s."
msgstr "L'utilisateur %(user)s à été retiré du groupe %(group)s."
#: allianceauth/groupmanagement/views.py:165
#: allianceauth/groupmanagement/views.py:168
msgid "User does not exist in that group"
msgstr "L'utilisateur n'existe pas dans ce groupe"
#: allianceauth/groupmanagement/views.py:168
#: allianceauth/groupmanagement/views.py:171
msgid "Group does not exist"
msgstr "Groupe non-existant"
#: allianceauth/groupmanagement/views.py:195
#: allianceauth/groupmanagement/views.py:198
#, python-format
msgid "Accepted application from %(mainchar)s to %(group)s."
msgstr "Candidature de %(mainchar)s acceptée à %(group)s."
#: allianceauth/groupmanagement/views.py:201
#: allianceauth/groupmanagement/views.py:232
#: allianceauth/groupmanagement/views.py:204
#: allianceauth/groupmanagement/views.py:235
#, python-format
msgid ""
"An unhandled error occurred while processing the application from "
@@ -1007,18 +1048,18 @@ msgstr ""
"Une erreur inattendue est survenue durant le traitement de l'application de "
"%(mainchar)s à %(group)s."
#: allianceauth/groupmanagement/views.py:226
#: allianceauth/groupmanagement/views.py:229
#, python-format
msgid "Rejected application from %(mainchar)s to %(group)s."
msgstr "L'application de %(mainchar)s à %(group)s est rejetée."
#: allianceauth/groupmanagement/views.py:261
#: allianceauth/groupmanagement/views.py:264
#, python-format
msgid "Accepted application from %(mainchar)s to leave %(group)s."
msgstr "La demande de retirer %(mainchar)s de %(group)s est acceptée."
#: allianceauth/groupmanagement/views.py:266
#: allianceauth/groupmanagement/views.py:298
#: allianceauth/groupmanagement/views.py:269
#: allianceauth/groupmanagement/views.py:301
#, python-format
msgid ""
"An unhandled error occurred while processing the application from "
@@ -1027,42 +1068,42 @@ msgstr ""
"Une erreur inattendue est survenue durant le traitement de la demande de "
"retirer %(mainchar)s de %(group)s."
#: allianceauth/groupmanagement/views.py:292
#: allianceauth/groupmanagement/views.py:295
#, python-format
msgid "Rejected application from %(mainchar)s to leave %(group)s."
msgstr "La remande de retirer %(mainchar)s de %(group)s a été refusée."
#: allianceauth/groupmanagement/views.py:336
#: allianceauth/groupmanagement/views.py:346
#: allianceauth/groupmanagement/views.py:339
#: allianceauth/groupmanagement/views.py:349
msgid "You cannot join that group"
msgstr "Vous ne pouvez pas joindre ce groupe."
#: allianceauth/groupmanagement/views.py:341
#: allianceauth/groupmanagement/views.py:344
msgid "You are already a member of that group."
msgstr "Vous faites déjà parti de ce groupe."
#: allianceauth/groupmanagement/views.py:358
#: allianceauth/groupmanagement/views.py:361
msgid "You already have a pending application for that group."
msgstr "Vous avez déjà une application en attente pour joindre ce groupe."
#: allianceauth/groupmanagement/views.py:367
#: allianceauth/groupmanagement/views.py:370
#, python-format
msgid "Applied to group %(group)s."
msgstr "Appliqué au groupe %(group)s."
#: allianceauth/groupmanagement/views.py:377
#: allianceauth/groupmanagement/views.py:380
msgid "You cannot leave that group"
msgstr "Vous ne pouvez pas quitter ce groupe."
#: allianceauth/groupmanagement/views.py:381
#: allianceauth/groupmanagement/views.py:384
msgid "You are not a member of that group"
msgstr "Vous n'êtes pas un membre de ce groupe."
#: allianceauth/groupmanagement/views.py:393
#: allianceauth/groupmanagement/views.py:396
msgid "You already have a pending leave request for that group."
msgstr "Vous avec déjà une demande de quitter ce groupe en attente."
#: allianceauth/groupmanagement/views.py:409
#: allianceauth/groupmanagement/views.py:412
#, python-format
msgid "Applied to leave group %(group)s."
msgstr "Appliqué pour quitter le groupe %(group)s."
@@ -1124,16 +1165,6 @@ msgstr "Créer une application"
msgid "Username"
msgstr "Nom d'utilisateur"
#: allianceauth/hrapplications/templates/hrapplications/management.html:28
#: allianceauth/hrapplications/templates/hrapplications/management.html:83
#: allianceauth/hrapplications/templates/hrapplications/management.html:127
#: allianceauth/hrapplications/templates/hrapplications/searchview.html:27
#: allianceauth/hrapplications/templates/hrapplications/view.html:73
#: allianceauth/srp/templates/srp/data.html:101
#: allianceauth/srp/templates/srp/management.html:44
msgid "Actions"
msgstr "Actions"
#: allianceauth/hrapplications/templates/hrapplications/management.html:38
#: allianceauth/hrapplications/templates/hrapplications/management.html:99
#: allianceauth/hrapplications/templates/hrapplications/management.html:143
@@ -1472,10 +1503,6 @@ msgstr "Modèle"
msgid "Code Name"
msgstr "Nom De Code"
#: allianceauth/permissions_tool/templates/permissions_tool/overview.html:35
msgid "Users"
msgstr "Utilisateurs"
#: allianceauth/permissions_tool/templates/permissions_tool/overview.html:41
msgid "States"
msgstr "États"
@@ -2217,15 +2244,12 @@ msgstr ""
" "
#: allianceauth/templates/allianceauth/admin-status/overview.html:95
#, python-format
msgid ""
"\n"
" %(queue_length)s queued tasks\n"
" "
msgid "running"
msgstr ""
#: allianceauth/templates/allianceauth/admin-status/overview.html:96
msgid "queued"
msgstr ""
"\n"
" %(queue_length)stâches en file d'attente\n"
" "
#: allianceauth/templates/allianceauth/top-menu-admin.html:9
msgid "Admin"
@@ -2240,11 +2264,11 @@ msgid "AA Support Discord"
msgstr "Support Discord AA"
#: allianceauth/templates/allianceauth/top-menu-user-dropdown.html:10
#: allianceauth/templates/allianceauth/top-menu-user-dropdown.html:14
#: allianceauth/templates/allianceauth/top-menu-user-dropdown.html:16
msgid "User Menu"
msgstr "Menu Utilisateur"
#: allianceauth/templates/allianceauth/top-menu-user-dropdown.html:56
#: allianceauth/templates/allianceauth/top-menu-user-dropdown.html:67
msgid "Logout"
msgstr "Déconnexion"
@@ -2300,22 +2324,30 @@ msgid "Objective"
msgstr "Objectif"
#: allianceauth/timerboard/form.py:64
msgid "Absolute Timer"
msgstr ""
#: allianceauth/timerboard/form.py:65
msgid "Date and Time"
msgstr ""
#: allianceauth/timerboard/form.py:66
msgid "Days Remaining"
msgstr "Jour restants"
#: allianceauth/timerboard/form.py:65
#: allianceauth/timerboard/form.py:67
msgid "Hours Remaining"
msgstr "Heures restantes"
#: allianceauth/timerboard/form.py:67
#: allianceauth/timerboard/form.py:69
msgid "Minutes Remaining"
msgstr "Minutes restantes"
#: allianceauth/timerboard/form.py:69
#: allianceauth/timerboard/form.py:71
msgid "Important"
msgstr "Important"
#: allianceauth/timerboard/form.py:70
#: allianceauth/timerboard/form.py:72
msgid "Corp-Restricted"
msgstr "Limité à la Corporation"

File diff suppressed because it is too large Load Diff

View File

@@ -4,17 +4,18 @@
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
# Translators:
# Foch Petain <brigadier.rockforward@gmail.com>, 2020
# kotaneko, 2023
# Foch Petain <brigadier.rockforward@gmail.com>, 2023
# Joel Falknau <ozirascal@gmail.com>, 2023
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-10-09 18:20+1000\n"
"PO-Revision-Date: 2020-02-18 03:14+0000\n"
"Last-Translator: kotaneko, 2023\n"
"POT-Creation-Date: 2024-02-17 18:50+1000\n"
"PO-Revision-Date: 2023-11-08 13:50+0000\n"
"Last-Translator: Joel Falknau <ozirascal@gmail.com>, 2023\n"
"Language-Team: Japanese (https://app.transifex.com/alliance-auth/teams/107430/ja/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@@ -30,7 +31,7 @@ msgstr "Google ユニバーサル アナリティクス"
msgid "Google Analytics V4"
msgstr "Google アナリティクス 4"
#: allianceauth/authentication/decorators.py:37
#: allianceauth/authentication/decorators.py:49
msgid "A main character is required to perform that action. Add one below."
msgstr "実行するためにはメインキャラクターの設定が必要です。設定してください。"
@@ -43,63 +44,68 @@ msgstr "メールアドレス"
msgid "You are not allowed to add or remove these restricted groups: %s"
msgstr "これらの制限付きグループを追加または削除することはできません。%s"
#: allianceauth/authentication/models.py:80
#: allianceauth/authentication/models.py:71
msgid "English"
msgstr "英語"
#: allianceauth/authentication/models.py:81
#: allianceauth/authentication/models.py:72
msgid "German"
msgstr "ドイツ語"
#: allianceauth/authentication/models.py:82
#: allianceauth/authentication/models.py:73
msgid "Spanish"
msgstr "スペイン語"
#: allianceauth/authentication/models.py:83
#: allianceauth/authentication/models.py:74
msgid "Chinese Simplified"
msgstr "中国語 簡体字"
#: allianceauth/authentication/models.py:84
#: allianceauth/authentication/models.py:75
msgid "Russian"
msgstr "ロシア語"
#: allianceauth/authentication/models.py:85
#: allianceauth/authentication/models.py:76
msgid "Korean"
msgstr "韓国語"
#: allianceauth/authentication/models.py:86
#: allianceauth/authentication/models.py:77
msgid "French"
msgstr "フランス語"
#: allianceauth/authentication/models.py:87
#: allianceauth/authentication/models.py:78
msgid "Japanese"
msgstr "日本語"
#: allianceauth/authentication/models.py:88
#: allianceauth/authentication/models.py:79
msgid "Italian"
msgstr "イタリア語"
#: allianceauth/authentication/models.py:91
#: allianceauth/authentication/models.py:80
msgid "Ukrainian"
msgstr ""
#: allianceauth/authentication/models.py:96
msgid "Language"
msgstr "言語"
#: allianceauth/authentication/models.py:96
#: allianceauth/authentication/models.py:101
#: allianceauth/templates/allianceauth/night-toggle.html:6
msgid "Night Mode"
msgstr "ナイトモード"
#: allianceauth/authentication/models.py:110
#: allianceauth/authentication/models.py:115
#, python-format
msgid "State changed to: %s"
msgstr "分類が%sに変更されました。"
#: allianceauth/authentication/models.py:111
#: allianceauth/authentication/models.py:116
#, python-format
msgid "Your user's state is now: %(state)s"
msgstr "あなたの分類は%(state)sになりました。"
#: allianceauth/authentication/templates/authentication/dashboard.html:4
#: allianceauth/authentication/templates/authentication/dashboard.html:7
#: allianceauth/authentication/templates/authentication/tokens.html:4
#: allianceauth/templates/allianceauth/side-menu.html:10
msgid "Dashboard"
msgstr "ダッシュボード"
@@ -157,8 +163,50 @@ msgstr "Corp"
msgid "Alliance"
msgstr "Alliance"
#: allianceauth/authentication/templates/authentication/tokens.html:7
#: allianceauth/templates/allianceauth/top-menu-user-dropdown.html:62
msgid "Token Management"
msgstr ""
#: allianceauth/authentication/templates/authentication/tokens.html:12
msgid "Scopes"
msgstr ""
#: allianceauth/authentication/templates/authentication/tokens.html:13
#: allianceauth/hrapplications/templates/hrapplications/management.html:28
#: allianceauth/hrapplications/templates/hrapplications/management.html:83
#: allianceauth/hrapplications/templates/hrapplications/management.html:127
#: allianceauth/hrapplications/templates/hrapplications/searchview.html:27
#: allianceauth/hrapplications/templates/hrapplications/view.html:73
#: allianceauth/srp/templates/srp/data.html:101
#: allianceauth/srp/templates/srp/management.html:44
msgid "Actions"
msgstr "アクション"
#: allianceauth/authentication/templates/authentication/tokens.html:14
#: allianceauth/corputils/templates/corputils/corpstats.html:74
#: allianceauth/corputils/templates/corputils/corpstats.html:112
#: allianceauth/corputils/templates/corputils/corpstats.html:156
#: allianceauth/corputils/templates/corputils/search.html:13
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkmodify.html:22
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkview.html:26
#: allianceauth/groupmanagement/templates/groupmanagement/audit.html:30
#: allianceauth/groupmanagement/templates/groupmanagement/groupmembers.html:29
#: allianceauth/groupmanagement/templates/groupmanagement/index.html:55
#: allianceauth/groupmanagement/templates/groupmanagement/index.html:112
msgid "Character"
msgstr "キャラクター"
#: allianceauth/authentication/templates/authentication/tokens.html:28
msgid ""
"This page is a best attempt, but backups or database logs can still contain "
"your tokens. Always revoke tokens on "
"https://community.eveonline.com/support/third-party-applications/ where "
"possible."
msgstr ""
#: allianceauth/authentication/templates/public/login.html:6
#: allianceauth/templates/allianceauth/top-menu-user-dropdown.html:58
#: allianceauth/templates/allianceauth/top-menu-user-dropdown.html:69
msgid "Login"
msgstr "ログイン"
@@ -190,47 +238,49 @@ msgstr "登録"
msgid "Invalid or expired activation link."
msgstr "アクティベーションリンクが無効か期限切れです。"
#: allianceauth/authentication/views.py:77
#: allianceauth/authentication/views.py:118
#, python-format
msgid ""
"Cannot change main character to %(char)s: character owned by a different "
"account."
msgstr "メインキャラクターを%(char)sへ変更できません。別のアカウントによって利用されています。"
#: allianceauth/authentication/views.py:83
#: allianceauth/authentication/views.py:124
#, python-format
msgid "Changed main character to %(char)s"
msgstr "メインキャラクターを%(char)sへ変更しました。"
#: allianceauth/authentication/views.py:92
#: allianceauth/authentication/views.py:133
#, python-format
msgid "Added %(name)s to your account."
msgstr "%(name)sをアカウントに追加しました。"
#: allianceauth/authentication/views.py:94
#: allianceauth/authentication/views.py:135
#, python-format
msgid "Failed to add %(name)s to your account: they already have an account."
msgstr "%(name)sをアカウントに追加することができません。すでに他のアカウントを持っています。"
#: allianceauth/authentication/views.py:133
msgid "Unable to authenticate as the selected character."
msgstr "選択されたキャラクターの認証が行えませんでした。"
#: allianceauth/authentication/views.py:178
msgid ""
"Unable to authenticate as the selected character. Please log in with the "
"main character associated with this account."
msgstr ""
#: allianceauth/authentication/views.py:197
#: allianceauth/authentication/views.py:244
msgid "Registration token has expired."
msgstr "Registrationトークンが有効期限切れです。"
#: allianceauth/authentication/views.py:252
#: allianceauth/authentication/views.py:302
msgid ""
"Sent confirmation email. Please follow the link to confirm your email "
"address."
msgstr "確認のメールを送信しました。メール内のリンクをご確認の上、メールアドレスの認証を完了させてください。"
#: allianceauth/authentication/views.py:257
#: allianceauth/authentication/views.py:307
msgid "Confirmed your email address. Please login to continue."
msgstr "メールアドレスを確認しました。続行するにはログインしてください。"
#: allianceauth/authentication/views.py:262
#: allianceauth/authentication/views.py:312
msgid "Registration of new accounts is not allowed at this time."
msgstr "新規アカウントの登録は、現時点ではできません。"
@@ -273,19 +323,6 @@ msgstr "未登録"
msgid "Last update:"
msgstr "最終更新:"
#: allianceauth/corputils/templates/corputils/corpstats.html:74
#: allianceauth/corputils/templates/corputils/corpstats.html:112
#: allianceauth/corputils/templates/corputils/corpstats.html:156
#: allianceauth/corputils/templates/corputils/search.html:13
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkmodify.html:22
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkview.html:26
#: allianceauth/groupmanagement/templates/groupmanagement/audit.html:30
#: allianceauth/groupmanagement/templates/groupmanagement/groupmembers.html:29
#: allianceauth/groupmanagement/templates/groupmanagement/index.html:55
#: allianceauth/groupmanagement/templates/groupmanagement/index.html:112
msgid "Character"
msgstr "キャラクター"
#: allianceauth/corputils/templates/corputils/corpstats.html:75
#: allianceauth/corputils/templates/corputils/search.html:14
#: allianceauth/groupmanagement/templates/groupmanagement/audit.html:31
@@ -615,19 +652,24 @@ msgstr "{character.character_name} のフリート参加を登録できません
msgid "Group Management"
msgstr "グループ管理"
#: allianceauth/groupmanagement/forms.py:15
#: allianceauth/groupmanagement/forms.py:18
#: allianceauth/permissions_tool/templates/permissions_tool/overview.html:35
msgid "Users"
msgstr "ユーザ"
#: allianceauth/groupmanagement/forms.py:52
msgid "This name has been reserved and can not be used for groups."
msgstr "この名前は予約済みで、グループには使用できません。"
#: allianceauth/groupmanagement/forms.py:25
#: allianceauth/groupmanagement/forms.py:62
msgid "(auto)"
msgstr "(auto)"
#: allianceauth/groupmanagement/forms.py:34
#: allianceauth/groupmanagement/forms.py:71
msgid "There already exists a group with that name."
msgstr "その名前のグループが既に存在しています。"
#: allianceauth/groupmanagement/models.py:105
#: allianceauth/groupmanagement/models.py:104
msgid ""
"Internal group, users cannot see, join or request to join this "
"group.<br>Used for groups such as Members, Corp_*, Alliance_* "
@@ -636,18 +678,18 @@ msgstr ""
"内部グループです。ユーザーはこのグループを表示したり、参加したり、参加をリクエストしたりすることはできません。<br>Members、Corp_*、Alliance_*などのグループに使用します。選択すると、非表示"
" オプションと 開く <br> <b> オプションが上書きされます。</b> "
#: allianceauth/groupmanagement/models.py:113
#: allianceauth/groupmanagement/models.py:112
msgid "Group is hidden from users but can still join with the correct link."
msgstr "グループはユーザーに表示されませんが、正しいリンク経由で参加することができます。"
#: allianceauth/groupmanagement/models.py:119
#: allianceauth/groupmanagement/models.py:118
msgid ""
"Group is open and users will be automatically added upon request.<br>If the "
"group is not open users will need their request manually approved."
msgstr ""
"グループはオープンで、ユーザーはリクエストに応じて自動的に追加されます。<br>グループがオープンでない場合、ユーザーのリクエストは手動で承認する必要があります。"
#: allianceauth/groupmanagement/models.py:126
#: allianceauth/groupmanagement/models.py:125
msgid ""
"Group is public. Any registered user is able to join this group, with "
"visibility based on the other options set for this group.<br>Auth will not "
@@ -657,13 +699,13 @@ msgstr ""
"グループは一般公開されています。登録ユーザーなら誰でもこのグループに参加でき、このグループに設定されている他のオプションに基づいて表示されます。<br>認証されなくなっても、Auth"
" はユーザーをこのグループから自動的に削除しません。"
#: allianceauth/groupmanagement/models.py:135
#: allianceauth/groupmanagement/models.py:134
msgid ""
"Group is restricted. This means that adding or removing users for this group"
" requires a superuser admin."
msgstr "グループは参加が制限されています。つまり、このグループのユーザーを追加または削除するには、スーパーユーザー管理者が必要です。"
#: allianceauth/groupmanagement/models.py:144
#: allianceauth/groupmanagement/models.py:143
msgid ""
"Group leaders can process requests for this group. Use the "
"<code>auth.group_management</code> permission to allow a user to manage all "
@@ -672,7 +714,7 @@ msgstr ""
"グループリーダーは、このグループのリクエストを処理できます。<code>auth.group_management </code> "
"権限を使用して、ユーザーがすべてのグループを管理できるようにします。<br> "
#: allianceauth/groupmanagement/models.py:154
#: allianceauth/groupmanagement/models.py:153
msgid ""
"Members of leader groups can process requests for this group. Use the "
"<code>auth.group_management</code> permission to allow a user to manage all "
@@ -681,46 +723,46 @@ msgstr ""
"リーダーグループのメンバーは、このグループのリクエストを処理できます。<code>auth.group_management </code> "
"権限を使用して、ユーザーがすべてのグループを管理できるようにします。<br> "
#: allianceauth/groupmanagement/models.py:163
#: allianceauth/groupmanagement/models.py:162
msgid ""
"States listed here will have the ability to join this group provided they "
"have the proper permissions.<br>"
msgstr "ここに記載されているStatesは、適切な許可があれば、このグループに参加できます。<br> "
#: allianceauth/groupmanagement/models.py:171
#: allianceauth/groupmanagement/models.py:170
msgid ""
"Short description <i>(max. 512 characters)</i> of the group shown to users."
msgstr "ユーザーに表示されるグループの簡単な説明 <i> (最大 512 文字) </i>。"
#: allianceauth/groupmanagement/models.py:178
#: allianceauth/groupmanagement/models.py:177
msgid "Can request non-public groups"
msgstr "非公開グループをリクエストできる"
#: allianceauth/groupmanagement/models.py:209
#: allianceauth/groupmanagement/models.py:208
msgid "name"
msgstr "名前"
#: allianceauth/groupmanagement/models.py:212
#: allianceauth/groupmanagement/models.py:211
msgid "Name that can not be used for groups."
msgstr "グループには使用できない名前。"
#: allianceauth/groupmanagement/models.py:215
#: allianceauth/groupmanagement/models.py:214
msgid "reason"
msgstr "理由"
#: allianceauth/groupmanagement/models.py:215
#: allianceauth/groupmanagement/models.py:214
msgid "Reason why this name is reserved."
msgstr "この名前が使用予約されている理由。"
#: allianceauth/groupmanagement/models.py:218
#: allianceauth/groupmanagement/models.py:217
msgid "created by"
msgstr "作成者"
#: allianceauth/groupmanagement/models.py:223
#: allianceauth/groupmanagement/models.py:222
msgid "created at"
msgstr "作成日時"
#: allianceauth/groupmanagement/models.py:223
#: allianceauth/groupmanagement/models.py:222
msgid "Date when this entry was created"
msgstr "このエントリが作成された日付"
@@ -947,86 +989,86 @@ msgstr "グループリクエスト"
msgid "Group Membership"
msgstr "グループメンバーシップ"
#: allianceauth/groupmanagement/views.py:163
#: allianceauth/groupmanagement/views.py:166
#, python-format
msgid "Removed user %(user)s from group %(group)s."
msgstr "%(user)sを%(group)sから削除する。"
#: allianceauth/groupmanagement/views.py:165
#: allianceauth/groupmanagement/views.py:168
msgid "User does not exist in that group"
msgstr "誰もグループに参加してません。"
#: allianceauth/groupmanagement/views.py:168
#: allianceauth/groupmanagement/views.py:171
msgid "Group does not exist"
msgstr "グループが存在しません。"
#: allianceauth/groupmanagement/views.py:195
#: allianceauth/groupmanagement/views.py:198
#, python-format
msgid "Accepted application from %(mainchar)s to %(group)s."
msgstr "%(mainchar)sからの%(group)sへの参加申請を承認しました。"
#: allianceauth/groupmanagement/views.py:201
#: allianceauth/groupmanagement/views.py:232
#: allianceauth/groupmanagement/views.py:204
#: allianceauth/groupmanagement/views.py:235
#, 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:226
#: allianceauth/groupmanagement/views.py:229
#, python-format
msgid "Rejected application from %(mainchar)s to %(group)s."
msgstr "%(mainchar)sからの%(group)sへの参加申請は拒否されました。"
#: allianceauth/groupmanagement/views.py:261
#: allianceauth/groupmanagement/views.py:264
#, python-format
msgid "Accepted application from %(mainchar)s to leave %(group)s."
msgstr "%(mainchar)sからの%(group)sからの脱退申請は承認されました。"
#: allianceauth/groupmanagement/views.py:266
#: allianceauth/groupmanagement/views.py:298
#: allianceauth/groupmanagement/views.py:269
#: allianceauth/groupmanagement/views.py:301
#, python-format
msgid ""
"An unhandled error occurred while processing the application from "
"%(mainchar)s to leave %(group)s."
msgstr "%(mainchar)sからの%(group)sからの脱退申請を処理中にエラーが発生しました。"
#: allianceauth/groupmanagement/views.py:292
#: allianceauth/groupmanagement/views.py:295
#, python-format
msgid "Rejected application from %(mainchar)s to leave %(group)s."
msgstr "%(mainchar)sの%(group)sからの脱退申請は拒否されました。"
#: allianceauth/groupmanagement/views.py:336
#: allianceauth/groupmanagement/views.py:346
#: allianceauth/groupmanagement/views.py:339
#: allianceauth/groupmanagement/views.py:349
msgid "You cannot join that group"
msgstr "このGroupには入れません"
#: allianceauth/groupmanagement/views.py:341
#: allianceauth/groupmanagement/views.py:344
msgid "You are already a member of that group."
msgstr "すでにその Group に参加してます。"
#: allianceauth/groupmanagement/views.py:358
#: allianceauth/groupmanagement/views.py:361
msgid "You already have a pending application for that group."
msgstr "すでに参加申請を送付済みです。"
#: allianceauth/groupmanagement/views.py:367
#: allianceauth/groupmanagement/views.py:370
#, python-format
msgid "Applied to group %(group)s."
msgstr "%(group)sへの参加申請を送信しました。"
#: allianceauth/groupmanagement/views.py:377
#: allianceauth/groupmanagement/views.py:380
msgid "You cannot leave that group"
msgstr "この Group から脱退することはできません"
#: allianceauth/groupmanagement/views.py:381
#: allianceauth/groupmanagement/views.py:384
msgid "You are not a member of that group"
msgstr "あなたはその Group のメンバーではありません"
#: allianceauth/groupmanagement/views.py:393
#: allianceauth/groupmanagement/views.py:396
msgid "You already have a pending leave request for that group."
msgstr "すでに脱退申請を送信済みです。"
#: allianceauth/groupmanagement/views.py:409
#: allianceauth/groupmanagement/views.py:412
#, python-format
msgid "Applied to leave group %(group)s."
msgstr "%(group)sからの脱退申請を送信しました。"
@@ -1088,16 +1130,6 @@ msgstr "申請を作成"
msgid "Username"
msgstr "ユーザー名"
#: allianceauth/hrapplications/templates/hrapplications/management.html:28
#: allianceauth/hrapplications/templates/hrapplications/management.html:83
#: allianceauth/hrapplications/templates/hrapplications/management.html:127
#: allianceauth/hrapplications/templates/hrapplications/searchview.html:27
#: allianceauth/hrapplications/templates/hrapplications/view.html:73
#: allianceauth/srp/templates/srp/data.html:101
#: allianceauth/srp/templates/srp/management.html:44
msgid "Actions"
msgstr "アクション"
#: allianceauth/hrapplications/templates/hrapplications/management.html:38
#: allianceauth/hrapplications/templates/hrapplications/management.html:99
#: allianceauth/hrapplications/templates/hrapplications/management.html:143
@@ -1436,10 +1468,6 @@ msgstr "モデル"
msgid "Code Name"
msgstr "コードネーム"
#: allianceauth/permissions_tool/templates/permissions_tool/overview.html:35
msgid "Users"
msgstr "ユーザ"
#: allianceauth/permissions_tool/templates/permissions_tool/overview.html:41
msgid "States"
msgstr "States"
@@ -2170,15 +2198,12 @@ msgstr ""
" "
#: allianceauth/templates/allianceauth/admin-status/overview.html:95
#, python-format
msgid ""
"\n"
" %(queue_length)s queued tasks\n"
" "
msgid "running"
msgstr ""
#: allianceauth/templates/allianceauth/admin-status/overview.html:96
msgid "queued"
msgstr ""
"\n"
" %(queue_length)sキューに入っているタスク\n"
" "
#: allianceauth/templates/allianceauth/top-menu-admin.html:9
msgid "Admin"
@@ -2193,11 +2218,11 @@ msgid "AA Support Discord"
msgstr "AA サポートディスコード"
#: allianceauth/templates/allianceauth/top-menu-user-dropdown.html:10
#: allianceauth/templates/allianceauth/top-menu-user-dropdown.html:14
#: allianceauth/templates/allianceauth/top-menu-user-dropdown.html:16
msgid "User Menu"
msgstr "ユーザーメニュー"
#: allianceauth/templates/allianceauth/top-menu-user-dropdown.html:56
#: allianceauth/templates/allianceauth/top-menu-user-dropdown.html:67
msgid "Logout"
msgstr "ログアウト"
@@ -2253,22 +2278,30 @@ msgid "Objective"
msgstr "目標"
#: allianceauth/timerboard/form.py:64
msgid "Absolute Timer"
msgstr ""
#: allianceauth/timerboard/form.py:65
msgid "Date and Time"
msgstr ""
#: allianceauth/timerboard/form.py:66
msgid "Days Remaining"
msgstr "残り日数"
#: allianceauth/timerboard/form.py:65
#: allianceauth/timerboard/form.py:67
msgid "Hours Remaining"
msgstr "残り時間"
#: allianceauth/timerboard/form.py:67
#: allianceauth/timerboard/form.py:69
msgid "Minutes Remaining"
msgstr "残り分数"
#: allianceauth/timerboard/form.py:69
#: allianceauth/timerboard/form.py:71
msgid "Important"
msgstr "重要"
#: allianceauth/timerboard/form.py:70
#: allianceauth/timerboard/form.py:72
msgid "Corp-Restricted"
msgstr "コーポレーション制限付き"

View File

@@ -4,22 +4,22 @@
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
# Translators:
# None None <khd1226543@gmail.com>, 2020
# Seowon Jung <seowon@hawaii.edu>, 2020
# Olgeda Choi <undead.choi@gmail.com>, 2020
# Lahty <js03js70@gmail.com>, 2020
# Joel Falknau <ozirascal@gmail.com>, 2020
# ThatRagingKid, 2022
# jackfrost, 2022
# Joel Falknau <ozirascal@gmail.com>, 2023
# None None <khd1226543@gmail.com>, 2023
# ThatRagingKid, 2023
# Lahty <js03js70@gmail.com>, 2023
# Olgeda Choi <undead.choi@gmail.com>, 2023
# Seowon Jung <seowon@hawaii.edu>, 2023
# Alpha, 2023
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-10-09 18:20+1000\n"
"PO-Revision-Date: 2020-02-18 03:14+0000\n"
"Last-Translator: jackfrost, 2022\n"
"POT-Creation-Date: 2024-02-17 18:50+1000\n"
"PO-Revision-Date: 2023-11-08 13:50+0000\n"
"Last-Translator: Alpha, 2023\n"
"Language-Team: Korean (Korea) (https://app.transifex.com/alliance-auth/teams/107430/ko_KR/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@@ -35,7 +35,7 @@ msgstr "Google 애널리틱스 유니버설"
msgid "Google Analytics V4"
msgstr "Google 애널리틱스 V4"
#: allianceauth/authentication/decorators.py:37
#: allianceauth/authentication/decorators.py:49
msgid "A main character is required to perform that action. Add one below."
msgstr "해당 기능을 수행하려면 주 캐릭터가 요구됩니다. 아래에서 하나를 추가하시오."
@@ -48,63 +48,68 @@ msgstr "이메일"
msgid "You are not allowed to add or remove these restricted groups: %s"
msgstr ""
#: allianceauth/authentication/models.py:80
#: allianceauth/authentication/models.py:71
msgid "English"
msgstr "영어"
#: allianceauth/authentication/models.py:81
#: allianceauth/authentication/models.py:72
msgid "German"
msgstr "독일어"
#: allianceauth/authentication/models.py:82
#: allianceauth/authentication/models.py:73
msgid "Spanish"
msgstr "스페인어"
#: allianceauth/authentication/models.py:83
#: allianceauth/authentication/models.py:74
msgid "Chinese Simplified"
msgstr "간체자"
#: allianceauth/authentication/models.py:84
#: allianceauth/authentication/models.py:75
msgid "Russian"
msgstr "러시아어"
#: allianceauth/authentication/models.py:85
#: allianceauth/authentication/models.py:76
msgid "Korean"
msgstr "한국어"
#: allianceauth/authentication/models.py:86
#: allianceauth/authentication/models.py:77
msgid "French"
msgstr "프랑스어"
#: allianceauth/authentication/models.py:87
#: allianceauth/authentication/models.py:78
msgid "Japanese"
msgstr "일본어"
#: allianceauth/authentication/models.py:88
#: allianceauth/authentication/models.py:79
msgid "Italian"
msgstr "이탈리아어"
#: allianceauth/authentication/models.py:91
msgid "Language"
#: allianceauth/authentication/models.py:80
msgid "Ukrainian"
msgstr ""
#: allianceauth/authentication/models.py:96
msgid "Language"
msgstr ""
#: allianceauth/authentication/models.py:101
#: allianceauth/templates/allianceauth/night-toggle.html:6
msgid "Night Mode"
msgstr "야간 모드"
#: allianceauth/authentication/models.py:110
#: allianceauth/authentication/models.py:115
#, python-format
msgid "State changed to: %s"
msgstr "상태가 %s로 변경됐습니다."
#: allianceauth/authentication/models.py:111
#: allianceauth/authentication/models.py:116
#, python-format
msgid "Your user's state is now: %(state)s"
msgstr "사용자의 상태는 %(state)s입니다."
#: allianceauth/authentication/templates/authentication/dashboard.html:4
#: allianceauth/authentication/templates/authentication/dashboard.html:7
#: allianceauth/authentication/templates/authentication/tokens.html:4
#: allianceauth/templates/allianceauth/side-menu.html:10
msgid "Dashboard"
msgstr "대시보드"
@@ -163,8 +168,50 @@ msgstr "코퍼레이션"
msgid "Alliance"
msgstr "얼라이언스"
#: allianceauth/authentication/templates/authentication/tokens.html:7
#: allianceauth/templates/allianceauth/top-menu-user-dropdown.html:62
msgid "Token Management"
msgstr ""
#: allianceauth/authentication/templates/authentication/tokens.html:12
msgid "Scopes"
msgstr ""
#: allianceauth/authentication/templates/authentication/tokens.html:13
#: allianceauth/hrapplications/templates/hrapplications/management.html:28
#: allianceauth/hrapplications/templates/hrapplications/management.html:83
#: allianceauth/hrapplications/templates/hrapplications/management.html:127
#: allianceauth/hrapplications/templates/hrapplications/searchview.html:27
#: allianceauth/hrapplications/templates/hrapplications/view.html:73
#: allianceauth/srp/templates/srp/data.html:101
#: allianceauth/srp/templates/srp/management.html:44
msgid "Actions"
msgstr "활동"
#: allianceauth/authentication/templates/authentication/tokens.html:14
#: allianceauth/corputils/templates/corputils/corpstats.html:74
#: allianceauth/corputils/templates/corputils/corpstats.html:112
#: allianceauth/corputils/templates/corputils/corpstats.html:156
#: allianceauth/corputils/templates/corputils/search.html:13
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkmodify.html:22
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkview.html:26
#: allianceauth/groupmanagement/templates/groupmanagement/audit.html:30
#: allianceauth/groupmanagement/templates/groupmanagement/groupmembers.html:29
#: allianceauth/groupmanagement/templates/groupmanagement/index.html:55
#: allianceauth/groupmanagement/templates/groupmanagement/index.html:112
msgid "Character"
msgstr "캐릭터"
#: allianceauth/authentication/templates/authentication/tokens.html:28
msgid ""
"This page is a best attempt, but backups or database logs can still contain "
"your tokens. Always revoke tokens on "
"https://community.eveonline.com/support/third-party-applications/ where "
"possible."
msgstr ""
#: allianceauth/authentication/templates/public/login.html:6
#: allianceauth/templates/allianceauth/top-menu-user-dropdown.html:58
#: allianceauth/templates/allianceauth/top-menu-user-dropdown.html:69
msgid "Login"
msgstr "로그인"
@@ -196,47 +243,49 @@ msgstr "등록"
msgid "Invalid or expired activation link."
msgstr "유효하지 않거나 만료된 활성화 주소"
#: allianceauth/authentication/views.py:77
#: allianceauth/authentication/views.py:118
#, python-format
msgid ""
"Cannot change main character to %(char)s: character owned by a different "
"account."
msgstr "%(char)s를 주 캐릭터로 변경할 수 없음: 다른 계정이 해당 캐릭터를 소유하고 있습니다."
#: allianceauth/authentication/views.py:83
#: allianceauth/authentication/views.py:124
#, python-format
msgid "Changed main character to %(char)s"
msgstr "주 캐릭터가 %(char)s로 변경됨"
#: allianceauth/authentication/views.py:92
#: allianceauth/authentication/views.py:133
#, python-format
msgid "Added %(name)s to your account."
msgstr "계정에 %(name)s를 추가했습니다."
#: allianceauth/authentication/views.py:94
#: allianceauth/authentication/views.py:135
#, python-format
msgid "Failed to add %(name)s to your account: they already have an account."
msgstr "계정에 %(name)s를 추가하지 못했습니다. 이미 다른 계정에 추가되었습니다."
#: allianceauth/authentication/views.py:133
msgid "Unable to authenticate as the selected character."
msgstr "선택한 캐릭터로 인증할 수 없습니다."
#: allianceauth/authentication/views.py:178
msgid ""
"Unable to authenticate as the selected character. Please log in with the "
"main character associated with this account."
msgstr ""
#: allianceauth/authentication/views.py:197
#: allianceauth/authentication/views.py:244
msgid "Registration token has expired."
msgstr "가입 토큰이 만료되었습니다."
#: allianceauth/authentication/views.py:252
#: allianceauth/authentication/views.py:302
msgid ""
"Sent confirmation email. Please follow the link to confirm your email "
"address."
msgstr "확인 메일 전송됨. 다음 링크를 눌러 이메일 주소를 확인하세요."
#: allianceauth/authentication/views.py:257
#: allianceauth/authentication/views.py:307
msgid "Confirmed your email address. Please login to continue."
msgstr "이메일 주소가 확인되었습니다. 로그인 해주세요."
#: allianceauth/authentication/views.py:262
#: allianceauth/authentication/views.py:312
msgid "Registration of new accounts is not allowed at this time."
msgstr "현재 새로운 계정 등록은 받지않습니다."
@@ -279,19 +328,6 @@ msgstr "미등록"
msgid "Last update:"
msgstr "마지막 업데이트:"
#: allianceauth/corputils/templates/corputils/corpstats.html:74
#: allianceauth/corputils/templates/corputils/corpstats.html:112
#: allianceauth/corputils/templates/corputils/corpstats.html:156
#: allianceauth/corputils/templates/corputils/search.html:13
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkmodify.html:22
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkview.html:26
#: allianceauth/groupmanagement/templates/groupmanagement/audit.html:30
#: allianceauth/groupmanagement/templates/groupmanagement/groupmembers.html:29
#: allianceauth/groupmanagement/templates/groupmanagement/index.html:55
#: allianceauth/groupmanagement/templates/groupmanagement/index.html:112
msgid "Character"
msgstr "캐릭터"
#: allianceauth/corputils/templates/corputils/corpstats.html:75
#: allianceauth/corputils/templates/corputils/search.html:14
#: allianceauth/groupmanagement/templates/groupmanagement/audit.html:31
@@ -621,19 +657,24 @@ msgstr ""
msgid "Group Management"
msgstr "그룹 관리"
#: allianceauth/groupmanagement/forms.py:15
#: allianceauth/groupmanagement/forms.py:18
#: allianceauth/permissions_tool/templates/permissions_tool/overview.html:35
msgid "Users"
msgstr "사용자"
#: allianceauth/groupmanagement/forms.py:52
msgid "This name has been reserved and can not be used for groups."
msgstr "이 이름은 이미 사용되었으며 그룹의 이름으로 사용될 수 없습니다."
#: allianceauth/groupmanagement/forms.py:25
#: allianceauth/groupmanagement/forms.py:62
msgid "(auto)"
msgstr "(자동)"
#: allianceauth/groupmanagement/forms.py:34
#: allianceauth/groupmanagement/forms.py:71
msgid "There already exists a group with that name."
msgstr "이 이름을 가진 그룹이 이미 있습니다."
#: allianceauth/groupmanagement/models.py:105
#: allianceauth/groupmanagement/models.py:104
msgid ""
"Internal group, users cannot see, join or request to join this "
"group.<br>Used for groups such as Members, Corp_*, Alliance_* "
@@ -642,11 +683,11 @@ msgstr ""
"시스템 그룹, 유저들은 이 그룹을 보거나, 참여하거나, 지원할 수 없습니다. <br>멤버, 코퍼레이션_*, 얼라이언스_* 등에 "
"사용됨.<br><b>선택된 경우 비공개와 공개 옵션을 무시함.</b>"
#: allianceauth/groupmanagement/models.py:113
#: allianceauth/groupmanagement/models.py:112
msgid "Group is hidden from users but can still join with the correct link."
msgstr "비공개 그룹이지만 링크를 통해 참여할 수 있음."
#: allianceauth/groupmanagement/models.py:119
#: allianceauth/groupmanagement/models.py:118
msgid ""
"Group is open and users will be automatically added upon request.<br>If the "
"group is not open users will need their request manually approved."
@@ -654,7 +695,7 @@ msgstr ""
"그룹은 공개되어 있으며 요청 시 유저는 자동적으로 추가됩니다.<br>그룹이 공개되어 있지 않은 경우, 유저는 직접 요청을 승인받아야 "
"합니다."
#: allianceauth/groupmanagement/models.py:126
#: allianceauth/groupmanagement/models.py:125
msgid ""
"Group is public. Any registered user is able to join this group, with "
"visibility based on the other options set for this group.<br>Auth will not "
@@ -664,13 +705,13 @@ msgstr ""
"공개 그룹입니다. 등록된 모든 유저는 이 그룹에 참여할 수 있으며, 이 그룹의 설정에 따라 공개 여부가 달라집니다.<br>유저가 더 "
"이상 인증을 하지 않을 때, Auth는 이 그룹에서 유저를 자동 추방하지 않습니다."
#: allianceauth/groupmanagement/models.py:135
#: allianceauth/groupmanagement/models.py:134
msgid ""
"Group is restricted. This means that adding or removing users for this group"
" requires a superuser admin."
msgstr ""
#: allianceauth/groupmanagement/models.py:144
#: allianceauth/groupmanagement/models.py:143
msgid ""
"Group leaders can process requests for this group. Use the "
"<code>auth.group_management</code> permission to allow a user to manage all "
@@ -679,7 +720,7 @@ msgstr ""
"그룹 리더는 이 그룹의 요청을 처리할 수 있습니다. <code>auth.group_management</code> 권한을 사용하여 "
"사용자가 모든 그룹을 관리할 수 있도록 합니다.<br>"
#: allianceauth/groupmanagement/models.py:154
#: allianceauth/groupmanagement/models.py:153
msgid ""
"Members of leader groups can process requests for this group. Use the "
"<code>auth.group_management</code> permission to allow a user to manage all "
@@ -688,46 +729,46 @@ msgstr ""
"리더 그룹의 구성원은 이 그룹에 대한 요청을 처리할 수 있습니다. <code>1auth.group_management1</code> "
"권한을 사용하여 사용자가 모든 그룹을 관리할 수 있도록 합니다.<br>"
#: allianceauth/groupmanagement/models.py:163
#: allianceauth/groupmanagement/models.py:162
msgid ""
"States listed here will have the ability to join this group provided they "
"have the proper permissions.<br>"
msgstr "만약 그들이 적절한 권한을 가졌다면, 여기 목록에 있는 신분 상태는 이 그룹에 가입할 수 있습니다."
#: allianceauth/groupmanagement/models.py:171
#: allianceauth/groupmanagement/models.py:170
msgid ""
"Short description <i>(max. 512 characters)</i> of the group shown to users."
msgstr "사용자에게 나타나는 그룹에 대한 간단한 설명 <i>(최대 512자)</i> 입니다."
#: allianceauth/groupmanagement/models.py:178
#: allianceauth/groupmanagement/models.py:177
msgid "Can request non-public groups"
msgstr "공용 그룹에 가입할 수 없음"
#: allianceauth/groupmanagement/models.py:209
#: allianceauth/groupmanagement/models.py:208
msgid "name"
msgstr "이름"
#: allianceauth/groupmanagement/models.py:212
#: allianceauth/groupmanagement/models.py:211
msgid "Name that can not be used for groups."
msgstr "그룹에 사용할 수 없는 이름입니다."
#: allianceauth/groupmanagement/models.py:215
#: allianceauth/groupmanagement/models.py:214
msgid "reason"
msgstr "원인"
#: allianceauth/groupmanagement/models.py:215
#: allianceauth/groupmanagement/models.py:214
msgid "Reason why this name is reserved."
msgstr "이 이름이 예약된 이유입니다."
#: allianceauth/groupmanagement/models.py:218
#: allianceauth/groupmanagement/models.py:217
msgid "created by"
msgstr "생성자:"
#: allianceauth/groupmanagement/models.py:223
#: allianceauth/groupmanagement/models.py:222
msgid "created at"
msgstr "생성일:"
#: allianceauth/groupmanagement/models.py:223
#: allianceauth/groupmanagement/models.py:222
msgid "Date when this entry was created"
msgstr "이 항목이 생성된 날짜"
@@ -954,86 +995,86 @@ msgstr "그룹 요청"
msgid "Group Membership"
msgstr "참가 중인 그룹"
#: allianceauth/groupmanagement/views.py:163
#: allianceauth/groupmanagement/views.py:166
#, python-format
msgid "Removed user %(user)s from group %(group)s."
msgstr "유저 %(user)s이(가) %(group)s에서 제거됨."
#: allianceauth/groupmanagement/views.py:165
#: allianceauth/groupmanagement/views.py:168
msgid "User does not exist in that group"
msgstr "사용자가 해당 그룹에 존재하지 않음."
#: allianceauth/groupmanagement/views.py:168
#: allianceauth/groupmanagement/views.py:171
msgid "Group does not exist"
msgstr "그룹이 존재하지 않음."
#: allianceauth/groupmanagement/views.py:195
#: allianceauth/groupmanagement/views.py:198
#, python-format
msgid "Accepted application from %(mainchar)s to %(group)s."
msgstr "%(mainchar)s의 %(group)s 그룹 신청 수락"
#: allianceauth/groupmanagement/views.py:201
#: allianceauth/groupmanagement/views.py:232
#: allianceauth/groupmanagement/views.py:204
#: allianceauth/groupmanagement/views.py:235
#, 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:226
#: allianceauth/groupmanagement/views.py:229
#, python-format
msgid "Rejected application from %(mainchar)s to %(group)s."
msgstr "%(mainchar)s의 %(group)s 그룹 신청 거절"
#: allianceauth/groupmanagement/views.py:261
#: allianceauth/groupmanagement/views.py:264
#, python-format
msgid "Accepted application from %(mainchar)s to leave %(group)s."
msgstr "%(mainchar)s의 %(group)s 그룹 탈퇴 수락"
#: allianceauth/groupmanagement/views.py:266
#: allianceauth/groupmanagement/views.py:298
#: allianceauth/groupmanagement/views.py:269
#: allianceauth/groupmanagement/views.py:301
#, python-format
msgid ""
"An unhandled error occurred while processing the application from "
"%(mainchar)s to leave %(group)s."
msgstr "%(mainchar)s의 %(group)s 그룹 탈퇴를 처리하는 중 알 수 없는 에러 발생"
#: allianceauth/groupmanagement/views.py:292
#: allianceauth/groupmanagement/views.py:295
#, python-format
msgid "Rejected application from %(mainchar)s to leave %(group)s."
msgstr "%(mainchar)s의 %(group)s 그룹 탈퇴 거절"
#: allianceauth/groupmanagement/views.py:336
#: allianceauth/groupmanagement/views.py:346
#: allianceauth/groupmanagement/views.py:339
#: allianceauth/groupmanagement/views.py:349
msgid "You cannot join that group"
msgstr "해당 그룹에 참여할 수 없습니다."
#: allianceauth/groupmanagement/views.py:341
#: allianceauth/groupmanagement/views.py:344
msgid "You are already a member of that group."
msgstr "이미 해당 그룹에 가입되어 있습니다."
#: allianceauth/groupmanagement/views.py:358
#: allianceauth/groupmanagement/views.py:361
msgid "You already have a pending application for that group."
msgstr "해당 그룹에 대한 참여신청이 보류되었습니다."
#: allianceauth/groupmanagement/views.py:367
#: allianceauth/groupmanagement/views.py:370
#, python-format
msgid "Applied to group %(group)s."
msgstr "%(group)s그룹에 지원하였음."
#: allianceauth/groupmanagement/views.py:377
#: allianceauth/groupmanagement/views.py:380
msgid "You cannot leave that group"
msgstr "해당 그룹을 떠날 수 없습니다."
#: allianceauth/groupmanagement/views.py:381
#: allianceauth/groupmanagement/views.py:384
msgid "You are not a member of that group"
msgstr "해당그룹의 멤버가 아닙니다."
#: allianceauth/groupmanagement/views.py:393
#: allianceauth/groupmanagement/views.py:396
msgid "You already have a pending leave request for that group."
msgstr "해당 그룹의 탈퇴 신청이 접수된 상태입니다."
#: allianceauth/groupmanagement/views.py:409
#: allianceauth/groupmanagement/views.py:412
#, python-format
msgid "Applied to leave group %(group)s."
msgstr "%(group)s그룹의 탈퇴가 신청됨."
@@ -1095,16 +1136,6 @@ msgstr "지원서 작성"
msgid "Username"
msgstr "사용자명"
#: allianceauth/hrapplications/templates/hrapplications/management.html:28
#: allianceauth/hrapplications/templates/hrapplications/management.html:83
#: allianceauth/hrapplications/templates/hrapplications/management.html:127
#: allianceauth/hrapplications/templates/hrapplications/searchview.html:27
#: allianceauth/hrapplications/templates/hrapplications/view.html:73
#: allianceauth/srp/templates/srp/data.html:101
#: allianceauth/srp/templates/srp/management.html:44
msgid "Actions"
msgstr "활동"
#: allianceauth/hrapplications/templates/hrapplications/management.html:38
#: allianceauth/hrapplications/templates/hrapplications/management.html:99
#: allianceauth/hrapplications/templates/hrapplications/management.html:143
@@ -1443,10 +1474,6 @@ msgstr "모델"
msgid "Code Name"
msgstr "코드명"
#: allianceauth/permissions_tool/templates/permissions_tool/overview.html:35
msgid "Users"
msgstr "사용자"
#: allianceauth/permissions_tool/templates/permissions_tool/overview.html:41
msgid "States"
msgstr "상태"
@@ -2170,11 +2197,11 @@ msgid ""
msgstr ""
#: allianceauth/templates/allianceauth/admin-status/overview.html:95
#, python-format
msgid ""
"\n"
" %(queue_length)s queued tasks\n"
" "
msgid "running"
msgstr ""
#: allianceauth/templates/allianceauth/admin-status/overview.html:96
msgid "queued"
msgstr ""
#: allianceauth/templates/allianceauth/top-menu-admin.html:9
@@ -2190,11 +2217,11 @@ msgid "AA Support Discord"
msgstr "AA Support Discord"
#: allianceauth/templates/allianceauth/top-menu-user-dropdown.html:10
#: allianceauth/templates/allianceauth/top-menu-user-dropdown.html:14
#: allianceauth/templates/allianceauth/top-menu-user-dropdown.html:16
msgid "User Menu"
msgstr "사용자 매뉴"
#: allianceauth/templates/allianceauth/top-menu-user-dropdown.html:56
#: allianceauth/templates/allianceauth/top-menu-user-dropdown.html:67
msgid "Logout"
msgstr "로그아웃"
@@ -2250,22 +2277,30 @@ msgid "Objective"
msgstr "목표 대상"
#: allianceauth/timerboard/form.py:64
msgid "Absolute Timer"
msgstr ""
#: allianceauth/timerboard/form.py:65
msgid "Date and Time"
msgstr ""
#: allianceauth/timerboard/form.py:66
msgid "Days Remaining"
msgstr "남은 일수"
#: allianceauth/timerboard/form.py:65
#: allianceauth/timerboard/form.py:67
msgid "Hours Remaining"
msgstr "남은 시간"
#: allianceauth/timerboard/form.py:67
#: allianceauth/timerboard/form.py:69
msgid "Minutes Remaining"
msgstr "남은 분"
#: allianceauth/timerboard/form.py:69
#: allianceauth/timerboard/form.py:71
msgid "Important"
msgstr "중요"
#: allianceauth/timerboard/form.py:70
#: allianceauth/timerboard/form.py:72
msgid "Corp-Restricted"
msgstr "코퍼레이션 제한"

View File

@@ -4,9 +4,9 @@
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
# Translators:
# Alexander Gess <de.alex.gess@gmail.com>, 2020
# Yuriy K <thedjcooltv@gmail.com>, 2020
# Андрей Зубков <and.vareba81@gmail.com>, 2020
# Андрей Зубков <and.vareba81@gmail.com>, 2023
# Yuriy K <thedjcooltv@gmail.com>, 2023
# Alexander Gess <de.alex.gess@gmail.com>, 2023
# Filipp Chertiev <f@fzfx.ru>, 2023
#
#, fuzzy
@@ -14,8 +14,8 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-10-09 18:20+1000\n"
"PO-Revision-Date: 2020-02-18 03:14+0000\n"
"POT-Creation-Date: 2024-02-17 18:50+1000\n"
"PO-Revision-Date: 2023-11-08 13:50+0000\n"
"Last-Translator: Filipp Chertiev <f@fzfx.ru>, 2023\n"
"Language-Team: Russian (https://app.transifex.com/alliance-auth/teams/107430/ru/)\n"
"MIME-Version: 1.0\n"
@@ -32,7 +32,7 @@ msgstr "Google Analytics Universal"
msgid "Google Analytics V4"
msgstr "Google Analytics V4"
#: allianceauth/authentication/decorators.py:37
#: allianceauth/authentication/decorators.py:49
msgid "A main character is required to perform that action. Add one below."
msgstr ""
"Для продолжения следует указать основного персонажа. Выберите его ниже."
@@ -46,63 +46,68 @@ msgstr "Email"
msgid "You are not allowed to add or remove these restricted groups: %s"
msgstr "Вам не разрешено добавлять или удалять эти ограниченные группы: %s"
#: allianceauth/authentication/models.py:80
#: allianceauth/authentication/models.py:71
msgid "English"
msgstr "Английский"
#: allianceauth/authentication/models.py:81
#: allianceauth/authentication/models.py:72
msgid "German"
msgstr "Немецкий"
#: allianceauth/authentication/models.py:82
#: allianceauth/authentication/models.py:73
msgid "Spanish"
msgstr "Испанский"
#: allianceauth/authentication/models.py:83
#: allianceauth/authentication/models.py:74
msgid "Chinese Simplified"
msgstr "Китайский упрощённый"
#: allianceauth/authentication/models.py:84
#: allianceauth/authentication/models.py:75
msgid "Russian"
msgstr "Русский"
#: allianceauth/authentication/models.py:85
#: allianceauth/authentication/models.py:76
msgid "Korean"
msgstr "Корейский"
#: allianceauth/authentication/models.py:86
#: allianceauth/authentication/models.py:77
msgid "French"
msgstr "Французский"
#: allianceauth/authentication/models.py:87
#: allianceauth/authentication/models.py:78
msgid "Japanese"
msgstr "Японский"
#: allianceauth/authentication/models.py:88
#: allianceauth/authentication/models.py:79
msgid "Italian"
msgstr "Итальянский"
#: allianceauth/authentication/models.py:91
#: allianceauth/authentication/models.py:80
msgid "Ukrainian"
msgstr ""
#: allianceauth/authentication/models.py:96
msgid "Language"
msgstr "Язык"
#: allianceauth/authentication/models.py:96
#: allianceauth/authentication/models.py:101
#: allianceauth/templates/allianceauth/night-toggle.html:6
msgid "Night Mode"
msgstr "Ночной режим"
#: allianceauth/authentication/models.py:110
#: allianceauth/authentication/models.py:115
#, python-format
msgid "State changed to: %s"
msgstr "Статус изменен: %s"
#: allianceauth/authentication/models.py:111
#: allianceauth/authentication/models.py:116
#, python-format
msgid "Your user's state is now: %(state)s"
msgstr "Статус пилота: %(state)s"
#: allianceauth/authentication/templates/authentication/dashboard.html:4
#: allianceauth/authentication/templates/authentication/dashboard.html:7
#: allianceauth/authentication/templates/authentication/tokens.html:4
#: allianceauth/templates/allianceauth/side-menu.html:10
msgid "Dashboard"
msgstr "Панель показателей"
@@ -161,8 +166,50 @@ msgstr "Корпорация"
msgid "Alliance"
msgstr "Альянс"
#: allianceauth/authentication/templates/authentication/tokens.html:7
#: allianceauth/templates/allianceauth/top-menu-user-dropdown.html:62
msgid "Token Management"
msgstr ""
#: allianceauth/authentication/templates/authentication/tokens.html:12
msgid "Scopes"
msgstr ""
#: allianceauth/authentication/templates/authentication/tokens.html:13
#: allianceauth/hrapplications/templates/hrapplications/management.html:28
#: allianceauth/hrapplications/templates/hrapplications/management.html:83
#: allianceauth/hrapplications/templates/hrapplications/management.html:127
#: allianceauth/hrapplications/templates/hrapplications/searchview.html:27
#: allianceauth/hrapplications/templates/hrapplications/view.html:73
#: allianceauth/srp/templates/srp/data.html:101
#: allianceauth/srp/templates/srp/management.html:44
msgid "Actions"
msgstr "Действия"
#: allianceauth/authentication/templates/authentication/tokens.html:14
#: allianceauth/corputils/templates/corputils/corpstats.html:74
#: allianceauth/corputils/templates/corputils/corpstats.html:112
#: allianceauth/corputils/templates/corputils/corpstats.html:156
#: allianceauth/corputils/templates/corputils/search.html:13
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkmodify.html:22
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkview.html:26
#: allianceauth/groupmanagement/templates/groupmanagement/audit.html:30
#: allianceauth/groupmanagement/templates/groupmanagement/groupmembers.html:29
#: allianceauth/groupmanagement/templates/groupmanagement/index.html:55
#: allianceauth/groupmanagement/templates/groupmanagement/index.html:112
msgid "Character"
msgstr "Персонаж"
#: allianceauth/authentication/templates/authentication/tokens.html:28
msgid ""
"This page is a best attempt, but backups or database logs can still contain "
"your tokens. Always revoke tokens on "
"https://community.eveonline.com/support/third-party-applications/ where "
"possible."
msgstr ""
#: allianceauth/authentication/templates/public/login.html:6
#: allianceauth/templates/allianceauth/top-menu-user-dropdown.html:58
#: allianceauth/templates/allianceauth/top-menu-user-dropdown.html:69
msgid "Login"
msgstr "Вход"
@@ -195,7 +242,7 @@ msgstr "Регистрация"
msgid "Invalid or expired activation link."
msgstr "Ссылка активации устарела"
#: allianceauth/authentication/views.py:77
#: allianceauth/authentication/views.py:118
#, python-format
msgid ""
"Cannot change main character to %(char)s: character owned by a different "
@@ -203,40 +250,42 @@ msgid ""
msgstr ""
"Нельзя сменить основного персонажа на %(char)s: похоже, что Владелец не Вы. "
#: allianceauth/authentication/views.py:83
#: allianceauth/authentication/views.py:124
#, python-format
msgid "Changed main character to %(char)s"
msgstr "Основной персонаж заменен на %(char)s"
#: allianceauth/authentication/views.py:92
#: allianceauth/authentication/views.py:133
#, python-format
msgid "Added %(name)s to your account."
msgstr "Добавлен %(name)s на Ваш аккаунт."
#: allianceauth/authentication/views.py:94
#: allianceauth/authentication/views.py:135
#, python-format
msgid "Failed to add %(name)s to your account: they already have an account."
msgstr "Персонаж %(name)s уже добавлен."
#: allianceauth/authentication/views.py:133
msgid "Unable to authenticate as the selected character."
msgstr "Невозможно авторизировать этого персонажа. "
#: allianceauth/authentication/views.py:178
msgid ""
"Unable to authenticate as the selected character. Please log in with the "
"main character associated with this account."
msgstr ""
#: allianceauth/authentication/views.py:197
#: allianceauth/authentication/views.py:244
msgid "Registration token has expired."
msgstr "Регистрационный токен просрочен."
#: allianceauth/authentication/views.py:252
#: allianceauth/authentication/views.py:302
msgid ""
"Sent confirmation email. Please follow the link to confirm your email "
"address."
msgstr "Отправить подтверждающее письмо. Пожалуйста, подтвердите почту. "
#: allianceauth/authentication/views.py:257
#: allianceauth/authentication/views.py:307
msgid "Confirmed your email address. Please login to continue."
msgstr "Подтвердите Ваш email адрес. Зайти для подтверждения. "
#: allianceauth/authentication/views.py:262
#: allianceauth/authentication/views.py:312
msgid "Registration of new accounts is not allowed at this time."
msgstr "Регистрация новых аккаунтов в настоящее время невозможна."
@@ -279,19 +328,6 @@ msgstr "Не зарегистрированы"
msgid "Last update:"
msgstr "Последнее обновление: "
#: allianceauth/corputils/templates/corputils/corpstats.html:74
#: allianceauth/corputils/templates/corputils/corpstats.html:112
#: allianceauth/corputils/templates/corputils/corpstats.html:156
#: allianceauth/corputils/templates/corputils/search.html:13
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkmodify.html:22
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkview.html:26
#: allianceauth/groupmanagement/templates/groupmanagement/audit.html:30
#: allianceauth/groupmanagement/templates/groupmanagement/groupmembers.html:29
#: allianceauth/groupmanagement/templates/groupmanagement/index.html:55
#: allianceauth/groupmanagement/templates/groupmanagement/index.html:112
msgid "Character"
msgstr "Персонаж"
#: allianceauth/corputils/templates/corputils/corpstats.html:75
#: allianceauth/corputils/templates/corputils/search.html:14
#: allianceauth/groupmanagement/templates/groupmanagement/audit.html:31
@@ -629,20 +665,25 @@ msgstr ""
msgid "Group Management"
msgstr "Управление Группой"
#: allianceauth/groupmanagement/forms.py:15
#: allianceauth/groupmanagement/forms.py:18
#: allianceauth/permissions_tool/templates/permissions_tool/overview.html:35
msgid "Users"
msgstr "Пользователи"
#: allianceauth/groupmanagement/forms.py:52
msgid "This name has been reserved and can not be used for groups."
msgstr ""
"Это имя является зарезервированным и не может быть использовано для групп."
#: allianceauth/groupmanagement/forms.py:25
#: allianceauth/groupmanagement/forms.py:62
msgid "(auto)"
msgstr "(авто)"
#: allianceauth/groupmanagement/forms.py:34
#: allianceauth/groupmanagement/forms.py:71
msgid "There already exists a group with that name."
msgstr "Группа с таким именем уже существует."
#: allianceauth/groupmanagement/models.py:105
#: allianceauth/groupmanagement/models.py:104
msgid ""
"Internal group, users cannot see, join or request to join this "
"group.<br>Used for groups such as Members, Corp_*, Alliance_* "
@@ -653,13 +694,13 @@ msgstr ""
"Members, Corp_*, Alliance_* и т. п.<br><b>Будучи выбранной, отменяет "
"настройки \"Скрытая\" и \"Открытая\".</b>"
#: allianceauth/groupmanagement/models.py:113
#: allianceauth/groupmanagement/models.py:112
msgid "Group is hidden from users but can still join with the correct link."
msgstr ""
"Группы скрыты от пользователей, но к ним всё ещё можно присоединиться с "
"помощью корректной ссылки."
#: allianceauth/groupmanagement/models.py:119
#: allianceauth/groupmanagement/models.py:118
msgid ""
"Group is open and users will be automatically added upon request.<br>If the "
"group is not open users will need their request manually approved."
@@ -668,7 +709,7 @@ msgstr ""
"при отправке запроса.<br>Если группа не является открытой, запросы от "
"пользователей будут требовать ручного подтверждения."
#: allianceauth/groupmanagement/models.py:126
#: allianceauth/groupmanagement/models.py:125
msgid ""
"Group is public. Any registered user is able to join this group, with "
"visibility based on the other options set for this group.<br>Auth will not "
@@ -680,7 +721,7 @@ msgstr ""
"настройках данной группы.<br>Auth не будет удалять пользователей из этой "
"группы автоматически при окончании срока их аутентификации."
#: allianceauth/groupmanagement/models.py:135
#: allianceauth/groupmanagement/models.py:134
msgid ""
"Group is restricted. This means that adding or removing users for this group"
" requires a superuser admin."
@@ -688,7 +729,7 @@ msgstr ""
"Группа является ограниченной. Это значит что добавление пользователей в эту "
"группу или удаление из неё требует прав superuser admin."
#: allianceauth/groupmanagement/models.py:144
#: allianceauth/groupmanagement/models.py:143
msgid ""
"Group leaders can process requests for this group. Use the "
"<code>auth.group_management</code> permission to allow a user to manage all "
@@ -698,7 +739,7 @@ msgstr ""
"Используйте разрешение <code>auth.group_management</code>, чтобы позволить "
"пользователю управлять всеми группами.<br>"
#: allianceauth/groupmanagement/models.py:154
#: allianceauth/groupmanagement/models.py:153
msgid ""
"Members of leader groups can process requests for this group. Use the "
"<code>auth.group_management</code> permission to allow a user to manage all "
@@ -708,7 +749,7 @@ msgstr ""
"Используйте разрешение <code>auth.group_management</code>, чтобы позволить "
"пользователю управлять всеми группами.<br>"
#: allianceauth/groupmanagement/models.py:163
#: allianceauth/groupmanagement/models.py:162
msgid ""
"States listed here will have the ability to join this group provided they "
"have the proper permissions.<br>"
@@ -716,42 +757,42 @@ msgstr ""
"Статусы, перечисленные здесь, смогут присоединиться к группе, если у них "
"есть соответствующие разрешения.<br>"
#: allianceauth/groupmanagement/models.py:171
#: allianceauth/groupmanagement/models.py:170
msgid ""
"Short description <i>(max. 512 characters)</i> of the group shown to users."
msgstr ""
"Краткое описание <i>(макс. 512 символов)</i> группы, отображаемое "
"пользователям."
#: allianceauth/groupmanagement/models.py:178
#: allianceauth/groupmanagement/models.py:177
msgid "Can request non-public groups"
msgstr "Можно отправлять запрос на непубличную группу."
#: allianceauth/groupmanagement/models.py:209
#: allianceauth/groupmanagement/models.py:208
msgid "name"
msgstr "имя"
#: allianceauth/groupmanagement/models.py:212
#: allianceauth/groupmanagement/models.py:211
msgid "Name that can not be used for groups."
msgstr "Имя, которое не может быть использовано для групп."
#: allianceauth/groupmanagement/models.py:215
#: allianceauth/groupmanagement/models.py:214
msgid "reason"
msgstr "причина"
#: allianceauth/groupmanagement/models.py:215
#: allianceauth/groupmanagement/models.py:214
msgid "Reason why this name is reserved."
msgstr "Причина, по которой это имя зарезервировано."
#: allianceauth/groupmanagement/models.py:218
#: allianceauth/groupmanagement/models.py:217
msgid "created by"
msgstr "создано кем"
#: allianceauth/groupmanagement/models.py:223
#: allianceauth/groupmanagement/models.py:222
msgid "created at"
msgstr "создано когда"
#: allianceauth/groupmanagement/models.py:223
#: allianceauth/groupmanagement/models.py:222
msgid "Date when this entry was created"
msgstr "Дата, когда данное содержимое было создано"
@@ -978,26 +1019,26 @@ msgstr "Групповой запрос"
msgid "Group Membership"
msgstr "Групповое участие"
#: allianceauth/groupmanagement/views.py:163
#: allianceauth/groupmanagement/views.py:166
#, python-format
msgid "Removed user %(user)s from group %(group)s."
msgstr "Пользователь %(user)s исключен из %(group)s."
#: allianceauth/groupmanagement/views.py:165
#: allianceauth/groupmanagement/views.py:168
msgid "User does not exist in that group"
msgstr "Пользователь не существует в этой группе."
#: allianceauth/groupmanagement/views.py:168
#: allianceauth/groupmanagement/views.py:171
msgid "Group does not exist"
msgstr "Группа не существует."
#: allianceauth/groupmanagement/views.py:195
#: allianceauth/groupmanagement/views.py:198
#, python-format
msgid "Accepted application from %(mainchar)s to %(group)s."
msgstr "Запрос от %(mainchar)sв %(group)s принят."
#: allianceauth/groupmanagement/views.py:201
#: allianceauth/groupmanagement/views.py:232
#: allianceauth/groupmanagement/views.py:204
#: allianceauth/groupmanagement/views.py:235
#, python-format
msgid ""
"An unhandled error occurred while processing the application from "
@@ -1006,18 +1047,18 @@ msgstr ""
"Персонаж %(mainchar)s не может быть добавлен %(group)s, из-за непредвиденной"
" ошибки. "
#: allianceauth/groupmanagement/views.py:226
#: allianceauth/groupmanagement/views.py:229
#, python-format
msgid "Rejected application from %(mainchar)s to %(group)s."
msgstr "%(mainchar)s исключен из %(group)s."
#: allianceauth/groupmanagement/views.py:261
#: allianceauth/groupmanagement/views.py:264
#, python-format
msgid "Accepted application from %(mainchar)s to leave %(group)s."
msgstr "Утвержден выход %(mainchar)s из %(group)s. "
#: allianceauth/groupmanagement/views.py:266
#: allianceauth/groupmanagement/views.py:298
#: allianceauth/groupmanagement/views.py:269
#: allianceauth/groupmanagement/views.py:301
#, python-format
msgid ""
"An unhandled error occurred while processing the application from "
@@ -1026,42 +1067,42 @@ msgstr ""
"Возникла ошибка во время обработки %(mainchar)s на выход из группы "
"%(group)s. Повторите позже."
#: allianceauth/groupmanagement/views.py:292
#: allianceauth/groupmanagement/views.py:295
#, python-format
msgid "Rejected application from %(mainchar)s to leave %(group)s."
msgstr "Прошение об исключении %(mainchar)s из %(group)s отклонено. "
#: allianceauth/groupmanagement/views.py:336
#: allianceauth/groupmanagement/views.py:346
#: allianceauth/groupmanagement/views.py:339
#: allianceauth/groupmanagement/views.py:349
msgid "You cannot join that group"
msgstr "Вы не можете вступить"
#: allianceauth/groupmanagement/views.py:341
#: allianceauth/groupmanagement/views.py:344
msgid "You are already a member of that group."
msgstr "Вы уже участник этой группы."
#: allianceauth/groupmanagement/views.py:358
#: allianceauth/groupmanagement/views.py:361
msgid "You already have a pending application for that group."
msgstr "Вы уже подали заявку на вступление этой группы."
#: allianceauth/groupmanagement/views.py:367
#: allianceauth/groupmanagement/views.py:370
#, python-format
msgid "Applied to group %(group)s."
msgstr "Вступить в группу %(group)s."
#: allianceauth/groupmanagement/views.py:377
#: allianceauth/groupmanagement/views.py:380
msgid "You cannot leave that group"
msgstr "Вы не можете покинуть эту группу"
#: allianceauth/groupmanagement/views.py:381
#: allianceauth/groupmanagement/views.py:384
msgid "You are not a member of that group"
msgstr "Вы не участник группыы"
#: allianceauth/groupmanagement/views.py:393
#: allianceauth/groupmanagement/views.py:396
msgid "You already have a pending leave request for that group."
msgstr "Ваш запрос находится на рассмотрении"
#: allianceauth/groupmanagement/views.py:409
#: allianceauth/groupmanagement/views.py:412
#, python-format
msgid "Applied to leave group %(group)s."
msgstr "Запрос на выход из группы %(group)s."
@@ -1123,16 +1164,6 @@ msgstr "Сделать запрос"
msgid "Username"
msgstr "Пользователь"
#: allianceauth/hrapplications/templates/hrapplications/management.html:28
#: allianceauth/hrapplications/templates/hrapplications/management.html:83
#: allianceauth/hrapplications/templates/hrapplications/management.html:127
#: allianceauth/hrapplications/templates/hrapplications/searchview.html:27
#: allianceauth/hrapplications/templates/hrapplications/view.html:73
#: allianceauth/srp/templates/srp/data.html:101
#: allianceauth/srp/templates/srp/management.html:44
msgid "Actions"
msgstr "Действия"
#: allianceauth/hrapplications/templates/hrapplications/management.html:38
#: allianceauth/hrapplications/templates/hrapplications/management.html:99
#: allianceauth/hrapplications/templates/hrapplications/management.html:143
@@ -1471,10 +1502,6 @@ msgstr "Модель"
msgid "Code Name"
msgstr "Кодовое имя"
#: allianceauth/permissions_tool/templates/permissions_tool/overview.html:35
msgid "Users"
msgstr "Пользователи"
#: allianceauth/permissions_tool/templates/permissions_tool/overview.html:41
msgid "States"
msgstr "Статусы"
@@ -2216,14 +2243,12 @@ msgstr ""
" Статус %(total)s обработанных задач • последние %(latest)s"
#: allianceauth/templates/allianceauth/admin-status/overview.html:95
#, python-format
msgid ""
"\n"
" %(queue_length)s queued tasks\n"
" "
msgid "running"
msgstr ""
#: allianceauth/templates/allianceauth/admin-status/overview.html:96
msgid "queued"
msgstr ""
"\n"
" %(queue_length)s запланированных задач"
#: allianceauth/templates/allianceauth/top-menu-admin.html:9
msgid "Admin"
@@ -2238,11 +2263,11 @@ msgid "AA Support Discord"
msgstr "Discord поддержки AA"
#: allianceauth/templates/allianceauth/top-menu-user-dropdown.html:10
#: allianceauth/templates/allianceauth/top-menu-user-dropdown.html:14
#: allianceauth/templates/allianceauth/top-menu-user-dropdown.html:16
msgid "User Menu"
msgstr "Меню пользователя"
#: allianceauth/templates/allianceauth/top-menu-user-dropdown.html:56
#: allianceauth/templates/allianceauth/top-menu-user-dropdown.html:67
msgid "Logout"
msgstr "Выход"
@@ -2298,22 +2323,30 @@ msgid "Objective"
msgstr "Задача"
#: allianceauth/timerboard/form.py:64
msgid "Absolute Timer"
msgstr ""
#: allianceauth/timerboard/form.py:65
msgid "Date and Time"
msgstr ""
#: allianceauth/timerboard/form.py:66
msgid "Days Remaining"
msgstr "Дней осталось"
#: allianceauth/timerboard/form.py:65
#: allianceauth/timerboard/form.py:67
msgid "Hours Remaining"
msgstr "Часов осталось"
#: allianceauth/timerboard/form.py:67
#: allianceauth/timerboard/form.py:69
msgid "Minutes Remaining"
msgstr "Минут осталось"
#: allianceauth/timerboard/form.py:69
#: allianceauth/timerboard/form.py:71
msgid "Important"
msgstr "Важно"
#: allianceauth/timerboard/form.py:70
#: allianceauth/timerboard/form.py:72
msgid "Corp-Restricted"
msgstr "Корпорация зарегистрированна"

View File

@@ -4,6 +4,7 @@
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
# Translators:
# Denys Ivchenko, 2023
# Kristof Swensen, 2023
#
#, fuzzy
@@ -11,8 +12,8 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-10-09 18:20+1000\n"
"PO-Revision-Date: 2020-02-18 03:14+0000\n"
"POT-Creation-Date: 2024-02-17 18:50+1000\n"
"PO-Revision-Date: 2023-11-08 13:50+0000\n"
"Last-Translator: Kristof Swensen, 2023\n"
"Language-Team: Ukrainian (https://app.transifex.com/alliance-auth/teams/107430/uk/)\n"
"MIME-Version: 1.0\n"
@@ -29,10 +30,10 @@ msgstr "Універсальна Google Аналітика"
msgid "Google Analytics V4"
msgstr "Google Analytics V4"
#: allianceauth/authentication/decorators.py:37
#: allianceauth/authentication/decorators.py:49
msgid "A main character is required to perform that action. Add one below."
msgstr ""
"Для виконання цієї дії потрібен головний персонаж. Додайте його нижче."
"Для виконання цієї дії потрібен основний персонаж. Додайте його нижче."
#: allianceauth/authentication/forms.py:12
msgid "Email"
@@ -43,63 +44,68 @@ msgstr "Електронна пошта"
msgid "You are not allowed to add or remove these restricted groups: %s"
msgstr "Вам заборонено додавати або видаляти ці обмежені групи: %s"
#: allianceauth/authentication/models.py:80
#: allianceauth/authentication/models.py:71
msgid "English"
msgstr "Англійська"
#: allianceauth/authentication/models.py:81
#: allianceauth/authentication/models.py:72
msgid "German"
msgstr "Німецька"
#: allianceauth/authentication/models.py:82
#: allianceauth/authentication/models.py:73
msgid "Spanish"
msgstr "Іспанська"
#: allianceauth/authentication/models.py:83
#: allianceauth/authentication/models.py:74
msgid "Chinese Simplified"
msgstr "Китайська спрощена"
#: allianceauth/authentication/models.py:84
#: allianceauth/authentication/models.py:75
msgid "Russian"
msgstr "Російська"
#: allianceauth/authentication/models.py:85
#: allianceauth/authentication/models.py:76
msgid "Korean"
msgstr "Корейська"
#: allianceauth/authentication/models.py:86
#: allianceauth/authentication/models.py:77
msgid "French"
msgstr "Французька"
#: allianceauth/authentication/models.py:87
#: allianceauth/authentication/models.py:78
msgid "Japanese"
msgstr "Японська"
#: allianceauth/authentication/models.py:88
#: allianceauth/authentication/models.py:79
msgid "Italian"
msgstr "Італійська"
#: allianceauth/authentication/models.py:91
#: allianceauth/authentication/models.py:80
msgid "Ukrainian"
msgstr ""
#: allianceauth/authentication/models.py:96
msgid "Language"
msgstr "Мова"
#: allianceauth/authentication/models.py:96
#: allianceauth/authentication/models.py:101
#: allianceauth/templates/allianceauth/night-toggle.html:6
msgid "Night Mode"
msgstr "Нічний режим"
#: allianceauth/authentication/models.py:110
#: allianceauth/authentication/models.py:115
#, python-format
msgid "State changed to: %s"
msgstr "Стан змінено на: %s"
#: allianceauth/authentication/models.py:111
#: allianceauth/authentication/models.py:116
#, python-format
msgid "Your user's state is now: %(state)s"
msgstr "Стан вашого користувача зараз: %(state)s"
#: allianceauth/authentication/templates/authentication/dashboard.html:4
#: allianceauth/authentication/templates/authentication/dashboard.html:7
#: allianceauth/authentication/templates/authentication/tokens.html:4
#: allianceauth/templates/allianceauth/side-menu.html:10
msgid "Dashboard"
msgstr "Панель приладів"
@@ -124,7 +130,7 @@ msgstr "Додати персонажа"
#: allianceauth/authentication/templates/authentication/dashboard.html:115
msgid "Change Main"
msgstr "Змінити головного персонажа"
msgstr "Змінити основного персонажа"
#: allianceauth/authentication/templates/authentication/dashboard.html:125
msgid "Group Memberships"
@@ -157,8 +163,50 @@ msgstr "Корпорація"
msgid "Alliance"
msgstr "Альянс"
#: allianceauth/authentication/templates/authentication/tokens.html:7
#: allianceauth/templates/allianceauth/top-menu-user-dropdown.html:62
msgid "Token Management"
msgstr ""
#: allianceauth/authentication/templates/authentication/tokens.html:12
msgid "Scopes"
msgstr ""
#: allianceauth/authentication/templates/authentication/tokens.html:13
#: allianceauth/hrapplications/templates/hrapplications/management.html:28
#: allianceauth/hrapplications/templates/hrapplications/management.html:83
#: allianceauth/hrapplications/templates/hrapplications/management.html:127
#: allianceauth/hrapplications/templates/hrapplications/searchview.html:27
#: allianceauth/hrapplications/templates/hrapplications/view.html:73
#: allianceauth/srp/templates/srp/data.html:101
#: allianceauth/srp/templates/srp/management.html:44
msgid "Actions"
msgstr "Дії"
#: allianceauth/authentication/templates/authentication/tokens.html:14
#: allianceauth/corputils/templates/corputils/corpstats.html:74
#: allianceauth/corputils/templates/corputils/corpstats.html:112
#: allianceauth/corputils/templates/corputils/corpstats.html:156
#: allianceauth/corputils/templates/corputils/search.html:13
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkmodify.html:22
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkview.html:26
#: allianceauth/groupmanagement/templates/groupmanagement/audit.html:30
#: allianceauth/groupmanagement/templates/groupmanagement/groupmembers.html:29
#: allianceauth/groupmanagement/templates/groupmanagement/index.html:55
#: allianceauth/groupmanagement/templates/groupmanagement/index.html:112
msgid "Character"
msgstr "Персонаж"
#: allianceauth/authentication/templates/authentication/tokens.html:28
msgid ""
"This page is a best attempt, but backups or database logs can still contain "
"your tokens. Always revoke tokens on "
"https://community.eveonline.com/support/third-party-applications/ where "
"possible."
msgstr ""
#: allianceauth/authentication/templates/public/login.html:6
#: allianceauth/templates/allianceauth/top-menu-user-dropdown.html:58
#: allianceauth/templates/allianceauth/top-menu-user-dropdown.html:69
msgid "Login"
msgstr "Увійти"
@@ -192,7 +240,7 @@ msgstr "Зареєструватися"
msgid "Invalid or expired activation link."
msgstr "Невірне або прострочене посилання для активації."
#: allianceauth/authentication/views.py:77
#: allianceauth/authentication/views.py:118
#, python-format
msgid ""
"Cannot change main character to %(char)s: character owned by a different "
@@ -201,32 +249,34 @@ msgstr ""
"Неможливо змінити основного персонажа на %(char)s: персонаж належить іншому "
"акаунту."
#: allianceauth/authentication/views.py:83
#: allianceauth/authentication/views.py:124
#, python-format
msgid "Changed main character to %(char)s"
msgstr "Основний персонаж змінено на %(char)s"
#: allianceauth/authentication/views.py:92
#: allianceauth/authentication/views.py:133
#, python-format
msgid "Added %(name)s to your account."
msgstr "Додано %(name)s до вашого облікового запису."
#: allianceauth/authentication/views.py:94
#: allianceauth/authentication/views.py:135
#, python-format
msgid "Failed to add %(name)s to your account: they already have an account."
msgstr ""
"Не вдалося додати %(name)s до вашого облікового запису: у них вже є "
"обліковий запис."
#: allianceauth/authentication/views.py:133
msgid "Unable to authenticate as the selected character."
msgstr "Не вдалося автентифікуватися як обраний персонаж."
#: allianceauth/authentication/views.py:178
msgid ""
"Unable to authenticate as the selected character. Please log in with the "
"main character associated with this account."
msgstr ""
#: allianceauth/authentication/views.py:197
#: allianceauth/authentication/views.py:244
msgid "Registration token has expired."
msgstr "Токен реєстрації застарів."
#: allianceauth/authentication/views.py:252
#: allianceauth/authentication/views.py:302
msgid ""
"Sent confirmation email. Please follow the link to confirm your email "
"address."
@@ -234,13 +284,13 @@ msgstr ""
"Відправлено лист з підтвердженням. Будь ласка, перейдіть за посиланням, щоб "
"підтвердити свою адресу електронної пошти."
#: allianceauth/authentication/views.py:257
#: allianceauth/authentication/views.py:307
msgid "Confirmed your email address. Please login to continue."
msgstr ""
"Підтверджено вашу адресу електронної пошти. Будь ласка, увійдіть, щоб "
"продовжити."
#: allianceauth/authentication/views.py:262
#: allianceauth/authentication/views.py:312
msgid "Registration of new accounts is not allowed at this time."
msgstr "Реєстрація нових облікових записів наразі не дозволена."
@@ -283,19 +333,6 @@ msgstr "Незареєстровані"
msgid "Last update:"
msgstr "Останнє оновлення:"
#: allianceauth/corputils/templates/corputils/corpstats.html:74
#: allianceauth/corputils/templates/corputils/corpstats.html:112
#: allianceauth/corputils/templates/corputils/corpstats.html:156
#: allianceauth/corputils/templates/corputils/search.html:13
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkmodify.html:22
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkview.html:26
#: allianceauth/groupmanagement/templates/groupmanagement/audit.html:30
#: allianceauth/groupmanagement/templates/groupmanagement/groupmembers.html:29
#: allianceauth/groupmanagement/templates/groupmanagement/index.html:55
#: allianceauth/groupmanagement/templates/groupmanagement/index.html:112
msgid "Character"
msgstr "Персонаж"
#: allianceauth/corputils/templates/corputils/corpstats.html:75
#: allianceauth/corputils/templates/corputils/search.html:14
#: allianceauth/groupmanagement/templates/groupmanagement/audit.html:31
@@ -352,7 +389,7 @@ 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:35
@@ -456,7 +493,7 @@ msgstr "Корабель"
#: allianceauth/timerboard/templates/timerboard/view.html:202
#: allianceauth/timerboard/templates/timerboard/view.html:375
msgid "Eve Time"
msgstr "Час в грі"
msgstr "Ігровий час"
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkmodify.html:33
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkview.html:36
@@ -560,16 +597,16 @@ msgstr "Fats"
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkstatisticscorpview.html:4
msgid "Fatlink Corp Statistics"
msgstr "Статистика корпорації Fatlink"
msgstr "Статистика фатів корпорації"
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkstatisticscorpview.html:23
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkstatisticsview.html:24
msgid "Average fats"
msgstr "Середній показник fats"
msgstr "Середній показник фатів"
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkstatisticsview.html:4
msgid "Fatlink statistics"
msgstr "Статистика Fatlink"
msgstr "Статистика фатів"
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkstatisticsview.html:20
msgid "Ticker"
@@ -625,7 +662,7 @@ msgid ""
"Cannot register the fleet participation for {character.character_name}. The "
"character needs to be online."
msgstr ""
"Не можна зареєструвати участь в флоті для {character.character_name}. "
"Не вдалося зареєструвати участь в флоті для {character.character_name}. "
"Персонаж повинен бути в мережі."
#: allianceauth/groupmanagement/auth_hooks.py:17
@@ -633,19 +670,24 @@ msgstr ""
msgid "Group Management"
msgstr "Керування групами"
#: allianceauth/groupmanagement/forms.py:15
#: allianceauth/groupmanagement/forms.py:18
#: allianceauth/permissions_tool/templates/permissions_tool/overview.html:35
msgid "Users"
msgstr "Користувачі"
#: allianceauth/groupmanagement/forms.py:52
msgid "This name has been reserved and can not be used for groups."
msgstr "Це ім'я зарезервоване і не може бути використане для груп."
#: allianceauth/groupmanagement/forms.py:25
#: allianceauth/groupmanagement/forms.py:62
msgid "(auto)"
msgstr "(авто)"
#: allianceauth/groupmanagement/forms.py:34
#: allianceauth/groupmanagement/forms.py:71
msgid "There already exists a group with that name."
msgstr "Група з таким ім'ям вже існує."
#: allianceauth/groupmanagement/models.py:105
#: allianceauth/groupmanagement/models.py:104
msgid ""
"Internal group, users cannot see, join or request to join this "
"group.<br>Used for groups such as Members, Corp_*, Alliance_* "
@@ -656,13 +698,12 @@ msgstr ""
"\"Members, Corp_, Alliance_ і т.д.<br><b>Перевизначає параметри Hidden і \"\n"
"\"Open при виборі.</b>\""
#: allianceauth/groupmanagement/models.py:113
#: allianceauth/groupmanagement/models.py:112
msgid "Group is hidden from users but can still join with the correct link."
msgstr ""
"Група прихована від користувачів, але можна приєднатися з правильним "
"посиланням."
"Група прихована від користувачів, але можна приєднатися за посиланням."
#: allianceauth/groupmanagement/models.py:119
#: allianceauth/groupmanagement/models.py:118
msgid ""
"Group is open and users will be automatically added upon request.<br>If the "
"group is not open users will need their request manually approved."
@@ -671,7 +712,7 @@ msgstr ""
"запитом.<br>Якщо група закрита, користувачі повинні отримати ручне "
"підтвердження запиту."
#: allianceauth/groupmanagement/models.py:126
#: allianceauth/groupmanagement/models.py:125
msgid ""
"Group is public. Any registered user is able to join this group, with "
"visibility based on the other options set for this group.<br>Auth will not "
@@ -683,7 +724,7 @@ msgstr ""
"групи.<br>Авторизація не буде автоматично видаляти користувачів з цієї "
"групи, коли вони більше не автентифіковані."
#: allianceauth/groupmanagement/models.py:135
#: allianceauth/groupmanagement/models.py:134
msgid ""
"Group is restricted. This means that adding or removing users for this group"
" requires a superuser admin."
@@ -691,7 +732,7 @@ msgstr ""
"Група обмежена. Це означає, що додавання або видалення користувачів для цієї"
" групи вимагає адміністратора-суперкористувача."
#: allianceauth/groupmanagement/models.py:144
#: allianceauth/groupmanagement/models.py:143
msgid ""
"Group leaders can process requests for this group. Use the "
"<code>auth.group_management</code> permission to allow a user to manage all "
@@ -701,7 +742,7 @@ msgstr ""
"<code>auth.group_management</code>, щоб дозволити користувачеві керувати "
"всіма групами.<br>"
#: allianceauth/groupmanagement/models.py:154
#: allianceauth/groupmanagement/models.py:153
msgid ""
"Members of leader groups can process requests for this group. Use the "
"<code>auth.group_management</code> permission to allow a user to manage all "
@@ -711,7 +752,7 @@ msgstr ""
" дозвіл <code>auth.group_management</code>, щоб дозволити користувачеві "
"керувати всіма групами.<br>"
#: allianceauth/groupmanagement/models.py:163
#: allianceauth/groupmanagement/models.py:162
msgid ""
"States listed here will have the ability to join this group provided they "
"have the proper permissions.<br>"
@@ -719,42 +760,42 @@ msgstr ""
"Штати, перераховані тут, матимуть змогу приєднатися до цієї групи, якщо вони"
" мають відповідні дозволи.<br>"
#: allianceauth/groupmanagement/models.py:171
#: allianceauth/groupmanagement/models.py:170
msgid ""
"Short description <i>(max. 512 characters)</i> of the group shown to users."
msgstr ""
"Короткий опис <i>(максимум 512 символів)</i> групи, що відображається "
"користувачам."
#: allianceauth/groupmanagement/models.py:178
#: allianceauth/groupmanagement/models.py:177
msgid "Can request non-public groups"
msgstr "Може запитувати непублічні групи"
#: allianceauth/groupmanagement/models.py:209
#: allianceauth/groupmanagement/models.py:208
msgid "name"
msgstr "назва"
#: allianceauth/groupmanagement/models.py:212
#: allianceauth/groupmanagement/models.py:211
msgid "Name that can not be used for groups."
msgstr "Назва, яку неможна використовувати для груп."
#: allianceauth/groupmanagement/models.py:215
#: allianceauth/groupmanagement/models.py:214
msgid "reason"
msgstr "причина"
#: allianceauth/groupmanagement/models.py:215
#: allianceauth/groupmanagement/models.py:214
msgid "Reason why this name is reserved."
msgstr "Причина, чому ця назва зарезервована."
#: allianceauth/groupmanagement/models.py:218
#: allianceauth/groupmanagement/models.py:217
msgid "created by"
msgstr "створено користувачем"
#: allianceauth/groupmanagement/models.py:223
#: allianceauth/groupmanagement/models.py:222
msgid "created at"
msgstr "створено о"
#: allianceauth/groupmanagement/models.py:223
#: allianceauth/groupmanagement/models.py:222
msgid "Date when this entry was created"
msgstr "Дата створення цього запису"
@@ -981,26 +1022,26 @@ msgstr "Групові запити"
msgid "Group Membership"
msgstr "Членство в групі"
#: allianceauth/groupmanagement/views.py:163
#: allianceauth/groupmanagement/views.py:166
#, python-format
msgid "Removed user %(user)s from group %(group)s."
msgstr "Користувач %(user)s вилучений з групи %(group)s."
#: allianceauth/groupmanagement/views.py:165
#: allianceauth/groupmanagement/views.py:168
msgid "User does not exist in that group"
msgstr "Користувача не існує в цій групі"
#: allianceauth/groupmanagement/views.py:168
#: allianceauth/groupmanagement/views.py:171
msgid "Group does not exist"
msgstr "Група не існує"
#: allianceauth/groupmanagement/views.py:195
#: allianceauth/groupmanagement/views.py:198
#, python-format
msgid "Accepted application from %(mainchar)s to %(group)s."
msgstr "Заявка %(mainchar)s на вступ до %(group)s прийнята."
#: allianceauth/groupmanagement/views.py:201
#: allianceauth/groupmanagement/views.py:232
#: allianceauth/groupmanagement/views.py:204
#: allianceauth/groupmanagement/views.py:235
#, python-format
msgid ""
"An unhandled error occurred while processing the application from "
@@ -1009,18 +1050,18 @@ msgstr ""
"Під час обробки заявки %(mainchar)s на вступ до %(group)s виникла помилка, "
"яку не можна обробити."
#: allianceauth/groupmanagement/views.py:226
#: allianceauth/groupmanagement/views.py:229
#, python-format
msgid "Rejected application from %(mainchar)s to %(group)s."
msgstr "Заявка %(mainchar)s на вступ до %(group)s відхилена."
#: allianceauth/groupmanagement/views.py:261
#: allianceauth/groupmanagement/views.py:264
#, python-format
msgid "Accepted application from %(mainchar)s to leave %(group)s."
msgstr "Заявка %(mainchar)s на вихід з %(group)s прийнята."
#: allianceauth/groupmanagement/views.py:266
#: allianceauth/groupmanagement/views.py:298
#: allianceauth/groupmanagement/views.py:269
#: allianceauth/groupmanagement/views.py:301
#, python-format
msgid ""
"An unhandled error occurred while processing the application from "
@@ -1029,42 +1070,42 @@ msgstr ""
"Під час обробки заявки %(mainchar)s на вихід з %(group)s виникла помилка, "
"яку не можна обробити."
#: allianceauth/groupmanagement/views.py:292
#: allianceauth/groupmanagement/views.py:295
#, python-format
msgid "Rejected application from %(mainchar)s to leave %(group)s."
msgstr "Заявка %(mainchar)s на вихід з %(group)s відхилена."
#: allianceauth/groupmanagement/views.py:336
#: allianceauth/groupmanagement/views.py:346
#: allianceauth/groupmanagement/views.py:339
#: allianceauth/groupmanagement/views.py:349
msgid "You cannot join that group"
msgstr "Ви не можете приєднатись до цієї групи"
#: allianceauth/groupmanagement/views.py:341
#: allianceauth/groupmanagement/views.py:344
msgid "You are already a member of that group."
msgstr "Ви вже є членом цієї групи."
#: allianceauth/groupmanagement/views.py:358
#: allianceauth/groupmanagement/views.py:361
msgid "You already have a pending application for that group."
msgstr "У вас вже є очікуюча заявка на вступ до цієї групи."
msgstr "Ви вже подали заявку на вступ до цієї групи."
#: allianceauth/groupmanagement/views.py:367
#: allianceauth/groupmanagement/views.py:370
#, python-format
msgid "Applied to group %(group)s."
msgstr "Подано заявку на групу %(group)s."
#: allianceauth/groupmanagement/views.py:377
#: allianceauth/groupmanagement/views.py:380
msgid "You cannot leave that group"
msgstr "Ви не можете покинути цю групу"
#: allianceauth/groupmanagement/views.py:381
#: allianceauth/groupmanagement/views.py:384
msgid "You are not a member of that group"
msgstr "Ви не є учасником цієї групи"
#: allianceauth/groupmanagement/views.py:393
#: allianceauth/groupmanagement/views.py:396
msgid "You already have a pending leave request for that group."
msgstr "Ви вже маєте очікувану запит на вихід з цієї групи."
msgstr "Ви вже подали запит на вихід з цієї групи."
#: allianceauth/groupmanagement/views.py:409
#: allianceauth/groupmanagement/views.py:412
#, python-format
msgid "Applied to leave group %(group)s."
msgstr "Подано заявку на вихід з групи %(group)s."
@@ -1126,16 +1167,6 @@ msgstr "Створити заявку"
msgid "Username"
msgstr "Ім'я користувача"
#: allianceauth/hrapplications/templates/hrapplications/management.html:28
#: allianceauth/hrapplications/templates/hrapplications/management.html:83
#: allianceauth/hrapplications/templates/hrapplications/management.html:127
#: allianceauth/hrapplications/templates/hrapplications/searchview.html:27
#: allianceauth/hrapplications/templates/hrapplications/view.html:73
#: allianceauth/srp/templates/srp/data.html:101
#: allianceauth/srp/templates/srp/management.html:44
msgid "Actions"
msgstr "Дії"
#: allianceauth/hrapplications/templates/hrapplications/management.html:38
#: allianceauth/hrapplications/templates/hrapplications/management.html:99
#: allianceauth/hrapplications/templates/hrapplications/management.html:143
@@ -1321,7 +1352,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
@@ -1345,7 +1376,7 @@ msgstr "Тип операції"
#: allianceauth/optimer/form.py:17
#: allianceauth/srp/templates/srp/management.html:38
msgid "Fleet Commander"
msgstr "Командувач флоту"
msgstr "Командир флоту"
#: allianceauth/optimer/form.py:22 allianceauth/srp/form.py:14
#: allianceauth/srp/templates/srp/data.html:91
@@ -1400,7 +1431,7 @@ msgstr "Немає наступних таймерів."
#: allianceauth/optimer/templates/optimer/management.html:33
msgid "Past Fleet Operations"
msgstr "Минулі флотові операції"
msgstr "Завершені флотові операції"
#: allianceauth/optimer/templates/optimer/management.html:37
#: allianceauth/timerboard/templates/timerboard/view.html:535
@@ -1474,17 +1505,13 @@ msgstr "Модель"
msgid "Code Name"
msgstr "Кодова назва"
#: allianceauth/permissions_tool/templates/permissions_tool/overview.html:35
msgid "Users"
msgstr "Користувачі"
#: allianceauth/permissions_tool/templates/permissions_tool/overview.html:41
msgid "States"
msgstr "Стани"
#: allianceauth/services/abstract.py:72
msgid "That service account already exists"
msgstr "Такий обліковий запис сервісу вже існує"
msgstr "Такий сервісний обліковий запис вже існує"
#: allianceauth/services/abstract.py:103
#, python-brace-format
@@ -1505,7 +1532,7 @@ msgstr "Командир флоту:"
#: allianceauth/services/forms.py:8
msgid "Fleet Comms:"
msgstr "Комунікації флоту:"
msgstr "Голосовий канал флоту:"
#: allianceauth/services/forms.py:9
msgid "Fleet Type:"
@@ -1545,7 +1572,7 @@ msgstr "Ні"
#: allianceauth/services/forms.py:16
msgid "Important?*"
msgstr "Важливо?*"
msgstr "Важливий?*"
#: allianceauth/services/forms.py:21 allianceauth/services/forms.py:31
msgid "Password"
@@ -1614,7 +1641,7 @@ msgstr "Ви не маєте прав на доступ до Discourse."
#: allianceauth/services/modules/discourse/views.py:34
msgid "You must have a main character set to access Discourse."
msgstr "Ви повинні мати головний персонаж, щоб отримати доступ до Discourse."
msgstr "Ви повинні мати основний персонаж, щоб отримати доступ до Discourse."
#: allianceauth/services/modules/discourse/views.py:44
msgid ""
@@ -1702,7 +1729,7 @@ msgstr "Відправлено трансляцію Jabber на %s"
#: allianceauth/services/modules/openfire/views.py:144
msgid "Set jabber password."
msgstr "Встановлення пароля Jabber."
msgstr "Встановити пароль Jabber."
#: allianceauth/services/modules/phpbb3/views.py:34
msgid "Activated forum account."
@@ -1713,7 +1740,7 @@ msgstr "Активований обліковий запис форуму."
#: allianceauth/services/modules/phpbb3/views.py:78
#: allianceauth/services/modules/phpbb3/views.py:101
msgid "An error occurred while processing your forum account."
msgstr "Виникла помилка під час обробки вашого облікового запису форуму."
msgstr "Виникла помилка під час обробки вашого облікового запису на форумі."
#: allianceauth/services/modules/phpbb3/views.py:53
msgid "Deactivated forum account."
@@ -1721,11 +1748,11 @@ msgstr "Деактивований обліковий запис форуму."
#: allianceauth/services/modules/phpbb3/views.py:70
msgid "Reset forum password."
msgstr "Скидання пароля форуму."
msgstr "Скинути пароль форуму."
#: allianceauth/services/modules/phpbb3/views.py:98
msgid "Set forum password."
msgstr "Встановлення пароля форуму."
msgstr "Встановити пароль форуму."
#: allianceauth/services/modules/smf/views.py:52
msgid "Activated SMF account."
@@ -1744,11 +1771,11 @@ msgstr "Деактивований обліковий запис SMF."
#: allianceauth/services/modules/smf/views.py:95
msgid "Reset SMF password."
msgstr "Скидання пароля SMF."
msgstr "Скинути пароль SMF."
#: allianceauth/services/modules/smf/views.py:121
msgid "Set SMF password."
msgstr "Встановлення пароля SMF."
msgstr "Встановити пароль SMF."
#: allianceauth/services/modules/teamspeak3/forms.py:14
#, python-format
@@ -1761,7 +1788,7 @@ msgstr "Оновити групи TS3"
#: allianceauth/services/modules/teamspeak3/templates/services/teamspeak3/teamspeakjoin.html:5
msgid "Verify Teamspeak"
msgstr "Перевірте Teamspeak"
msgstr "Перевірити Teamspeak"
#: allianceauth/services/modules/teamspeak3/templates/services/teamspeak3/teamspeakjoin.html:10
msgid "Verify Teamspeak Identity"
@@ -1869,11 +1896,11 @@ msgstr "Керування послугами"
#: allianceauth/services/templates/services/services.html:9
msgid "Available Services"
msgstr "Доступні послуги"
msgstr "Доступні сервіси"
#: allianceauth/services/templates/services/services.html:14
msgid "Service"
msgstr "Послуга"
msgstr "Сервіс"
#: allianceauth/services/templates/services/services.html:16
msgid "Domain"
@@ -1881,7 +1908,7 @@ msgstr "Домен"
#: allianceauth/srp/auth_hooks.py:13
msgid "Ship Replacement"
msgstr "Компенсація за корабель"
msgstr "Компенсації"
#: allianceauth/srp/form.py:9
#: allianceauth/srp/templates/srp/management.html:36
@@ -2220,14 +2247,12 @@ msgstr ""
"Статус %(total)s виконаних завдань • останній %(latest)s"
#: allianceauth/templates/allianceauth/admin-status/overview.html:95
#, python-format
msgid ""
"\n"
" %(queue_length)s queued tasks\n"
" "
msgid "running"
msgstr ""
#: allianceauth/templates/allianceauth/admin-status/overview.html:96
msgid "queued"
msgstr ""
"\n"
"%(queue_length)s завдань в черзі"
#: allianceauth/templates/allianceauth/top-menu-admin.html:9
msgid "Admin"
@@ -2242,11 +2267,11 @@ msgid "AA Support Discord"
msgstr "Підтримка AA у Discord"
#: allianceauth/templates/allianceauth/top-menu-user-dropdown.html:10
#: allianceauth/templates/allianceauth/top-menu-user-dropdown.html:14
#: allianceauth/templates/allianceauth/top-menu-user-dropdown.html:16
msgid "User Menu"
msgstr "Меню Користувача"
#: allianceauth/templates/allianceauth/top-menu-user-dropdown.html:56
#: allianceauth/templates/allianceauth/top-menu-user-dropdown.html:67
msgid "Logout"
msgstr "Вихід"
@@ -2302,22 +2327,30 @@ msgid "Objective"
msgstr "Мета"
#: allianceauth/timerboard/form.py:64
msgid "Absolute Timer"
msgstr ""
#: allianceauth/timerboard/form.py:65
msgid "Date and Time"
msgstr ""
#: allianceauth/timerboard/form.py:66
msgid "Days Remaining"
msgstr "Залишилося днів"
#: allianceauth/timerboard/form.py:65
#: allianceauth/timerboard/form.py:67
msgid "Hours Remaining"
msgstr "Залишилося годин"
#: allianceauth/timerboard/form.py:67
#: allianceauth/timerboard/form.py:69
msgid "Minutes Remaining"
msgstr "Залишилося хвилин"
#: allianceauth/timerboard/form.py:69
#: allianceauth/timerboard/form.py:71
msgid "Important"
msgstr "Важливо"
#: allianceauth/timerboard/form.py:70
#: allianceauth/timerboard/form.py:72
msgid "Corp-Restricted"
msgstr "Обмежено для корпорації"

View File

@@ -4,18 +4,19 @@
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
# Translators:
# Joel Falknau <ozirascal@gmail.com>, 2020
# Jesse . <sgeine@hotmail.com>, 2020
# Aaron BuBu <351793078@qq.com>, 2020
# Shen Yang, 2023
# Jesse . <sgeine@hotmail.com>, 2023
# Aaron BuBu <351793078@qq.com>, 2023
# Joel Falknau <ozirascal@gmail.com>, 2023
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-10-09 18:20+1000\n"
"PO-Revision-Date: 2020-02-18 03:14+0000\n"
"Last-Translator: Aaron BuBu <351793078@qq.com>, 2020\n"
"POT-Creation-Date: 2024-02-17 18:50+1000\n"
"PO-Revision-Date: 2023-11-08 13:50+0000\n"
"Last-Translator: Joel Falknau <ozirascal@gmail.com>, 2023\n"
"Language-Team: Chinese Simplified (https://app.transifex.com/alliance-auth/teams/107430/zh-Hans/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@@ -31,7 +32,7 @@ msgstr ""
msgid "Google Analytics V4"
msgstr ""
#: allianceauth/authentication/decorators.py:37
#: allianceauth/authentication/decorators.py:49
msgid "A main character is required to perform that action. Add one below."
msgstr "只有主要角色才能执行这个操作。在下面添加一个"
@@ -44,63 +45,68 @@ msgstr "电子邮箱"
msgid "You are not allowed to add or remove these restricted groups: %s"
msgstr ""
#: allianceauth/authentication/models.py:80
#: allianceauth/authentication/models.py:71
msgid "English"
msgstr ""
msgstr "英语"
#: allianceauth/authentication/models.py:81
#: allianceauth/authentication/models.py:72
msgid "German"
msgstr ""
msgstr "德语"
#: allianceauth/authentication/models.py:82
#: allianceauth/authentication/models.py:73
msgid "Spanish"
msgstr ""
msgstr "西班牙语"
#: allianceauth/authentication/models.py:83
#: allianceauth/authentication/models.py:74
msgid "Chinese Simplified"
msgstr ""
msgstr "简体中文"
#: allianceauth/authentication/models.py:84
#: allianceauth/authentication/models.py:75
msgid "Russian"
msgstr ""
msgstr "俄语"
#: allianceauth/authentication/models.py:85
#: allianceauth/authentication/models.py:76
msgid "Korean"
msgstr ""
msgstr "韩语"
#: allianceauth/authentication/models.py:86
#: allianceauth/authentication/models.py:77
msgid "French"
msgstr ""
msgstr "法语"
#: allianceauth/authentication/models.py:87
#: allianceauth/authentication/models.py:78
msgid "Japanese"
msgstr ""
msgstr "日语"
#: allianceauth/authentication/models.py:88
#: allianceauth/authentication/models.py:79
msgid "Italian"
msgstr ""
msgstr "意大利语"
#: allianceauth/authentication/models.py:91
msgid "Language"
#: allianceauth/authentication/models.py:80
msgid "Ukrainian"
msgstr ""
#: allianceauth/authentication/models.py:96
msgid "Language"
msgstr "语言"
#: allianceauth/authentication/models.py:101
#: allianceauth/templates/allianceauth/night-toggle.html:6
msgid "Night Mode"
msgstr ""
msgstr "夜间模式"
#: allianceauth/authentication/models.py:110
#: allianceauth/authentication/models.py:115
#, python-format
msgid "State changed to: %s"
msgstr ""
#: allianceauth/authentication/models.py:111
#: allianceauth/authentication/models.py:116
#, python-format
msgid "Your user's state is now: %(state)s"
msgstr ""
#: allianceauth/authentication/templates/authentication/dashboard.html:4
#: allianceauth/authentication/templates/authentication/dashboard.html:7
#: allianceauth/authentication/templates/authentication/tokens.html:4
#: allianceauth/templates/allianceauth/side-menu.html:10
msgid "Dashboard"
msgstr "账户总览"
@@ -156,8 +162,50 @@ msgstr "所在公司"
msgid "Alliance"
msgstr "所在联盟"
#: allianceauth/authentication/templates/authentication/tokens.html:7
#: allianceauth/templates/allianceauth/top-menu-user-dropdown.html:62
msgid "Token Management"
msgstr ""
#: allianceauth/authentication/templates/authentication/tokens.html:12
msgid "Scopes"
msgstr ""
#: allianceauth/authentication/templates/authentication/tokens.html:13
#: allianceauth/hrapplications/templates/hrapplications/management.html:28
#: allianceauth/hrapplications/templates/hrapplications/management.html:83
#: allianceauth/hrapplications/templates/hrapplications/management.html:127
#: allianceauth/hrapplications/templates/hrapplications/searchview.html:27
#: allianceauth/hrapplications/templates/hrapplications/view.html:73
#: allianceauth/srp/templates/srp/data.html:101
#: allianceauth/srp/templates/srp/management.html:44
msgid "Actions"
msgstr "操作"
#: allianceauth/authentication/templates/authentication/tokens.html:14
#: allianceauth/corputils/templates/corputils/corpstats.html:74
#: allianceauth/corputils/templates/corputils/corpstats.html:112
#: allianceauth/corputils/templates/corputils/corpstats.html:156
#: allianceauth/corputils/templates/corputils/search.html:13
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkmodify.html:22
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkview.html:26
#: allianceauth/groupmanagement/templates/groupmanagement/audit.html:30
#: allianceauth/groupmanagement/templates/groupmanagement/groupmembers.html:29
#: allianceauth/groupmanagement/templates/groupmanagement/index.html:55
#: allianceauth/groupmanagement/templates/groupmanagement/index.html:112
msgid "Character"
msgstr "角色"
#: allianceauth/authentication/templates/authentication/tokens.html:28
msgid ""
"This page is a best attempt, but backups or database logs can still contain "
"your tokens. Always revoke tokens on "
"https://community.eveonline.com/support/third-party-applications/ where "
"possible."
msgstr ""
#: allianceauth/authentication/templates/public/login.html:6
#: allianceauth/templates/allianceauth/top-menu-user-dropdown.html:58
#: allianceauth/templates/allianceauth/top-menu-user-dropdown.html:69
msgid "Login"
msgstr "登录"
@@ -189,47 +237,49 @@ msgstr "注册"
msgid "Invalid or expired activation link."
msgstr "激活链接无效或过期"
#: allianceauth/authentication/views.py:77
#: allianceauth/authentication/views.py:118
#, python-format
msgid ""
"Cannot change main character to %(char)s: character owned by a different "
"account."
msgstr "不能修改主角色为%(char)s这个角色被另一个账户所拥有"
#: allianceauth/authentication/views.py:83
#: allianceauth/authentication/views.py:124
#, python-format
msgid "Changed main character to %(char)s"
msgstr "修改主要角色为%(char)s"
#: allianceauth/authentication/views.py:92
#: allianceauth/authentication/views.py:133
#, python-format
msgid "Added %(name)s to your account."
msgstr "添加%(name)s到您的账户"
#: allianceauth/authentication/views.py:94
#: allianceauth/authentication/views.py:135
#, python-format
msgid "Failed to add %(name)s to your account: they already have an account."
msgstr "添加%(name)s到您的账户失败他们已经在一个账户中了"
#: allianceauth/authentication/views.py:133
msgid "Unable to authenticate as the selected character."
msgstr "无法作为选定的角色进行身份验证"
#: allianceauth/authentication/views.py:178
msgid ""
"Unable to authenticate as the selected character. Please log in with the "
"main character associated with this account."
msgstr ""
#: allianceauth/authentication/views.py:197
#: allianceauth/authentication/views.py:244
msgid "Registration token has expired."
msgstr "注册令牌过期。"
#: allianceauth/authentication/views.py:252
#: allianceauth/authentication/views.py:302
msgid ""
"Sent confirmation email. Please follow the link to confirm your email "
"address."
msgstr "已经发送了确认邮件。请按照链接确定您的电邮地址"
#: allianceauth/authentication/views.py:257
#: allianceauth/authentication/views.py:307
msgid "Confirmed your email address. Please login to continue."
msgstr "已确认您的电邮地址。请登录以继续"
#: allianceauth/authentication/views.py:262
#: allianceauth/authentication/views.py:312
msgid "Registration of new accounts is not allowed at this time."
msgstr ""
@@ -272,19 +322,6 @@ msgstr "未注册成员"
msgid "Last update:"
msgstr "最后一次更新"
#: allianceauth/corputils/templates/corputils/corpstats.html:74
#: allianceauth/corputils/templates/corputils/corpstats.html:112
#: allianceauth/corputils/templates/corputils/corpstats.html:156
#: allianceauth/corputils/templates/corputils/search.html:13
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkmodify.html:22
#: allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkview.html:26
#: allianceauth/groupmanagement/templates/groupmanagement/audit.html:30
#: allianceauth/groupmanagement/templates/groupmanagement/groupmembers.html:29
#: allianceauth/groupmanagement/templates/groupmanagement/index.html:55
#: allianceauth/groupmanagement/templates/groupmanagement/index.html:112
msgid "Character"
msgstr "角色"
#: allianceauth/corputils/templates/corputils/corpstats.html:75
#: allianceauth/corputils/templates/corputils/search.html:14
#: allianceauth/groupmanagement/templates/groupmanagement/audit.html:31
@@ -614,36 +651,41 @@ msgstr ""
msgid "Group Management"
msgstr "用户组管理"
#: allianceauth/groupmanagement/forms.py:15
#: allianceauth/groupmanagement/forms.py:18
#: allianceauth/permissions_tool/templates/permissions_tool/overview.html:35
msgid "Users"
msgstr "用户"
#: allianceauth/groupmanagement/forms.py:52
msgid "This name has been reserved and can not be used for groups."
msgstr ""
#: allianceauth/groupmanagement/forms.py:25
#: allianceauth/groupmanagement/forms.py:62
msgid "(auto)"
msgstr ""
#: allianceauth/groupmanagement/forms.py:34
#: allianceauth/groupmanagement/forms.py:71
msgid "There already exists a group with that name."
msgstr ""
#: allianceauth/groupmanagement/models.py:105
#: allianceauth/groupmanagement/models.py:104
msgid ""
"Internal group, users cannot see, join or request to join this "
"group.<br>Used for groups such as Members, Corp_*, Alliance_* "
"etc.<br><b>Overrides Hidden and Open options when selected.</b>"
msgstr ""
#: allianceauth/groupmanagement/models.py:113
#: allianceauth/groupmanagement/models.py:112
msgid "Group is hidden from users but can still join with the correct link."
msgstr ""
#: allianceauth/groupmanagement/models.py:119
#: allianceauth/groupmanagement/models.py:118
msgid ""
"Group is open and users will be automatically added upon request.<br>If the "
"group is not open users will need their request manually approved."
msgstr ""
#: allianceauth/groupmanagement/models.py:126
#: allianceauth/groupmanagement/models.py:125
msgid ""
"Group is public. Any registered user is able to join this group, with "
"visibility based on the other options set for this group.<br>Auth will not "
@@ -651,66 +693,66 @@ msgid ""
"authenticated."
msgstr ""
#: allianceauth/groupmanagement/models.py:135
#: allianceauth/groupmanagement/models.py:134
msgid ""
"Group is restricted. This means that adding or removing users for this group"
" requires a superuser admin."
msgstr ""
#: allianceauth/groupmanagement/models.py:144
#: allianceauth/groupmanagement/models.py:143
msgid ""
"Group leaders can process requests for this group. Use the "
"<code>auth.group_management</code> permission to allow a user to manage all "
"groups.<br>"
msgstr ""
#: allianceauth/groupmanagement/models.py:154
#: allianceauth/groupmanagement/models.py:153
msgid ""
"Members of leader groups can process requests for this group. Use the "
"<code>auth.group_management</code> permission to allow a user to manage all "
"groups.<br>"
msgstr ""
#: allianceauth/groupmanagement/models.py:163
#: allianceauth/groupmanagement/models.py:162
msgid ""
"States listed here will have the ability to join this group provided they "
"have the proper permissions.<br>"
msgstr ""
#: allianceauth/groupmanagement/models.py:171
#: allianceauth/groupmanagement/models.py:170
msgid ""
"Short description <i>(max. 512 characters)</i> of the group shown to users."
msgstr ""
#: allianceauth/groupmanagement/models.py:178
#: allianceauth/groupmanagement/models.py:177
msgid "Can request non-public groups"
msgstr ""
#: allianceauth/groupmanagement/models.py:209
#: allianceauth/groupmanagement/models.py:208
msgid "name"
msgstr ""
#: allianceauth/groupmanagement/models.py:212
#: allianceauth/groupmanagement/models.py:211
msgid "Name that can not be used for groups."
msgstr ""
#: allianceauth/groupmanagement/models.py:215
#: allianceauth/groupmanagement/models.py:214
msgid "reason"
msgstr ""
msgstr "原因"
#: allianceauth/groupmanagement/models.py:215
#: allianceauth/groupmanagement/models.py:214
msgid "Reason why this name is reserved."
msgstr ""
#: allianceauth/groupmanagement/models.py:218
#: allianceauth/groupmanagement/models.py:217
msgid "created by"
msgstr ""
#: allianceauth/groupmanagement/models.py:223
#: allianceauth/groupmanagement/models.py:222
msgid "created at"
msgstr ""
#: allianceauth/groupmanagement/models.py:223
#: allianceauth/groupmanagement/models.py:222
msgid "Date when this entry was created"
msgstr ""
@@ -754,7 +796,7 @@ msgstr "操作者"
#: allianceauth/groupmanagement/templates/groupmanagement/audit.html:48
msgid "Removed"
msgstr ""
msgstr "已移除"
#: allianceauth/groupmanagement/templates/groupmanagement/audit.html:60
msgid "All times displayed are EVE/UTC."
@@ -937,86 +979,86 @@ msgstr "用户组请求"
msgid "Group Membership"
msgstr "用户组成员"
#: allianceauth/groupmanagement/views.py:163
#: allianceauth/groupmanagement/views.py:166
#, python-format
msgid "Removed user %(user)s from group %(group)s."
msgstr "已将用户%(user)s从用户组%(group)s中移除"
#: allianceauth/groupmanagement/views.py:165
#: allianceauth/groupmanagement/views.py:168
msgid "User does not exist in that group"
msgstr "那个用户组中不存在这个用户"
#: allianceauth/groupmanagement/views.py:168
#: allianceauth/groupmanagement/views.py:171
msgid "Group does not exist"
msgstr "用户组不存在"
#: allianceauth/groupmanagement/views.py:195
#: allianceauth/groupmanagement/views.py:198
#, python-format
msgid "Accepted application from %(mainchar)s to %(group)s."
msgstr "已接受用户%(mainchar)s加入%(group)s的申请"
#: allianceauth/groupmanagement/views.py:201
#: allianceauth/groupmanagement/views.py:232
#: allianceauth/groupmanagement/views.py:204
#: allianceauth/groupmanagement/views.py:235
#, 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:226
#: allianceauth/groupmanagement/views.py:229
#, python-format
msgid "Rejected application from %(mainchar)s to %(group)s."
msgstr "%(mainchar)s加入%(group)s的申请已拒绝"
#: allianceauth/groupmanagement/views.py:261
#: allianceauth/groupmanagement/views.py:264
#, python-format
msgid "Accepted application from %(mainchar)s to leave %(group)s."
msgstr "%(mainchar)s加入%(group)s的申请已通过"
#: allianceauth/groupmanagement/views.py:266
#: allianceauth/groupmanagement/views.py:298
#: allianceauth/groupmanagement/views.py:269
#: allianceauth/groupmanagement/views.py:301
#, python-format
msgid ""
"An unhandled error occurred while processing the application from "
"%(mainchar)s to leave %(group)s."
msgstr "在处理%(mainchar)s离开%(group)s的程序时发生了未知的错误"
#: allianceauth/groupmanagement/views.py:292
#: allianceauth/groupmanagement/views.py:295
#, python-format
msgid "Rejected application from %(mainchar)s to leave %(group)s."
msgstr "%(mainchar)s离开%(group)s的请求已被拒绝"
#: allianceauth/groupmanagement/views.py:336
#: allianceauth/groupmanagement/views.py:346
#: allianceauth/groupmanagement/views.py:339
#: allianceauth/groupmanagement/views.py:349
msgid "You cannot join that group"
msgstr "你无法加入那个用户组"
#: allianceauth/groupmanagement/views.py:341
#: allianceauth/groupmanagement/views.py:344
msgid "You are already a member of that group."
msgstr "你已经是那个群组的一员了。"
#: allianceauth/groupmanagement/views.py:358
#: allianceauth/groupmanagement/views.py:361
msgid "You already have a pending application for that group."
msgstr "你已经有了该组的未决申请"
#: allianceauth/groupmanagement/views.py:367
#: allianceauth/groupmanagement/views.py:370
#, python-format
msgid "Applied to group %(group)s."
msgstr "修改已经应用到%(group)s啦"
#: allianceauth/groupmanagement/views.py:377
#: allianceauth/groupmanagement/views.py:380
msgid "You cannot leave that group"
msgstr "你无法离开那个用户组"
#: allianceauth/groupmanagement/views.py:381
#: allianceauth/groupmanagement/views.py:384
msgid "You are not a member of that group"
msgstr "你不是那个用户组的成员"
#: allianceauth/groupmanagement/views.py:393
#: allianceauth/groupmanagement/views.py:396
msgid "You already have a pending leave request for that group."
msgstr "你已经有了该组的未决离开请求"
#: allianceauth/groupmanagement/views.py:409
#: allianceauth/groupmanagement/views.py:412
#, python-format
msgid "Applied to leave group %(group)s."
msgstr "已经离开群组%(group)s"
@@ -1078,16 +1120,6 @@ msgstr "创建申请"
msgid "Username"
msgstr "用户名"
#: allianceauth/hrapplications/templates/hrapplications/management.html:28
#: allianceauth/hrapplications/templates/hrapplications/management.html:83
#: allianceauth/hrapplications/templates/hrapplications/management.html:127
#: allianceauth/hrapplications/templates/hrapplications/searchview.html:27
#: allianceauth/hrapplications/templates/hrapplications/view.html:73
#: allianceauth/srp/templates/srp/data.html:101
#: allianceauth/srp/templates/srp/management.html:44
msgid "Actions"
msgstr "操作"
#: allianceauth/hrapplications/templates/hrapplications/management.html:38
#: allianceauth/hrapplications/templates/hrapplications/management.html:99
#: allianceauth/hrapplications/templates/hrapplications/management.html:143
@@ -1198,11 +1230,11 @@ msgstr "添加评论"
#: allianceauth/notifications/models.py:21
msgid "danger"
msgstr ""
msgstr "危险"
#: allianceauth/notifications/models.py:22
msgid "warning"
msgstr ""
msgstr "警告"
#: allianceauth/notifications/models.py:23
msgid "info"
@@ -1343,7 +1375,7 @@ msgstr "当前EVE游戏内时间"
#: allianceauth/optimer/templates/optimer/management.html:26
msgid "Next Fleet Operations"
msgstr ""
msgstr "下一个舰队任务"
#: allianceauth/optimer/templates/optimer/management.html:30
#: allianceauth/timerboard/templates/timerboard/view.html:362
@@ -1352,7 +1384,7 @@ msgstr "没有快到的时间节点,歇一会吧"
#: allianceauth/optimer/templates/optimer/management.html:33
msgid "Past Fleet Operations"
msgstr ""
msgstr "过去的舰队任务"
#: allianceauth/optimer/templates/optimer/management.html:37
#: allianceauth/timerboard/templates/timerboard/view.html:535
@@ -1426,10 +1458,6 @@ msgstr "类型"
msgid "Code Name"
msgstr "操作类型"
#: allianceauth/permissions_tool/templates/permissions_tool/overview.html:35
msgid "Users"
msgstr "用户"
#: allianceauth/permissions_tool/templates/permissions_tool/overview.html:41
msgid "States"
msgstr "声望"
@@ -2152,11 +2180,11 @@ msgid ""
msgstr ""
#: allianceauth/templates/allianceauth/admin-status/overview.html:95
#, python-format
msgid ""
"\n"
" %(queue_length)s queued tasks\n"
" "
msgid "running"
msgstr ""
#: allianceauth/templates/allianceauth/admin-status/overview.html:96
msgid "queued"
msgstr ""
#: allianceauth/templates/allianceauth/top-menu-admin.html:9
@@ -2172,11 +2200,11 @@ msgid "AA Support Discord"
msgstr ""
#: allianceauth/templates/allianceauth/top-menu-user-dropdown.html:10
#: allianceauth/templates/allianceauth/top-menu-user-dropdown.html:14
#: allianceauth/templates/allianceauth/top-menu-user-dropdown.html:16
msgid "User Menu"
msgstr ""
#: allianceauth/templates/allianceauth/top-menu-user-dropdown.html:56
#: allianceauth/templates/allianceauth/top-menu-user-dropdown.html:67
msgid "Logout"
msgstr "登出"
@@ -2232,22 +2260,30 @@ msgid "Objective"
msgstr "声望"
#: allianceauth/timerboard/form.py:64
msgid "Absolute Timer"
msgstr ""
#: allianceauth/timerboard/form.py:65
msgid "Date and Time"
msgstr ""
#: allianceauth/timerboard/form.py:66
msgid "Days Remaining"
msgstr "剩余天数"
#: allianceauth/timerboard/form.py:65
#: allianceauth/timerboard/form.py:67
msgid "Hours Remaining"
msgstr "剩余小时数"
#: allianceauth/timerboard/form.py:67
#: allianceauth/timerboard/form.py:69
msgid "Minutes Remaining"
msgstr "剩余分钟"
#: allianceauth/timerboard/form.py:69
#: allianceauth/timerboard/form.py:71
msgid "Important"
msgstr "重要信息"
#: allianceauth/timerboard/form.py:70
#: allianceauth/timerboard/form.py:72
msgid "Corp-Restricted"
msgstr "受限制的公司"
@@ -2257,15 +2293,15 @@ msgstr ""
#: allianceauth/timerboard/models.py:15
msgid "Shield"
msgstr ""
msgstr "护盾"
#: allianceauth/timerboard/models.py:16
msgid "Armor"
msgstr ""
msgstr "装甲"
#: allianceauth/timerboard/models.py:17
msgid "Hull"
msgstr ""
msgstr "结构"
#: allianceauth/timerboard/models.py:18
msgid "Final"
@@ -2273,11 +2309,11 @@ msgstr ""
#: allianceauth/timerboard/models.py:19
msgid "Anchoring"
msgstr ""
msgstr "铆钉"
#: allianceauth/timerboard/models.py:20
msgid "Unanchoring"
msgstr ""
msgstr "解锚"
#: allianceauth/timerboard/templates/timerboard/timer_confirm_delete.html:11
msgid "Delete Timer"

View File

@@ -172,7 +172,7 @@ MESSAGE_TAGS = {
CACHES = {
"default": {
"BACKEND": "django_redis.cache.RedisCache",
"LOCATION": "redis://127.0.0.1:6379/1" # change the 1 here to change the database used
"LOCATION": "redis://127.0.0.1:6379/1" # change the 1 here for the DB used
}
}
@@ -202,6 +202,8 @@ LOGOUT_REDIRECT_URL = 'authentication:dashboard' # destination after logging ou
# scopes required on new tokens when logging in. Cannot be blank.
LOGIN_TOKEN_SCOPES = ['publicData']
EMAIL_TIMEOUT = 15
# number of days email verification links are valid for
ACCOUNT_ACTIVATION_DAYS = 1

View File

@@ -11,6 +11,9 @@ from .models import DiscordUser
from .urls import urlpatterns
from .utils import LoggerAddTag
from . import tasks, __title__
from .app_settings import (
DISCORD_SYNC_NAMES
)
logger = LoggerAddTag(logging.getLogger(__name__), __title__)
@@ -99,17 +102,18 @@ class DiscordService(ServicesHook):
return has_perms
def sync_nickname(self, user):
logger.debug('Syncing %s nickname for user %s', self.name, user)
if self.user_has_account(user):
tasks.update_nickname.apply_async(
kwargs={
'user_pk': user.pk,
# since the new nickname is not yet in the DB we need to
# provide it manually to the task
'nickname': user_formatted_nick(user)
},
priority=SINGLE_TASK_PRIORITY
)
if DISCORD_SYNC_NAMES:
logger.debug('Syncing %s nickname for user %s', self.name, user)
if self.user_has_account(user):
tasks.update_nickname.apply_async(
kwargs={
'user_pk': user.pk,
# since the new nickname is not yet in the DB we need to
# provide it manually to the task
'nickname': user_formatted_nick(user)
},
priority=SINGLE_TASK_PRIORITY
)
def sync_nicknames_bulk(self, users: list):
"""Sync nickname for a list of users in bulk.

View File

@@ -81,11 +81,18 @@ class TestDiscordService(NoSocketsTestCase):
self.assertFalse(DiscordUser.objects.filter(user=self.none_member).exists())
@patch(MODULE_PATH + '.tasks.update_nickname')
@patch(MODULE_PATH + '.auth_hooks.DISCORD_SYNC_NAMES', True)
def test_sync_nickname(self, mock_update_nickname):
service = self.service()
service.sync_nickname(self.member)
self.assertTrue(mock_update_nickname.apply_async.called)
@patch(MODULE_PATH + '.tasks.update_nickname')
def test_sync_nickname_no_setting(self, mock_update_nickname):
service = self.service()
service.sync_nickname(self.member)
self.assertFalse(mock_update_nickname.apply_async.called)
@patch(MODULE_PATH + '.tasks.update_nicknames_bulk')
def test_sync_nicknames_bulk(self, mock_update_nicknames_bulk):
service = self.service()

View File

@@ -164,6 +164,7 @@ class TestServiceFeatures(TransactionTestCase):
self.discord_user = DiscordUser.objects.create(user=self.user, uid=TEST_USER_ID)
self.assertTrue(DiscordUser.objects.user_has_account(self.user))
@patch(MODULE_PATH + '.auth_hooks.DISCORD_SYNC_NAMES', True)
def test_when_name_of_main_changes_then_discord_nick_is_updated(
self, requests_mocker
):
@@ -185,6 +186,7 @@ class TestServiceFeatures(TransactionTestCase):
self.assertTrue(nick_updated)
self.assertTrue(DiscordUser.objects.user_has_account(self.user))
@patch(MODULE_PATH + '.auth_hooks.DISCORD_SYNC_NAMES', True)
def test_when_name_of_main_changes_and_user_deleted_then_account_is_deleted(
self, requests_mocker
):

View File

@@ -1,7 +1,7 @@
PROTOCOL=https://
AUTH_SUBDOMAIN=%AUTH_SUBDOMAIN%
DOMAIN=%DOMAIN%
AA_DOCKER_TAG=registry.gitlab.com/allianceauth/allianceauth/auth:v3.7.0
AA_DOCKER_TAG=registry.gitlab.com/allianceauth/allianceauth/auth:v3.8.1
# Nginx Proxy Manager
PROXY_HTTP_PORT=80

View File

@@ -1,5 +1,5 @@
FROM python:3.9-slim
ARG AUTH_VERSION=v3.7.0
ARG AUTH_VERSION=v3.8.1
ARG AUTH_PACKAGE=allianceauth==${AUTH_VERSION}
ENV VIRTUAL_ENV=/opt/venv
ENV AUTH_USER=allianceauth

72
docs/_static/css/tabs.css vendored Normal file
View File

@@ -0,0 +1,72 @@
.sphinx-tabs {
margin-bottom: 1rem;
}
[role="tablist"] {
border-bottom: 1px solid #a0b3bf;
}
.sphinx-tabs-tab {
position: relative;
font-family: Lato, 'Helvetica Neue', Arial, Helvetica, sans-serif;
color: #1D5C87;
line-height: 24px;
margin: 0;
font-size: 16px;
font-weight: 400;
background-color: rgba(255, 255, 255, 0);
border-radius: 5px 5px 0 0;
border: 0;
padding: 1rem 1.5rem;
margin-bottom: 0;
}
.sphinx-tabs-tab[aria-selected="true"] {
font-weight: 700;
border: 1px solid #a0b3bf;
border-bottom: 1px solid white;
margin: -1px;
background-color: white;
}
.sphinx-tabs-tab:focus {
z-index: 1;
outline-offset: 1px;
}
.sphinx-tabs-panel {
position: relative;
padding: 1rem;
border: 1px solid #a0b3bf;
margin: 0px -1px -1px -1px;
border-radius: 0 0 5px 5px;
border-top: 0;
background: white;
}
.sphinx-tabs-panel.code-tab {
padding: 0.4rem;
}
.sphinx-tab img {
margin-bottom: 24 px;
}
/* Dark theme preference styling */
@media (prefers-color-scheme: dark) {
.sphinx-tabs-panel {
color: white;
background-color: rgb(50, 50, 50);
}
.sphinx-tabs-tab {
color: white;
background-color: rgba(255, 255, 255, 0.05);
}
.sphinx-tabs-tab[aria-selected="true"] {
border-bottom: 1px solid rgb(50, 50, 50);
background-color: rgb(50, 50, 50);
}
}

View File

@@ -1,15 +1,10 @@
# Configuration file for the Sphinx documentation builder.
#
# Alliance Auth documentation build configuration file, created by
# sphinx-quickstart on Tue Jan 3 12:56:59 2017.
#
# This file is execfile()d with the current directory set to its
# containing dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.
# This file only contains a selection of the most common options. For a full
# list see the documentation:
# https://www.sphinx-doc.org/en/master/usage/configuration.html
# -- Path setup --------------------------------------------------------------
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
@@ -18,23 +13,23 @@
import os
import sys
import django
import sphinx_rtd_theme # noqa
sys.path.insert(0, os.path.abspath('..'))
os.environ['DJANGO_SETTINGS_MODULE'] = 'tests.settings_all'
django.setup()
# -- Project information -----------------------------------------------------
project = 'Alliance Auth'
copyright = '2018-2023, Alliance Auth'
author = 'Alliance Auth Team'
# -- General configuration ---------------------------------------------------
# on_rtd is whether we are on readthedocs.org, this line of code grabbed from docs.readthedocs.org
on_rtd = os.environ.get('READTHEDOCS', None) == 'True'
# Support for recommonmark module
import recommonmark
from recommonmark.transform import AutoStructify
# -- General configuration ------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
#
# needs_sphinx = '1.0'
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
@@ -42,11 +37,18 @@ from recommonmark.transform import AutoStructify
extensions = [
'sphinx_rtd_theme',
'sphinx.ext.autodoc',
'sphinx.ext.intersphinx',
'sphinx.ext.napoleon',
'recommonmark',
'sphinxcontrib_django2',
'sphinx.ext.viewcode',
'sphinx_copybutton'
'myst_parser',
'sphinxcontrib_django',
'sphinx_copybutton',
'sphinx_tabs.tabs'
]
myst_enable_extensions = [
"colon_fence",
"tasklist",
]
# Add any paths that contain templates here, relative to this directory.
@@ -59,41 +61,16 @@ templates_path = ['_templates']
source_suffix = ['.md', '.rst']
# The master toctree document.
master_doc = 'index'
# General information about the project.
project = 'Alliance Auth'
copyright = '2018-2022, Alliance Auth'
author = 'Alliance Auth Team'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = '3.0'
# The full version, including alpha/beta/rc tags.
# release = u'1.14.0'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#
# This is also used if you do content translation via gettext catalogs.
# Usually you set "language" from the command line for these cases.
language = 'en'
root_doc = 'index'
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
# This patterns also effect to html_static_path and html_extra_path
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
# If true, `todo` and `todoList` produce output, else they produce nothing.
todo_include_todos = False
# -- Options for HTML output ----------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
@@ -101,20 +78,11 @@ todo_include_todos = False
#
html_theme = 'sphinx_rtd_theme'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
#
html_theme_options = {
'navigation_depth': 4,
}
# Add any paths that contain custom static files (such as style sheets) here,
# 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"]
html_css_files = ["css/rtd_dark.css", "css/tabs.css"]
# -- Options for HTMLHelp output ------------------------------------------
@@ -147,7 +115,7 @@ latex_elements = {
# (source start file, target name, title,
# author, documentclass [howto, manual, or own class]).
latex_documents = [
(master_doc, 'AllianceAuth.tex', 'Alliance Auth Documentation', 'R4stl1n', 'manual'),
(root_doc, 'AllianceAuth.tex', 'Alliance Auth Documentation', 'Alliance Auth Team', 'manual'),
]
@@ -156,7 +124,7 @@ latex_documents = [
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
(master_doc, 'allianceauth', 'Alliance Auth Documentation',
(root_doc, 'allianceauth', 'Alliance Auth Documentation',
[author], 1)
]
@@ -169,15 +137,12 @@ add_module_names = False
# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
(master_doc, 'AllianceAuth', 'Alliance Auth Documentation',
author, 'AllianceAuth', 'An auth system for EVE Online to help in-game organizations manage online service access.',
'Miscellaneous'),
texinfo_documents = [(
root_doc, 'AllianceAuth', 'Alliance Auth Documentation', author, 'AllianceAuth',
'An auth system for EVE Online to help in-game organizations manage online service access.', 'Miscellaneous'),
]
def setup(app):
app.add_config_value('recommonmark_config', {
'auto_toc_tree_section': 'Contents',
}, True)
app.add_transform(AutoStructify)
# -- https://myst-parser.readthedocs.io/en/latest/configuration.html
myst_heading_anchors = 4

View File

@@ -1,12 +1,12 @@
# Contributing
Alliance Auth is developed by the community and we are always looking to welcome new contributors. If you are interested in contributing, here are some ideas where to start:
Alliance Auth is developed by the community, and we are always looking to welcome new contributors. If you are interested in contributing, here are some ideas where to start:
## Publish a new community app or service
One great way to contribute is to develop and publish your own community app or service for Alliance Auth. By design Auth only comes with some basic features and therefore heavily relies on the community to provide apps to extend Auth with additional features.
One great way to contribute is to develop and publish your own community app or service for Alliance Auth. By design, Auth only comes with some basic features and therefore heavily relies on the community to provide apps to extend Auth with additional features.
To publish your app make sure it can be installed from a public repo or PyPI. Once it's ready, you can inform everybody about your new app by posting it to our [list of community apps](/features/community/index.md).
To publish your app, make sure it can be installed from a public repo or PyPI. Once it's ready, you can inform everybody about your new app by posting it to our [list of community apps](/features/community/index.md).
If you are looking for ideas on what to make, you can check out Auth's [issue list](https://gitlab.com/allianceauth/allianceauth/-/issues?scope=all&utf8=%E2%9C%93&state=opened&label_name[]=enhancement). Many of those issues are feature requests that will probably never make into Auth core, but would be awesome to have as community app or service. You could also ask the other devs on our Discord server for ideas or to help you get a feeling about which new features might be in higher demand than others.
@@ -16,7 +16,7 @@ There are quite a few great community apps that need help from additional mainta
Sometimes original app owners may even be looking to completely hand over their apps to a new owner.
If you are interested to help maintain an existing community app or service you can just start working on open issues and create merge requests. Or just ask other devs on our Discord.
If you are interested to help maintain an existing community app or service, you can start working on open issues and create merge requests. Or just ask other devs on our Discord.
## Help with improving Auth documentation
@@ -26,7 +26,7 @@ Auth has an extensive [documentation](https://allianceauth.readthedocs.io/en/lat
One of the main functions of the Auth Discord server is to help the community with any support question they may have when installing or running an Auth installation.
Note that you do not need a be part of any official group to become a supporter. Just jump in and help with answering new questions from the community if you know how to help.
Note that you do not need to be part of any official group to become a supporter. Jump in and help with answering new questions from the community if you know how to help.
## Help to improve Alliance Auth core
@@ -34,12 +34,12 @@ Alliance Auth has an issue list, which is usually the basis for all maintenance
We usually have a long list of open issues and very much welcome every help to fix existing bugs or work on new features for Auth.
Before starting to code on any topic we'd suggest talking to the other devs on Discord to make sure your issue is not already being worked on. Also, some feature request may be better implemented in a community app. Another aspect, which is best clarified by talking with the other devs.
Before starting to code on any topic, we'd suggest talking to the other devs on Discord to make sure your issue is not already being worked on. Also, some feature requests may be better implemented in a community app. Another aspect, which is best clarified by talking with the other devs.
If you like to contribute to Auth core, but are unsure where to start, we have a dedicated label for issues that are suitable for beginners: [beginner friendly](https://gitlab.com/allianceauth/allianceauth/-/issues?label_name%5B%5D=beginner+friendly).
If you like to contribute to Auth core, but are unsure where to start, we have a dedicated label for issues that are suitable for beginners: [beginner-friendly](https://gitlab.com/allianceauth/allianceauth/-/issues?label_name%5B%5D=beginner+friendly).
## Additional Resources
For more information on how to create community apps or how to setup a developer environment for Auth, please see our official [developer documentation](/development/index.md).
For more information on how to create community apps or how to set up a developer environment for Auth, please see our official [developer documentation](/development/index.md).
For getting in touch with other contributors please feel free to join the [Alliance Auth Discord server](https://discord.gg/fjnHAmk).
For getting in touch with other contributors, please feel free to join the [Alliance Auth Discord server](https://discord.gg/fjnHAmk).

View File

@@ -2,14 +2,13 @@
It is possible to customize your **Alliance Auth** instance.
```eval_rst
.. warning::
Keep in mind that you may need to update some of your customizations manually after new Auth releases (e.g. when replacing templates).
```
:::{warning}
Keep in mind that you may need to update some of your customizations manually after new Auth releases (e.g., when replacing templates).
:::
## Site name
You can replace the default name shown on the web site with your own, e.g. the name of your Alliance.
You can replace the default name shown on the website with your own, e.g., the name of your Alliance.
Just update `SITE_NAME` in your `local.py` settings file accordingly, e.g.:
@@ -19,15 +18,15 @@ SITE_NAME = 'Awesome Alliance'
## Custom Static and Templates
Within your auth project exists two folders named `static` and `templates`. These are used by Django for rendering web pages. Static refers to content Django does not need to parse before displaying, such as CSS styling or images. When running via a WSGI worker such as Gunicorn static files are copied to a location for the web server to read from. Templates are always read from the template folders, rendered with additional context from a view function, and then displayed to the user.
Within your auth project exists two folders named `static` and `templates`. These are used by Django for rendering web pages. Static refers to content Django does not need to parse before displaying, such as CSS styling or images. When running via a WSGI worker such as Gunicorn, static files are copied to a location for the web server to read from. Templates are always read from the template folders, rendered with additional context from a view function, and then displayed to the user.
You can add extra static or templates by putting files in these folders. Note that changes to static requires running the `python manage.py collectstatic` command to copy to the web server directory.
You can add extra static or templates by putting files in these folders. Note that changes to static require running the `python manage.py collectstatic` command to copy to the web server directory.
It is possible to overload static and templates shipped with Django or Alliance Auth by including a file with the exact path of the one you wish to overload. For instance if you wish to add extra links to the menu bar by editing the template, you would make a copy of the `allianceauth/templates/allianceauth/base.html` file to `myauth/templates/allianceauth/base.html` and edit it there. Notice the paths are identical after the `templates/` directory - this is critical for it to be recognized. Your custom template would be used instead of the one included with Alliance Auth when Django renders the web page. Similar idea for static: put CSS or images at an identical path after the `static/` directory and they will be copied to the web server directory instead of the ones included.
## Custom URLs and Views
It is possible to add or override URLs with your auth project's URL config file. Upon install it is of the form:
It is possible to add or override URLs with your auth project's URL config file. Upon installing, it is of the form:
```python
from django.urls import re_path
@@ -57,7 +56,7 @@ urlpatterns = [
]
```
Additionally you can override URLs used by Alliance Auth here:
Additionally, you can override URLs used by Alliance Auth here:
```python
from django.urls import re_path
@@ -74,47 +73,46 @@ urlpatterns = [
## Example: Adding an external link to the sidebar
As an example we are adding an external links to the Alliance Auth sidebar using the template overrides feature. For our example let's add a link to Google's start page.
As an example, we are adding an external links to the Alliance Auth sidebar using the template overrides feature. For example, let's add a link to Google's start page.
### Step 1 - Create the template override folder
First you need to create the folder for the template on your server. For AA to pick it up it has to match a specific structure.
First, you need to create the folder for the template on your server. For Alliance Auth to pick it up, it has to match a specific structure.
If you have a default installation you can create the folder like this:
If you have a default installation, you can create a folder like this:
```sh
```shell
mkdir -p /home/allianceserver/myauth/myauth/templates/allianceauth
```
### Step 2 - Download the original template
Next you need to download a copy of the original template file we want to change. For that let's move into the above folder and then download the file into the current folder with:
Next, you need to download a copy of the original template file we want to change. For that, let's move into the above folder and then download the file into the current folder with:
```sh
```shell
cd /home/allianceserver/myauth/myauth/templates/allianceauth
wget <https://gitlab.com/allianceauth/allianceauth/-/raw/master/allianceauth/templates/allianceauth/side-menu.html>
```
### Step 3 - Modify the template
Now you can modify the template to add your custom link. To create the google link we can add this snippet *between* the `{% menu_items %}` and the `</ul>` tag:
Now you can modify the template to add your custom link. To create the Google link, we can add this snippet *between* the `{% menu_items %}` and the `</ul>` tag:
```sh
```shell
nano /home/allianceserver/myauth/myauth/templates/allianceauth/side-menu.html
```
```jinja
<li>
<a href="https://www.google.com/" target="_blank">
<i class="fab fa-google fa-fw"></i>Google
</a>
</li>
```django
<li>
<a href="https://www.google.com/" target="_blank">
<i class="fab fa-google fa-fw"></i>Google
</a>
</li>
```
```eval_rst
.. hint::
:::{hint}
You can find other icons with a matching style on the `Font Awesome site <https://fontawesome.com/v5/search?m=free>`_ . AA currently uses Font Awesome version 5. You also want to keep the ``fa-fw`` tag to ensure all icons have the same width.
```
:::
### Step 4 - Restart your AA services

View File

@@ -0,0 +1,49 @@
# Code Style
## Pre-Commit
Alliance Auth is a team effort with developers of various skill levels and background. To avoid significant drift or formatting changes between developers, we use [pre-commit](https://pre-commit.com/) to apply a very minimal set of formatting checks to code contributed to the project.
Pre-commit is also very popular with our Community Apps and may be significantly more opinionated or looser depending on the project.
To get started, `pip install pre-commit`, then `pre-commit install` to add the git hooks.
Before any code is "git push"-ed, pre-commit will check it for uniformity and correct it if possible
```shell
check python ast.....................................(no files to check)Skipped
check yaml...........................................(no files to check)Skipped
check json...........................................(no files to check)Skipped
check toml...........................................(no files to check)Skipped
check xml............................................(no files to check)Skipped
check for merge conflicts............................(no files to check)Skipped
check for added large files..........................(no files to check)Skipped
detect private key...................................(no files to check)Skipped
check for case conflicts.............................(no files to check)Skipped
debug statements (python)............................(no files to check)Skipped
fix python encoding pragma...........................(no files to check)Skipped
fix utf-8 byte order marker..........................(no files to check)Skipped
mixed line ending....................................(no files to check)Skipped
trim trailing whitespace.............................(no files to check)Skipped
check that executables have shebangs.................(no files to check)Skipped
fix end of files.....................................(no files to check)Skipped
Check .editorconfig rules............................(no files to check)Skipped
django-upgrade.......................................(no files to check)Skipped
pyupgrade............................................(no files to check)Skipped
```
## Editorconfig
[Editorconfig](https://editorconfig.org/) is supported my most IDE's to streamline the most common editor disparities. While checked by our pre-commit file, using this in your IDE (Either automatically or via a plugin) will minimize the corrections that may need to be made.
## Doc Strings
We prefer either [PEP-287](https://peps.python.org/pep-0287/)/[reStructuredText](https://docutils.sourceforge.io/rst.html) or [Google](https://google.github.io/styleguide/pyguide.html#381-docstrings) Docstrings.
These can be used to automatically generate our Sphinx documentation in either format.
## Best Practice
It is advisable to avoid wide formatting changes on code that is not being modified by an MR. Further to this, automated code formatting should be kept to a minimal when modifying sections of existing files.
If you are contributing whole modules or rewriting large sections of code, you may use any legible code formatting valid under Python.

View File

@@ -4,15 +4,15 @@ The documentation for Alliance Auth uses [Sphinx](http://www.sphinx-doc.org/) to
to specific branches is made (master, primarily), the repository is automatically pulled, docs built and deployed on
[readthedocs.org](https://readthedocs.org/).
Documentation was migrated from the GitHub wiki pages and into the repository to allow documentation changes to be
included with pull requests. This means that documentation can be guaranteed to be updated when a pull request is
accepted rather than hoping documentation is updated afterwards or relying on maintainers to do the work. It also
allows for documentation to be maintained at different versions more easily.
## Building Documentation
If you're developing new documentation, its likely you'll want or need to test build it before committing to your
branch. To achieve this you can use Sphinx to build the documentation locally as it appears on Read the Docs.
If you're developing new documentation, it's likely you'll want or need to test build it before committing to your
branch. To achieve this, you can use Sphinx to build the documentation locally as it appears on Read the Docs.
Activate your virtual environment (if you're using one) and install the documentation requirements found in
`docs/requirements.txt` using pip, e.g. `pip install -r docs/requirements.txt`.
@@ -24,15 +24,16 @@ build in the `/docs/_build/` directory.
Occasionally you may need to fully rebuild the documents by running `make clean` first, usually when you add or
rearrange toctrees.
## Documentation Format
CommonMark Markdown is the current preferred format, via [recommonmark](https://github.com/rtfd/recommonmark).
reStructuredText is supported if required, or you can execute snippets of reST inside Markdown by using a code block:
CommonMark-plus Markdown is the current preferred format, via [MyST-Parser](https://github.com/executablebooks/MyST-Parser).
reStructuredText is supported if required, or you can execute snippets of MyST inside Markdown by using a code block:
```eval_rst
reStructuredText here
```
````md
```{eval-rst}
reStructuredText here
```
````
Markdown is used elsewhere on Github so it provides the most portability of documentation from Issues and Pull Requests
as well as providing an easier initial migration path from the Github wiki.
Markdown is used elsewhere on GitHub, so it provides the most portability of documentation from Issues and Pull Requests
as well as providing an easier initial migration path from the GitHub wiki.

View File

@@ -2,9 +2,9 @@
This section contains important information on how to develop Alliance Auth itself.
```eval_rst
.. toctree::
:maxdepth: 1
:::{toctree}
:maxdepth: 1
documentation
```
documentation
code-style
:::

View File

@@ -2,12 +2,11 @@
This section describes how to extend **Alliance Auth** with custom apps and services.
```eval_rst
.. toctree::
:maxdepth: 1
:::{toctree}
:maxdepth: 1
integrating-services
menu-hooks
url-hooks
logging
```
integrating-services
menu-hooks
url-hooks
logging
:::

View File

@@ -1,16 +1,16 @@
# Integrating Services
One of the primary roles of Alliance Auth is integrating with external services in order to authenticate and manage users. This is achieved through the use of service modules.
One of the primary roles of Alliance Auth is integrating with external services to authenticate and manage users. This is achieved through the use of service modules.
## The Service Module
Each service module is its own self contained Django app. It will likely contain views, models, migrations and templates. Anything that is valid in a Django app is valid in a service module.
Each service module is its own self-contained Django app. It will likely contain views, models, migrations and templates. Anything that is valid in a Django app is valid in a service module.
Normally service modules live in `services.modules` though they may also be installed as external packages and installed via `pip` if you wish. A module is installed by including it in the `INSTALLED_APPS` setting.
### Service Module Structure
Typically a service will contain 5 key components:
Typically, a service will contain 5 key components:
- [The Hook](#the-hook)
- [The Service Manager](#the-service-manager)
@@ -20,60 +20,65 @@ Typically a service will contain 5 key components:
The architecture looks something like this:
urls -------▶ Views
▲ |
| |
|
ServiceHook ----▶ Tasks ----▶ Manager
|
|
AllianceAuth
```none
urls -------▶ Views
|
| |
| ▼
ServiceHook ----▶ Tasks ----▶ Manager
|
|
AllianceAuth
Where:
Module --▶ Dependency/Import
Where:
Module --▶ Dependency/Import
```
While this is the typical structure of the existing services modules, there is no enforcement of this structure and you are, effectively, free to create whatever architecture may be necessary. A service module need not even communicate with an external service, for example, if similar triggers such as validate_user, delete_user are required for a module it may be convenient to masquerade as a service. Ideally though, using the common structure improves the maintainability for other developers.
While this is the typical structure of the existing services modules, there is no enforcement of this structure, and you are, effectively, free to create whatever architecture may be necessary. A service module need not even communicate with an external service, for example, if similar triggers such as validate_user, delete_user are required for a module it may be convenient to masquerade as a service. Ideally, using the common structure improves the maintainability for other developers.
### The Hook
In order to integrate with Alliance Auth service modules must provide a `services_hook`. This hook will be a function that returns an instance of the `services.hooks.ServiceHook` class and decorated with the `@hooks.registerhook` decorator. For example:
To integrate with Alliance Auth service modules must provide a `services_hook`. This hook will be a function that returns an instance of the `services.hooks.ServiceHook` class and decorated with the `@hooks.registerhook` decorator. For example:
@hooks.register('services_hook')
def register_service():
return ExampleService()
```python
@hooks.register('services_hook')
def register_service():
return ExampleService()
```
This would register the ExampleService class which would need to be a subclass of `services.hooks.ServiceHook`.
```eval_rst
.. important::
The hook **MUST** be registered in ``yourservice.auth_hooks`` along with any other hooks you are registering for Alliance Auth.
```
:::{important}
The hook **MUST** be registered in ``yourservice.auth_hooks`` along with any other hooks you are registering for Alliance Auth.
:::
A subclassed `ServiceHook` might look like this:
class ExampleService(ServicesHook):
def __init__(self):
ServicesHook.__init__(self)
self.urlpatterns = urlpatterns
self.service_url = 'http://exampleservice.example.com'
```python
class ExampleService(ServicesHook):
def __init__(self):
ServicesHook.__init__(self)
self.urlpatterns = urlpatterns
self.service_url = 'https://exampleservice.example.com'
"""
Overload base methods here to implement functionality
"""
"""
Overload base methods here to implement functionality
"""
```
### The ServiceHook class
The base `ServiceHook` class defines function signatures that Alliance Auth will call under certain conditions in order to trigger some action in the service.
The base `ServiceHook` class defines function signatures that Alliance Auth will call under certain conditions to trigger some action in the service.
You will need to subclass `services.hooks.ServiceHook` in order to provide implementation of the functions so that Alliance Auth can interact with the service correctly. All of the functions are optional, so its up to you to define what you need.
You will need to subclass `services.hooks.ServiceHook` in order to provide implementation of the functions so that Alliance Auth can interact with the service correctly. All the functions are optional, so its up to you to define what you need.
Instance Variables:
- [self.name](#self-name)
- [self.urlpatterns](#self-url-patterns)
- [self.service_ctrl_template](#self-service-ctrl-template)
- [self.name](#selfname)
- [self.urlpatterns](#selfurlpatterns)
- [self.service_ctrl_template](#selfservice_ctrl_template)
Properties:
@@ -88,8 +93,6 @@ Functions:
- [update_groups](#update_groups)
- [update_groups_bulk](#update_groups_bulk)
- [update_all_groups](#update_all_groups)
- [service_enabled_members](#service_enabled_members)
- [service_enabled_blues](#service_enabled_blues)
- [service_active_for_user](#service_active_for_user)
- [show_service_ctrl](#show_service_ctrl)
- [render_service_ctrl](#render_service_ctrl)
@@ -100,30 +103,32 @@ Internal name of the module, should be unique amongst modules.
#### self.urlpatterns
You should define all of your service URLs internally, usually in `urls.py`. Then you can import them and set `self.urlpatterns` to your defined urlpatterns.
You should usually define all of your service URLs internally, in `urls.py`. Then you can import them and set `self.urlpatterns` to your defined urlpatterns.
from . import urls
...
class MyService(ServiceHook):
def __init__(self):
...
self.urlpatterns = urls.urlpatterns
```python
from . import urls
...
class MyService(ServiceHook):
def __init__(self):
...
self.urlpatterns = urls.urlpatterns
```
All of your apps defined urlpatterns will then be included in the `URLconf` when the core application starts.
#### self.service_ctrl_template
This is provided as a courtesy and defines the default template to be used with [render_service_ctrl](#render-service-ctrl). You are free to redefine or not use this variable at all.
This is provided as a courtesy and defines the default template to be used with [render_service_ctrl](#render_service_ctrl). You are free to redefine or not use this variable at all.
#### title
This is a property which provides a user friendly display of your service's name. It will usually do a reasonably good job unless your service name has punctuation or odd capitalization. If this is the case you should override this method and return a string.
This is a property which provides a user-friendly display of your service's name. It will usually do a reasonably good job unless your service name has punctuation or odd capitalization. If this is the case, you should override this method and return a string.
#### delete_user
`def delete_user(self, user, notify_user=False):`
Delete the users service account, optionally notify them that the service has been disabled. The `user` parameter should be a Django User object. If notify_user is set to `True` a message should be set to the user via the `notifications` module to alert them that their service account has been disabled.
Delete the user's service account, optionally notify them that the service has been disabled. The `user` parameter should be a Django User object. If notify_user is set to `True` a message should be set to the user via the `notifications` module to alert them that their service account has been disabled.
The function should return a boolean, `True` if successfully disabled, `False` otherwise.
@@ -131,14 +136,16 @@ The function should return a boolean, `True` if successfully disabled, `False` o
`def validate_user(self, user):`
Validate the users service account, deleting it if they should no longer have access. The `user` parameter should be a Django User object.
Validate the user's service account, deleting it if they should no longer have access. The `user` parameter should be a Django User object.
An implementation will probably look like the following:
def validate_user(self, user):
logger.debug('Validating user %s %s account' % (user, self.name))
if ExampleTasks.has_account(user) and not self.service_active_for_user(user):
self.delete_user(user, notify_user=True)
```python
def validate_user(self, user):
logger.debug('Validating user %s %s account' % (user, self.name))
if ExampleTasks.has_account(user) and not self.service_active_for_user(user):
self.delete_user(user, notify_user=True)
```
No return value is expected.
@@ -148,7 +155,7 @@ This function will be called periodically on all users to validate that the give
`def sync_nickname(self, user):`
Very optional. As of writing only one service defines this. The `user` parameter should be a Django User object. When called, the given users nickname for the service should be updated and synchronized with the service.
Very optional. As of writing, only one service defines this. The `user` parameter should be a Django User object. When called, the given users nickname for the service should be updated and synchronized with the service.
If this function is defined, an admin action will be registered on the Django Users view, allowing admins to manually trigger this action for one or many users. The hook will trigger this action user by user, so you won't have to manage a list of users.
@@ -158,7 +165,7 @@ If this function is defined, an admin action will be registered on the Django Us
Updates the nickname for a list of users. The `users` parameter must be a list of Django User objects.
If this method is defined, the admin action for updating service related nicknames for users will call this bulk method instead of sync_nickname. This gives you more control over how mass updates are executed, e.g. ensuring updates do not run in parallel to avoid causing rate limit violations from an external API.
If this method is defined, the admin action for updating service related nicknames for users will call this bulk method instead of sync_nickname. This gives you more control over how mass updates are executed, e.g., ensuring updates do not run in parallel to avoid causing rate limit violations from an external API.
This is an optional method.
@@ -166,12 +173,12 @@ This is an optional method.
`def update_groups(self, user):`
Update the users group membership. The `user` parameter should be a Django User object.
When this is called the service should determine the groups the user is a member of and synchronize the group membership with the external service. If you service does not support groups then you are not required to define this.
Update the user's group membership. The `user` parameter should be a Django User object.
When this is called, the service should determine the groups the user is a member of and synchronize the group membership with the external service. If your service does not support groups, then you are not required to define this.
If this function is defined, an admin action will be registered on the Django Users view, allowing admins to manually trigger this action for one or many users. The hook will trigger this action user by user, so you won't have to manage a list of users.
This action is usually called via a signal when a users group membership changes (joins or leaves a group).
This action is usually called via a signal when a user's group membership changes (joins or leaves a group).
#### update_groups_bulk
@@ -179,7 +186,7 @@ This action is usually called via a signal when a users group membership changes
Updates the group memberships for a list of users. The `users` parameter must be a list of Django User objects.
If this method is defined, the admin action for updating service related groups for users will call this bulk method instead of update_groups. This gives you more control over how mass updates are executed, e.g. ensuring updates do not run in parallel to avoid causing rate limit violations from an external API.
If this method is defined, the admin action for updating service related groups for users will call this bulk method instead of update_groups. This gives you more control over how mass updates are executed, e.g., ensuring updates do not run in parallel to avoid causing rate limit violations from an external API.
This is an optional method.
@@ -197,7 +204,7 @@ I'm really not sure when this is called, it may have been a hold over from befor
Is this service active for the given user? The `user` parameter should be a Django User object.
Usually you wont need to override this as it calls `service_enabled_members` or `service_enabled_blues` depending on the users state.
Usually you won't need to override this as it calls `service_enabled_members` or `service_enabled_blues` depending on the user's state.
#### show_service_ctrl
@@ -205,92 +212,100 @@ Usually you wont need to override this as it calls `service_enabled_members` or
Should the service be shown for the given `user` with the given `state`? The `user` parameter should be a Django User object, and the `state` parameter should be a valid state from `authentication.states`.
Usually you wont need to override this function.
Usually you won't need to override this function.
For more information see the [render_service_ctrl](#render-service-ctrl) section.
For more information see the [render_service_ctrl](#render_service_ctrl) section.
#### render_service_ctrl
`def render_services_ctrl(self, request):`
Render the services control row. This will be called for all active services when a user visits the `/services/` page and [show_service_ctrl](#show-service-ctrl) returns `True` for the given user.
Render the services control row. This will be called for all active services when a user visits the `/services/` page and [show_service_ctrl](#show_service_ctrl) returns `True` for the given user.
It should return a string (usually from `render_to_string`) of a table row (`<tr>`) with 4 columns (`<td>`). Column #1 is the service name, column #2 is the users username for this service, column #3 is the services URL, and column #4 is the action buttons.
It should return a string (usually from `render_to_string`) of a table row (`<tr>`) with 4 columns (`<td>`). Column #1 is the service name, column #2 is the user's username for this service, column #3 is the services URL, and column #4 is the action buttons.
You may either define your own service template or use the default one provided. The default can be used like this example:
def render_services_ctrl(self, request):
"""
Example for rendering the service control panel row
You can override the default template and create a
custom one if you wish.
:param request:
:return:
"""
urls = self.Urls()
urls.auth_activate = 'auth_example_activate'
urls.auth_deactivate = 'auth_example_deactivate'
urls.auth_reset_password = 'auth_example_reset_password'
urls.auth_set_password = 'auth_example_set_password'
return render_to_string(self.service_ctrl_template, {
'service_name': self.title,
'urls': urls,
'service_url': self.service_url,
'username': 'example username'
}, request=request)
```python
def render_services_ctrl(self, request):
"""
Example for rendering the service control panel row
You can override the default template and create a
custom one if you wish.
:param request:
:return:
"""
urls = self.Urls()
urls.auth_activate = 'auth_example_activate'
urls.auth_deactivate = 'auth_example_deactivate'
urls.auth_reset_password = 'auth_example_reset_password'
urls.auth_set_password = 'auth_example_set_password'
return render_to_string(self.service_ctrl_template, {
'service_name': self.title,
'urls': urls,
'service_url': self.service_url,
'username': 'example username'
}, request=request)
```
the `Urls` class defines the available URL names for the 4 actions available in the default template:
the `Urls` class defines the available URL names for the four actions available in the default template:
- Activate (create service account)
- Deactivate (delete service account)
- Activate (create a service account)
- Deactivate (delete a service account)
- Reset Password (random password)
- Set Password (custom password)
If you don't define one or all of these variable the button for the undefined URLs will not be displayed.
If you don't define one or all of these variables, the button for the undefined URLs will not be displayed.
Most services will survive with the default template. If, however, you require extra buttons for whatever reason, you are free to provide your own template as long as you stick within the 4 columns. Multiple rows should be OK, though may be confusing to users.
Most services will survive with the default template. If, however, you require extra buttons for whatever reason, you are free to provide your own template as long as you stick within the 4 columns. Multiple rows should be OK, though it may be confusing to users.
### Menu Item Hook
If you services needs cannot be satisfied by the Service Control row, you are free to specify extra hooks by subclassing or instantiating the `services.hooks.MenuItemHook` class.
If your service needs cannot be satisfied by the Service Control row, you are free to specify extra hooks by subclassing or instantiating the `services.hooks.MenuItemHook` class.
For more information see the [Menu Hooks](menu-hooks.md) page.
For more information, see the [Menu Hooks](menu-hooks.md) page.
### The Service Manager
The service manager is what interacts with the external service. Ideally it should be completely agnostic about its environment, meaning that it should avoid calls to Alliance Auth and Django in general (except in special circumstances where the service is managed locally, e.g. Mumble). Data should come in already arranged by the Tasks and data passed back for the tasks to manage or distribute.
The service manager is what interacts with the external service. Ideally, it should be completely agnostic about its environment, meaning that it should avoid calls to Alliance Auth and Django in general (except in special circumstances where the service is managed locally, e.g., Mumble). Data should come in already arranged by the Tasks and data passed back for the tasks to manage or distribute.
The reason for maintaining this separation is that managers may be reused from other sources and there may not even be a need to write a custom manager. Likewise, by maintaining this neutral environment others may reuse the managers that we write. It can also significantly ease the unit testing of services.
The reason for maintaining this separation is that managers may be reused from other sources, and there may not even be a need to write a custom manager. Likewise, by maintaining this neutral environment, others may reuse the managers that we write. It can also significantly ease the unit testing of services.
### The Views
As mentioned at the start of this page, service modules are fully fledged Django apps. This means you're free to do whatever you wish with your views.
Typically most traditional username/password services define four views.
Typically, most traditional username/password services define four views.
- Create Account
- Delete Account
- Reset Password
- Set Password
These views should interact with the service via the Tasks, though in some instances may bypass the Tasks and access the manager directly where necessary, for example OAuth functionality.
These views should interact with the service via the Tasks, though in some instances may bypass the Tasks and access the manager directly where necessary, for example, OAuth functionality.
### The Tasks
The tasks component is the glue that holds all of the other components of the service module together. It provides the function implementation to handle things like adding and deleting users, updating groups, validating the existence of a users account. Whatever tasks `auth_hooks` and `views` have with interacting with the service will probably live here.
The tasks component is the glue that holds all the other components of the service module together. It provides the function implementation to handle things like adding and deleting users, updating groups, and validating the existence of a user's account. Whatever tasks `auth_hooks` and `views` have with interacting with the service will probably live here.
### The Models
Its very likely that you'll need to store data about a users remote service account locally. As service modules are fully fledged Django apps you are free to create as many models as necessary for persistent storage. You can create foreign keys to other models in Alliance Auth if necessary, though I _strongly_ recommend you limit this to the User and Groups models from `django.contrib.auth.models` and query any other data manually.
It's very likely that you'll need to store data about a users remote service account locally. As service modules are fully fledged Django apps, you are free to create as many models as necessary for persistent storage. You can create foreign keys to other models in Alliance Auth if necessary, though I _strongly_ recommend you limit this to the User and Groups models from `django.contrib.auth.models` and query any other data manually.
If you create models you should create the migrations that go along with these inside of your module/app.
If you create models, you should create the migrations that go along with them inside your module/app.
## Examples
There is a bare bones example service included in `services.modules.example`, you may like to use this as the base for your new service.
There is a bare-bones example service included in `services.modules.example`, you may like to use this as the base for your new service.
You should have a look through some of the other service modules before you get started to get an idea of the general structure of one. A lot of them aren't perfect so don't feel like you have to rigidly follow the structure of the existing services if you think its sub-optimal or doesn't suit the external service you're integrating.
You should have a look through some of the other service modules before you get started to get an idea of the general structure. A lot of them aren't perfect, so don't feel like you have to rigidly follow the structure of the existing services if you think its suboptimal or doesn't suit the external service you're integrating.
## Testing
You will need to add unit tests for all aspects of your service module before it is accepted. Be mindful that you don't actually want to make external calls to the service so you should mock the appropriate components to prevent this behavior.
You will need to add unit tests for all aspects of your service module before it is accepted. Be mindful that you don't actually want to make external calls to the service, so you should mock the appropriate components to prevent this behavior.
```{eval-rst}
.. autoclass:: allianceauth.services.hooks.ServicesHook
:members:
:undoc-members:
```

View File

@@ -1,7 +1,9 @@
# 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.
@@ -15,19 +17,30 @@ This works by creating a child logger of the extension logger which propagates a
to the parent (extensions) logger.
## Changing the Logging Level
By default, the extension logger's level is set to `DEBUG`.
To change this, uncomment (or add) the following line in `local.py`.
```python
LOGGING['handlers']['extension_file']['level'] = 'INFO'
```
*(Remember to restart your supervisor workers after changes to `local.py`)*
This will change the logger's level to the level you define.
Options are: *(all options accept entries of levels listed below them)*
* `DEBUG`
* `INFO`
* `WARNING`
* `ERROR`
* `CRITICAL`
## allianceauth.services.hooks.get_extension_logger
```{eval-rst}
.. automodule:: allianceauth.services.hooks.get_extension_logger
:members:
:undoc-members:
```

View File

@@ -1,13 +1,13 @@
# Menu Hooks
The menu hooks allow you to dynamically specify menu items from your plugin app or service. To achieve this you should subclass or instantiate the `services.hooks.MenuItemHook` class and then register the menu item with one of the hooks.
The menu hooks allow you to dynamically specify menu items from your plugin app or service. To achieve this, you should subclass or instantiate the `services.hooks.MenuItemHook` class and then register the menu item with one of the hooks.
To register a MenuItemHook class you would do the following:
To register a MenuItemHook class, you would do the following:
```Python
```python
@hooks.register('menu_item_hook')
def register_menu():
return MenuItemHook('Example Item', 'glyphicon glyphicon-heart', 'example_url_name',150)
return MenuItemHook('Example Item', 'fas fa-users fa-fw', 'example_url_name',150)
```
The `MenuItemHook` class specifies some parameters/instance variables required for menu item display.
@@ -16,7 +16,7 @@ The `MenuItemHook` class specifies some parameters/instance variables required f
### text
The text shown as menu item, e.g. usually the name of the app.
The text shown as menu item, e.g., usually the name of the app.
### classes
@@ -28,7 +28,7 @@ The name of the Django URL to use
### order
An integer which specifies the order of the menu item, lowest to highest. Community apps are free ot use an oder above `1000`. Numbers below are served for Auth.
An integer which specifies the order of the menu item, lowest to highest. Community apps are free ot use an oder above `1000`. The numbers below are reserved for Auth.
### navactive
@@ -38,18 +38,17 @@ A list of views or namespaces the link should be highlighted on. See [django-nav
`count` is an integer shown next to the menu item as badge when `count` is not `None`.
This is a great feature to signal the user, that he has some open issues to take care of within an app. For example Auth uses this feature to show the specific number of open group request to the current user.
This is a great feature to signal the user that he has some open issues to take care of within an app. For example, Auth uses this feature to show the specific number of open group request to the current user.
```eval_rst
.. hint::
Here is how to stay consistent with the Auth design philosophy for using this feature:
1. Use it to display open items that the current user can close by himself only. Do not use it for items, that the user has no control over.
2. If there are currently no open items, do not show a badge at all.
```
:::{hint}
Here is how to stay consistent with the Auth design philosophy for using this feature:
1. Use it to display open items that the current user can close by himself only. Do not use it for items that the user has no control over.
2. If there are currently no open items, do not show a badge at all.
:::
To use it set count the `render()` function of your subclass in accordance to the current user. Here is an example:
```Python
```python
def render(self, request):
# ...
self.count = calculate_count_for_user(request.user)

View File

@@ -2,9 +2,9 @@
## Base functionality
The URL hooks allow you to dynamically specify URL patterns from your plugin app or service. To achieve this you should subclass or instantiate the `services.hooks.UrlHook` class and then register the URL patterns with the hook.
The URL hooks allow you to dynamically specify URL patterns from your plugin app or service. To achieve this, you should subclass or instantiate the `services.hooks.UrlHook` class and then register the URL patterns with the hook.
To register a UrlHook class you would do the following:
To register a UrlHook class, you would do the following:
```python
@hooks.register('url_hook')
@@ -14,14 +14,13 @@ def register_urls():
### Public views
In addition is it possible to make views public. Normally, all views are automatically decorated with the `main_character_required` decorator. That decorator ensures a user needs to be logged in and have a main before he can access that view. This feature protects against a community app sneaking in a public view without the administrator knowing about it.
In addition, is it possible to make views public. Normally, all views are automatically decorated with the `main_character_required` decorator. That decorator ensures a user needs to be logged in and have a main before he can access that view. This feature protects against a community app sneaking in a public view without the administrator knowing about it.
An app can opt-out of this feature by adding a list of views to be excluded when registering the URLs. See the `excluded_views` parameter for details.
An app can opt out of this feature by adding a list of views to be excluded when registering the URLs. See the `excluded_views` parameter for details.
```eval_rst
.. note::
Note that for a public view to work, administrators need to also explicitly allow apps to have public views in their AA installation, by adding the apps label to ``APPS_WITH_PUBLIC_VIEWS`` setting.
```
:::{note}
Note that for a public view to work, administrators need to also explicitly allow apps to have public views in their AA installation, by adding the app label to ``APPS_WITH_PUBLIC_VIEWS`` setting.
:::
## Examples
@@ -43,7 +42,7 @@ urlpatterns = [
]
```
Subsequently it would implement the UrlHook in a dedicated `auth_hooks.py` file like so:
Subsequently, it would implement the UrlHook in a dedicated `auth_hooks.py` file like so:
```python
from alliance_auth import hooks
@@ -59,7 +58,7 @@ When this app is included in the project's `settings.INSTALLED_APPS` users would
## API
```eval_rst
```{eval-rst}
.. autoclass:: allianceauth.services.hooks.UrlHook
:members:
```

View File

@@ -1,21 +1,20 @@
# Development on Windows 10 with WSL and Visual Studio Code
This document describes step-by-step how to setup a complete development environment for Alliance Auth apps on Windows 10 with Windows Subsystem for Linux (WSL) and Visual Studio Code.
This document describes step-by-step how to set up a complete development environment for Alliance Auth apps on Windows 10 with Windows Subsystem for Linux (WSL) and Visual Studio Code.
The main benefit of this setup is that it runs all services and code in the native Linux environment (WSL) and at the same time can be full controlled from within a comfortable Windows IDE (Visual Studio Code) including code debugging.
The main benefit of this setup is that it runs all services and code in the native Linux environment (WSL) and at the same time can be fully controlled from within a comfortable Windows IDE (Visual Studio Code) including code debugging.
In addition all tools described in this guide are open source or free software.
In addition, all tools described in this guide are open source or free software.
```eval_rst
.. hint::
This guide is meant for development purposes only and not for installing AA in a production environment. For production installation please see chapter **Installation**.
```
:::{hint}
This guide is meant for development purposes only and not for installing AA in a production environment. For production installation, please see chapter **Installation**.
:::
## Overview
The development environment consists of the following components:
- Visual Studio Code with Remote WSL and Python extension
- Visual Studio Code with the Remote WSL and Python extension
- WSL with Ubuntu (18.04. LTS or higher)
- Python environment on WSL (3.8 or higher)
- MySQL server on WSL
@@ -23,86 +22,77 @@ The development environment consists of the following components:
- Alliance Auth on WSL
- Celery on WSL
We will use the build-in Django development web server, so we don't need to setup a WSGI server or a web server.
We will use the build-in Django development web server, so we don't need to set up a WSGI server or a web server.
```eval_rst
.. note::
This setup works with both WSL 1 and WSL 2. However, due to the significantly better performance we recommend WSL 2.
```
:::{note}
This setup works with both WSL 1 and WSL 2. However, due to the significantly better performance, we recommend WSL 2.
:::
## Requirement
The only requirement is a PC with Windows 10 and Internet connection in order to download the additional software components.
The only requirement is a PC with Windows 10 and Internet connection to download the additional software components.
## Installing Windows apps
### Windows Subsystem for Linux
- Install from here: [Microsoft docs](https://docs.microsoft.com/en-us/windows/wsl/install-win10)
- Choose Ubuntu 18.04. LTS or higher
### Visual Studio Code
- Install from here: [VSC Download](https://code.visualstudio.com/Download)
- Open the app and install the following VSC extensions:
- Remote WSL
- Connect to WSL. This will automatically install the VSC server on the VSC server for WSL
- Once connected to WSL install the Python extension on the WSL side
- Once connected to WSL, install the Python extension on the WSL side
## Setting up WSL / Linux
Open a WSL bash and update all software packets:
```bash
```shell
sudo apt update && sudo apt upgrade -y
```
### Install Tools
```bash
```shell
sudo apt-get install build-essential
sudo apt-get install gettext
```
### Install Python
Next we need to install Python and related development tools.
Next, we need to install Python and related development tools.
```eval_rst
.. hint::
To check your system's Python 3 version you can enter: ``python3 --version``
:::{note}
Should your Ubuntu come with a newer version of Python we recommend to still set up your dev environment with the oldest Python 3 version currently supported by AA (e.g., Python 3.8 at this time of writing) to ensure your apps are compatible with all current AA installations
You can check out this `page <https://askubuntu.com/questions/682869/how-do-i-install-a-different-python-version-using-apt-get/1195153>`_ on how to install additional Python versions on Ubuntu.
If you install a different python version from the default, you need to adjust some commands below to install appopriate versions of those packages, for example, using Python 3.8 you might need to run the following after using the setup steps for the repository mentioned in the AskUbuntu post above:
```shell
sudo apt-get install python3.8 python3.8-dev python3.8-venv python3-setuptools python3-pip python-pip
```
```eval_rst
.. note::
Should your Ubuntu come with a newer version of Python we recommend to still setup your dev environment with the oldest Python 3 version currently supported by AA (e.g Python 3.8 at this time of writing) to ensure your apps are compatible with all current AA installations
You an check out this `page <https://askubuntu.com/questions/682869/how-do-i-install-a-different-python-version-using-apt-get/1195153>`_ on how to install additional Python versions on Ubuntu.
If you install a different python version from the default you need to adjust some of the commands below to install appopriate versions of those packages for example using Python 3.8 you might need to run the following after using the setup steps for the repository mentioned in the AskUbuntu post above:
`sudo apt-get install python3.8 python3.8-dev python3.8-venv python3-setuptools python3-pip python-pip`
```
:::
Use the following command to install Python 3 with all required libraries with the default version:
```bash
```shell
sudo apt-get install python3 python3-dev python3-venv python3-setuptools python3-pip python-pip
```
### Install redis and other tools
```bash
```shell
sudo apt-get install unzip git redis-server curl libssl-dev libbz2-dev libffi-dev pkg-config
```
Start redis
```bash
```shell
sudo redis-server --daemonize yes
```
@@ -110,30 +100,29 @@ sudo redis-server --daemonize yes
Install MySQL and required libraries with the following command:
```bash
```shell
sudo apt-get install mysql-server mysql-client libmysqlclient-dev
```
```eval_rst
.. note::
We chose to use MySQL instead of MariaDB, because the standard version of MariaDB that comes with this Ubuntu distribution will not work with AA.
```
:::{note}
We chose to use MySQL instead of MariaDB, because the standard version of MariaDB that comes with this Ubuntu distribution will not work with AA.
:::
We need to apply a permission fix to mysql or you will get a warning with every startup:
We need to apply a permission fix to mysql, or you will get a warning with every startup:
```bash
```shell
sudo usermod -d /var/lib/mysql/ mysql
```
Start the mysql server
```bash
```shell
sudo service mysql start
```
Create database and user for AA
Create a database and user for AA
```bash
```shell
sudo mysql -u root
```
@@ -147,26 +136,25 @@ exit;
Add timezone info to mysql:
```bash
```shell
sudo mysql_tzinfo_to_sql /usr/share/zoneinfo | sudo mysql -u root mysql
```
```eval_rst
.. note::
If your WSL does not have an init.d service, it will not automatically start your services such as MySQL and Redis when you boot your Windows machine and you have to manually start them. For convenience we recommend putting these commands in a bash script. Here is an example:
::
#/bin/bash
# start services for AA dev
sudo service mysql start
sudo redis-server --daemonize yes
:::{note}
If your WSL does not have an init.d service, it will not automatically start your services such as MySQL and Redis when you boot your Windows machine, and you have to manually start them. For convenience, we recommend putting these commands in a bash script. Here is an example:
```shell
#/bin/bash
# start services for AA dev
sudo service mysql start
sudo redis-server --daemonize yes
```
:::
### Setup dev folder on WSL
Setup your folders on WSL bash for your dev project. Our approach will setup one AA project with one venv and multiple apps running under the same AA project, but each in their own folder and git.
Set up your folders on WSL bash for your dev project. Our approach will set up one AA project with one venv and multiple apps running under the same AA project, but each in their own folder and git.
A good location for setting up this folder structure is your home folder or a subfolder of your home:
@@ -179,32 +167,31 @@ A good location for setting up this folder structure is your home folder or a su
|- ...
```
Following this approach you can also setup additional AA projects, e.g. aa-dev-2, aa-dev-3 if needed.
Following this approach, you can also set up additional AA projects, e.g. aa-dev-2, aa-dev-3 if needed.
Create the root folder `aa-dev`.
```eval_rst
.. hint::
The folders `venv` and `myauth` will be created automatically in later steps. Please do not create them manually as this would lead to errors.
```
:::{hint}
The folders `venv` and `myauth` will be created automatically in later steps. Please do not create them manually as this would lead to errors.
:::
### Setup virtual Python environment for aa-dev
Create the virtual environment. Run this in your aa-dev folder:
```bash
```shell
python3 -m venv venv
```
And activate your venv:
```bash
```shell
source venv/bin/activate
```
### Install and update basic Python packages
```bash
```shell
pip install -U pip setuptools wheel
```
@@ -212,29 +199,29 @@ pip install -U pip setuptools wheel
### Install and create AA instance
```bash
```shell
pip install allianceauth
```
Now we are ready to setup our AA instance. Make sure to run this command in your aa-dev folder:
Now we are ready to set up our AA instance. Make sure to run this command in your aa-dev folder:
```bash
```shell
allianceauth start myauth
```
Next we will setup our VSC project for aa-dev by starting it directly from the WSL bash:
Next, we will set up our VSC project for aa-dev by starting it directly from the WSL bash:
```bash
```shell
code .
```
First you want to make sure exclude the venv folder from VSC as follows:
Open settings and go to Files:Exclude
Add pattern: `**/venv`
Add the pattern: `**/venv`
### Create EVE Online SSO App
For the Eve Online related setup you need to create a SSO app on the developer site:
For the Eve Online related setup you need to create an SSO app on the developer site:
- Create your Eve Online SSO App on the [Eve Online developer site](https://developers.eveonline.com/)
- Add all ESI scopes
@@ -244,10 +231,9 @@ For the Eve Online related setup you need to create a SSO app on the developer s
Open your local Django settings with VSC. The file is under `myauth/myauth/settings/local.py`
```eval_rst
.. hint::
There are two Django settings files: ``base.py`` and ``local.py``. The base settings file is controlled by the AA project and may change at any time. It is therefore recommended to only change the local settings file.
```
:::{hint}
There are two Django settings files: ``base.py`` and ``local.py``. The base settings file is controlled by the AA project and may change at any time. It is therefore recommended to only change the local settings file.
:::
```python
DEBUG = True
@@ -291,16 +277,16 @@ REGISTRATION_VERIFY_EMAIL = False
### Migrations and superuser
Before we can start AA we need to run migrations:
Before we can start AA, we need to run migrations:
```bash
```shell
cd myauth
python manage.py migrate
```
We also need to create a superuser for our AA installation:
```bash
```shell
python manage.py createsuperuser
```
@@ -310,50 +296,48 @@ python manage.py createsuperuser
We are now ready to run out AA instance with the following command:
```bash
```shell
python manage.py runserver
```
Once running you can access your auth site on the browser under `http://localhost:8000`. Or the admin site under `http://localhost:8000/admin`
Once running, you can access your auth site on the browser under `http://localhost:8000`. Or the admin site under `http://localhost:8000/admin`
```eval_rst
.. hint::
You can start your AA server directly from a terminal window in VSC or with a VSC debug config (see chapter about debugging for details).
```
:::{hint}
You can start your AA server directly from a terminal window in VSC or with a VSC debug config (see chapter about debugging for details).
:::
```eval_rst
.. note::
**Debug vs. Non-Debug mode**
Usually it is best to run your dev AA instance in debug mode, so you get all the detailed error messages that helps a lot for finding errors. But there might be cases where you want to test features that do not exist in debug mode (e.g. error pages) or just want to see how your app behaves in non-debug / production mode.
:::{note}
**Debug vs. Non-Debug mode**
Usually it is best to run your dev AA instance in debug mode, so you get all the detailed error messages that help a lot for finding errors. But there might be cases where you want to test features that do not exist in debug mode (e.g. error pages) or just want to see how your app behaves in non-debug / production mode.
When you turn off debug mode you will see a problem though: Your pages will not render correctly. The reason is that Django will stop serving your static files in production mode and expect you to serve them from a real web server. Luckily, there is an option that forces Django to continue serving your static files directly even when not in debug mode. Just start your server with the following option: ``python manage.py runserver --insecure``
```
When you turn off debug mode, you will see a problem though: Your pages will not render correctly. The reason is that Django will stop serving your static files in production mode and expect you to serve them from a real web server. Luckily, there is an option that forces Django to continue serving your static files directly even when not in debug mode. Start your server with the following option: ``python manage.py runserver --insecure``
:::
### Celery
In addition you can start a celery worker instance for myauth. For development purposed it makes sense to only start one instance and add some additional logging.
In addition, you can start a celery worker instance for myauth. For development purposes, it makes sense to only start one instance and add some additional logging.
This can be done from the command line with the following command in the myauth folder (where manage.py is located):
```bash
```shell
celery -A myauth worker -l info -P solo
```
Same as AA itself you can start Celery from any terminal session, from a terminal window within VSC or as a debug config in VSC (see chapter about debugging for details). For convenience we recommend starting Celery as debug config.
Same as AA itself, you can start Celery from any terminal session, from a terminal window within VSC or as a debug config in VSC (see chapter about debugging for details). For convenience, we recommend starting Celery as debug config.
## Debugging setup
To be able to debug your code you need to add debugging configuration to VSC. At least one for AA and one for celery.
To be able to debug your code, you need to add a debugging configuration to VSC. At least one for AA and one for celery.
### Breakpoints
By default VSC will break on any uncaught exception. Since every error raised by your tests will cause an uncaught exception we recommend to deactivate this feature.
By default, VSC will break on any uncaught exception. Since every error raised by your tests will cause an uncaught exception, we recommend deactivating this feature.
To deactivate open click on the debug icon to switch to the debug view. Then un-check "Uncaught Exceptions" on the breakpoints window.
To deactivate, click on the debug icon to switch to the debug view. Then uncheck "Uncaught Exceptions" in the "Breakpoints" window.
### AA debug config
In VSC click on Debug / Add Configuration and choose "Django". Should Django not appear as option make sure to first open a Django file (e.g. the local.py settings) to help VSC detect that you are using Django.
In VSC, click on Debug / Add Configuration and choose "Django". Should Django not appear as an option, make sure to first open a Django file (e.g., the local.py settings) to help VSC detect that you are using Django.
The result should look something like this:
@@ -375,7 +359,7 @@ The result should look something like this:
### Debug celery
For celery we need another debug config, so that we can run it in parallel to our AA instance.
For celery, we need another debug config, so that we can run it in parallel to our AA instance.
Here is an example debug config for Celery:
@@ -403,7 +387,7 @@ Here is an example debug config for Celery:
### Debug config for unit tests
Finally it makes sense to have a dedicated debug config for running unit tests. Here is an example config for running all tests of the app `example`.
Finally, it makes sense to have a dedicated debug config for running unit tests. Here is an example config for running all tests of the app `example`.
```json
{
@@ -423,11 +407,11 @@ Finally it makes sense to have a dedicated debug config for running unit tests.
},
```
You can also specify to run just a part of your test suite down to a test method. Just give the full path to the test you want to run, e.g. `example.test.test_models.TestDemoModel.test_this_method`
You can also specify to run just a part of your test suite down to a test method. Give the full path to the test you want to run, e.g. `example.test.test_models.TestDemoModel.test_this_method`
### Debugging normal python scripts
Finally you may also want to have a debug config to debug a non-Django Python script:
Finally, you may also want to have a debug config to debug a non-Django Python script:
```json
{
@@ -463,43 +447,41 @@ Extension for Visual Studio Code - Markdown linting and style checking for Visua
#### Live Server
Live Server allows you to start a mini webserver for any file quickly. This can e.g. be useful for looking at changes to to Sphinx docs.: [Live Server](https://marketplace.visualstudio.com/items?itemName=ritwickdey.LiveServer)
Live Server allows you to start a mini webserver for any file quickly. This can e.g. be useful for looking at changes to Sphinx docs.: [Live Server](https://marketplace.visualstudio.com/items?itemName=ritwickdey.LiveServer)
### Django apps
#### Django Extensions
[django-extensions](https://django-extensions.readthedocs.io/en/latest/) is a swiss army knife for django developers with adds a lot of very useful features to your Django site. Here are a few highlights:
[django-extensions](https://django-extensions.readthedocs.io/en/latest/) is a swiss army knife for django developers with adds a lot of useful features to your Django site. Here are a few highlights:
- shell_plus - An enhanced version of the Django shell. It will auto-load all your models at startup so you don't have to import anything and can use them right away.
- graph_models - Creates a dependency graph of Django models. Visualizing a model dependency structure can be very useful for trying to understand how an existing Django app works, or e.g. how all the AA models work together.
- runserver_plus - The standard runserver stuff but with the Werkzeug debugger baked in. This is a must have for any serious debugging.
- `shell_plus` - An enhanced version of the Django shell. It will autoload all your models at startup, so you don't have to import anything and can use them right away.
- `graph_models` - Creates a dependency graph of Django models. Visualizing a model dependency structure can be useful for trying to understand how an existing Django app works, or e.g., how all the AA models work together.
- `runserver_plus` - The standard runserver stuff but with the debugger baked in. This is a must-have for any serious debugging.
#### Django Debug Toolbar
The [Django Debug Toolbar](https://github.com/jazzband/django-debug-toolbar) is a configurable set of panels that display various debug information about the current request/response and when clicked, display more details about the panel's content.
E.g. this tool is invaluable to debug and fix performance issues with Django queries.
The [Django Debug Toolbar](https://github.com/jazzband/django-debug-toolbar) is a configurable set of panels that display various debug information about the current request/response and when clicked, display more details about the panel's content. This tool is invaluable to debug and fix performance issues with Django queries.
### Windows applications
#### DBeaver
DBeaver is a free universal database tool and works with many different kinds of databases include MySQL. It can be installed on Windows 10 and will be able to help manage your MySQL databases running on WSL.
DBeaver is a free universal database tool and works with many different kinds of databases including MySQL. It can be installed on Windows 10 and will be able to help manage your MySQL databases running on WSL.
Install from here. [DBeaver](https://dbeaver.io/)
## Adding apps for development
The idea behind the particular folder structure of aa-dev is to have each and every app in its own folder and git repo. To integrate them with the AA instance they need to be installed once using the -e option that enabled editing of the package. And then added to the INSTALLED_APPS settings.
The idea behind the particular folder structure of aa-dev is to have each and every app in its own folder and git repo. To integrate them with the AA instance, they need to be installed once using the -e option that enabled editing of the package. And then added to the INSTALLED_APPS settings.
To demonstrate let's add the example plugin to our environment.
To demonstrate, let's add the example plugin to our environment.
Open a WSL bash and navigate to the aa-dev folder. Make sure you have activate your virtual environment. (`source venv/bin/activate`)
Open a WSL bash and navigate to the aa-dev folder. Make sure you have activated your virtual environment. (`source venv/bin/activate`)
Run these commands:
```bash
```shell
git clone https://gitlab.com/ErikKalkoken/allianceauth-example-plugin.git
pip install -e allianceauth-example-plugin
```
@@ -508,7 +490,7 @@ Add `'example'` to INSTALLED_APPS in your `local.py` settings.
Run migrations and restart your AA server, e.g.:
```bash
```shell
cd myauth
python manage.py migrate
```

View File

@@ -2,9 +2,8 @@
Here you find guides on how to setup your development environment for AA.
```eval_rst
.. toctree::
:maxdepth: 1
:::{toctree}
:maxdepth: 1
aa-dev-setup-wsl-vsc-v2
```
aa-dev-setup-wsl-vsc-v2
:::

View File

@@ -2,12 +2,11 @@
**Alliance Auth** is designed to be extended easily. Learn how to develop your own apps and services for AA or to develop for AA core in the development chapter.
```eval_rst
.. toctree::
:maxdepth: 1
:::{toctree}
:maxdepth: 1
custom/index
aa_core/index
dev_setup/index
tech_docu/index
```
custom/index
aa_core/index
dev_setup/index
tech_docu/index
:::

View File

@@ -1,17 +1,16 @@
# API
To reduce redundancy and help speed up development we encourage developers to utilize the following packages when developing apps for Alliance Auth.
To reduce redundancy and help speed up development, we encourage developers to utilize the following packages when developing apps for Alliance Auth.
```eval_rst
.. toctree::
:maxdepth: 1
:::{toctree}
:maxdepth: 1
discord_client
discord_service
esi
evelinks
eveonline
notifications
testutils
utils
```
discord_client
discord_service
esi
evelinks
eveonline
notifications
testutils
utils
:::

View File

@@ -2,32 +2,31 @@
**Alliance Auth** uses Celery for asynchronous task management. This page aims to give developers some guidance on how to use Celery when developing apps for Alliance Auth.
For a complete documentation of Celery please refer to the [official Celery documentation](http://docs.celeryproject.org/en/latest/index.html).
For the complete documentation of Celery, please refer to the [official Celery documentation](http://docs.celeryproject.org/en/latest/index.html).
## When should I use Celery in my app?
There are two main cases for using celery. Long duration of a process and recurrence of a process.
There are two main reasons for using celery. Long duration of a process, and recurrence of a process.
### Duration
Alliance Auth is an online web application and as such the user expects fast and immediate responses to any of his clicks or actions. Same as with any other good web site. Good response times are measures in ms and a user will perceive everything that takes longer than 1 sec as an interruption of his flow of thought (see also [Response Times: The 3 Important Limits](https://www.nngroup.com/articles/response-times-3-important-limits/)).
Alliance Auth is an online web application, and as such, the user expects fast and immediate responses to any of his clicks or actions. Same as with any other good website. Good response times are measured in ms, and a user will perceive everything that takes longer than 1 sec as an interruption of his flow of thought (see also [Response Times: The 3 Important Limits](https://www.nngroup.com/articles/response-times-3-important-limits/)).
As a rule of thumb we therefore recommend to use celery tasks for every process that can take longer than 1 sec to complete (also think about how long your process might take with large amounts of data).
As a rule of thumb, we therefore recommend using celery tasks for every process that can take longer than 1 sec to complete (also think about how long your process might take with large amounts of data).
```eval_rst
.. note::
Another solution for dealing with long response time in particular when loading pages is to load parts of a page asynchronously, for example with AJAX.
```
:::{note}
Another solution for dealing with long response time in particular when loading pages is to load parts of a page asynchronously, for example, with AJAX.
:::
### Recurrence
Another case for using celery tasks is when you need recurring execution of tasks. For example you may want to update the list of characters in a corporation from ESI every hour.
Another case for using celery tasks is when you need recurring execution of tasks. For example, you may want to update the list of characters in a corporation from ESI every hour.
These are called periodic tasks and Alliance Auth uses [celery beat](https://docs.celeryproject.org/en/latest/userguide/periodic-tasks.html) to implement them.
These are called periodic tasks, and Alliance Auth uses [celery beat](https://docs.celeryproject.org/en/latest/userguide/periodic-tasks.html) to implement them.
## What is a celery task?
For the most part a celery task is a Python functions that is configured to be executed asynchronously and controlled by Celery. Celery tasks can be automatically retried, executed periodically, executed in work flows and much more. See the [celery docs](https://docs.celeryproject.org/en/latest/userguide/tasks.html) for a more detailed description.
For the most part, a celery task is a Python function configured to be executed asynchronously and controlled by Celery. Celery tasks can be automatically retried, executed periodically, executed in work flows and much more. See the [celery docs](https://docs.celeryproject.org/en/latest/userguide/tasks.html) for a more detailed description.
## How should I use Celery in my app?
@@ -40,7 +39,7 @@ Please use the following approach to ensure your tasks are working properly with
Here is an example implementation of a task:
```Python
```python
import logging
from celery import shared_task
@@ -54,7 +53,7 @@ def example():
This task can then be started from any another Python module like so:
```Python
```python
from .tasks import example
example.delay()
@@ -62,25 +61,25 @@ example.delay()
## How should I use celery tasks in the UI?
There is a well established pattern for integrating asynchronous processes in the UI, for example when the user asks your app to perform a longer running action:
There is a well-established pattern for integrating asynchronous processes in the UI, for example, when the user asks your app to perform a longer running action:
1. Notify the user immediately (with a Django message) that the process for completing the action has been started and that he will receive a report once completed.
2. Start the celery task
3. Once the celery task is completed it should send a notification containing the result of the action to the user. It's important to send that notification also in case of errors.
3. Once the celery task is completed, it should send a notification containing the result of the action to the user. It's important to send that notification also in case of errors.
## Can I use long running tasks?
## Can I use long-running tasks?
Long running tasks are possible, but in general Celery works best with short running tasks. Therefore we strongly recommend to try and break down long running tasks into smaller tasks if possible.
Long-running tasks are possible, but in general Celery works best with short running tasks. Therefore, we strongly recommend trying to break down long-running tasks into smaller tasks if possible.
If contextually possible try to break down your long running task in shorter tasks that can run in parallel.
If contextually possible, try to break down your long-running task in shorter tasks that can run in parallel.
However, many long running tasks consist of several smaller processes that need to run one after the other. For example you may have a loop where you perform the same action on hundreds of objects. In those cases you can define each of the smaller processes as it's own task and then link them together, so that they are run one after the other. That is called chaining in Celery and is the preferred approach for implementing long running processes.
However, many long-running tasks consist of several smaller processes that need to run one after the other. For example, you may have a loop where you perform the same action on hundreds of objects. In those cases, you can define each of the smaller processes as its own task and then link them together, so that they are run one after the other. That is called chaining in Celery and is the preferred approach for implementing long-running processes.
Example implementation for a celery chain:
```Python
```python
import logging
from celery import shared_task, chain
@@ -102,42 +101,41 @@ def long_runner():
chain(my_tasks).delay()
```
In this example we fist add 10 example tasks that need to run one after the other to a list. This can be done by creating a so called signature for a task. Those signature are a kind of wrapper for tasks and can be used in various ways to compose work flow for tasks.
In this example, we first add 10 example tasks that need to run one after the other to a list. This can be done by creating a so-called signature for a task. Those signatures are a kind of wrapper for tasks and can be used in various ways to compose work flow for tasks.
The list of task signatures is then converted to a chain and started asynchronously.
```eval_rst
.. hint::
In our example we use ``si()``, which is a shortcut for "immutable signatures" and prevents us from having to deal with result sharing between tasks.
:::{hint}
In our example we use ``si()``, which is a shortcut for "immutable signatures" and prevents us from having to deal with result sharing between tasks.
For more information on signature and work flows see the official documentation on `Canvas <https://docs.celeryproject.org/en/latest/userguide/canvas.html>`_.
For more information on signature and work flows see the official documentation on `Canvas <https://docs.celeryproject.org/en/latest/userguide/canvas.html>`_.
In this context please note that Alliance Auth currently only supports chaining, because all other variants require a so called results back, which Alliance Auth does not have.
```
In this context, please note that Alliance Auth currently only supports chaining because all other variants require a so-called results back, which Alliance Auth does not have.
:::
## How can I define periodic tasks for my app?
Periodic tasks are normal celery tasks which are added the scheduler for periodic execution. The convention for defining periodic tasks for an app is to define them in the local settings. So user will need to add those settings manually to his local settings during the installation process.
Periodic tasks are normal celery tasks that are added to the scheduler for periodic execution. The convention for defining periodic tasks for an app is to define them in the local settings. So user will need to add those settings manually to his local settings during the installation process.
Example setting:
```Python
```python
CELERYBEAT_SCHEDULE['structures_update_all_structures'] = {
'task': 'structures.tasks.update_all_structures',
'schedule': crontab(minute='*/30'),
}
```
- `structures_update_all_structures` is the name of the scheduling entry. You can chose any name, but the convention is name of your app plus name of the task.
- `structures_update_all_structures` is the name of the scheduling entry. You can choose any name, but the convention is name of your app plus name of the task.
- `'task'`: Name of your task (full path)
- `'schedule'`: Schedule definition (see Celery documentation on [Periodic Tasks](https://docs.celeryproject.org/en/latest/userguide/periodic-tasks.html) for details)
## How can I use priorities for tasks?
In Alliance Auth we have defined task priorities from 0 - 9 as follows:
In Alliance Auth we have defined task priorities from 0 to 9 as follows:
```eval_rst
```{eval-rst}
====== ========= ===========
Number Priority Description
====== ========= ===========
@@ -150,30 +148,25 @@ In Alliance Auth we have defined task priorities from 0 - 9 as follows:
====== ========= ===========
```
```eval_rst
.. warning::
Please make sure to use task priorities with care and especially do not use higher priorities without a good reason. All apps including Alliance Auth share the same task queues, so using higher task priorities excessively can potentially prevent more important tasks (of other apps) from completing on time.
:::{warning}
Please make sure to use task priorities with care and especially do not use higher priorities without a good reason. All apps including Alliance Auth share the same task queues, so using higher task priorities excessively can potentially prevent more important tasks (of other apps) from completing on time.
You also want to make sure to run use lower priorities if you have a large amount of tasks or long running tasks, which are not super urgent. (e.g. the regular update of all Eve characters from ESI runs with priority 7)
```
```eval_rst
.. hint::
If no priority is specified all tasks will be started with the default priority, which is 5.
```
To run a task with a different priority you need to specify it when starting it.
You also want to make sure to run use lower priorities if you have a large number of tasks or long-running tasks, which are not super urgent. (e.g., the regular update of all Eve characters from ESI runs with priority 7)
:::
:::{hint}
If no priority is specified, all tasks will be started with the default priority, which is 5.
:::
To run a task with a different priority, you need to specify it when starting it.
Example for starting a task with priority 3:
```Python
```python
example.apply_async(priority=3)
```
```eval_rst
.. hint::
For defining a priority to tasks you can not use the convenient shortcut ``delay()``, but instead need to start a task with ``apply_async()``, which also requires you to pass parameters to your task function differently. Please check out the `official docs <https://docs.celeryproject.org/en/stable/reference/celery.app.task.html#celery.app.task.Task.apply_async>`_ for details.
```
:::{hint}
For defining a priority to tasks, you cannot use the convenient shortcut ``delay()``, but instead need to start a task with ``apply_async()``, which also requires you to pass parameters to your task function differently. Please check out the `official docs <https://docs.celeryproject.org/en/stable/reference/celery.app.task.html#celery.app.task.Task.apply_async>`_ for details.
:::
## What special features should I be aware of?
@@ -181,24 +174,24 @@ Every Alliance Auth installation will come with a couple of special celery relat
### celery-once
Celery-once is a celery extension "that allows you to prevent multiple execution and queuing of celery tasks". What that means is that you can ensure that only one instance of a celery task runs at any given time. This can be useful for example if you do not want multiple instances of you task to talk to the same external service at the same time.
Celery-once is a celery extension "that allows you to prevent multiple execution and queuing of celery tasks". What that means is that you can ensure that only one instance of a celery task runs at any given time. This can be useful, for example, if you do not want multiple instances of your task to talk to the same external service at the same time.
We use a custom backend for celery_once in Alliance Auth defined [here](https://gitlab.com/allianceauth/allianceauth/-/blob/master/allianceauth/services/tasks.py#L14)
You can import it for use like so:
```Python
```python
from allianceauth.services.tasks import QueueOnce
```
An example of AllianceAuth's use within the `@sharedtask` decorator, can be seen [here](https://gitlab.com/allianceauth/allianceauth/-/blob/master/allianceauth/services/modules/discord/tasks.py#L62) in the discord module
An example of Alliance Auth's use within the `@sharedtask` decorator, can be seen [here](https://gitlab.com/allianceauth/allianceauth/-/blob/master/allianceauth/services/modules/discord/tasks.py#L62) in the discord module
You can use it like so:
```Python
```python
@shared_task(bind=True, name='your_modules.update_task', base=QueueOnce)
```
Please see the [official documentation](hhttps://pypi.org/project/celery_once/) of celery-once for details.
Please see the [official documentation](https://pypi.org/project/celery_once/) of celery-once for details.
### task priorities
Alliance Auth is using task priorities to enable priority based scheduling of task execution. Please see [How can I use priorities for tasks?](#how-can-i-use-priorities-for-tasks) for details.
Alliance Auth is using task priorities to enable priority-based scheduling of task execution. Please see [How can I use priorities for tasks?](#how-can-i-use-priorities-for-tasks) for details.

View File

@@ -1,13 +1,12 @@
# Developing apps
In this section you find topics useful for app developers.
In this section, you find topics useful for app developers.
```eval_rst
.. toctree::
:maxdepth: 1
:::{toctree}
:maxdepth: 1
api/index
celery
core_models
templatetags
```
api/index
celery
core_models
templatetags
:::

View File

@@ -1,11 +1,6 @@
# Auto Groups
```eval_rst
.. note::
New in 2.0
```
Auto groups allows you to automatically place users of certain states into Corp or Alliance based groups. These groups are created when the first user is added to them and removed when the configuration is deleted.
Auto Groups allows you to automatically place users of certain states into corp or alliance-based groups. These groups are created when the first user is added to them and removed when the configuration is deleted.
## Installation
@@ -15,30 +10,25 @@ To install this app add `'allianceauth.eveonline.autogroups',` to your `INSTALLE
## Configuring a group
When you create an autogroup config you will be given the following options:
When you create an autogroup config, you will be given the following options:
![Create Autogroup page](/_static/images/features/apps/autogroups/group-creation.png)
```eval_rst
.. warning::
After creating a group you wont be able to change the Corp and Alliance group prefixes, name source and the replace spaces settings. Make sure you configure these the way you want before creating the config. If you need to change these you will have to create a new autogroup config.
```
- States selects which states will be added to automatic Corp/Alliance groups
:::{warning}
After creating a group, you won't be able to change the Corp and Alliance group prefixes, name source, and the replace spaces settings. Make sure you configure these the way you want before creating the config. If you need to change these, you will have to create a new autogroup config.
:::
- States select which states will be added to automatic Corp/Alliance groups
- Corp/Alliance groups checkbox toggles Corp/Alliance autogroups on or off for this config.
- Corp/Alliance group prefix sets the prefix for the group name, e.g. if your Corp was called `MyCorp` and your prefix was `Corp`, your autogroup name would be created as `Corp MyCorp`. This field accepts leading/trailing spaces.
- Corp/Alliance name source sets the source of the Corp/Alliance name used in creating the group name. Currently the options are Full name and Ticker.
- Replace spaces allows you to replace spaces in the autogroup name with the value in the Replace spaces with field. This can be blank.
- Corp/Alliance group prefix sets the prefix for the group name, e.g., if your corp was called `MyCorp` and your prefix was `Corp`, your autogroup name would be created as `Corp MyCorp`. This field accepts leading/trailing spaces.
- Corp/Alliance name source sets the source of the Corp/Alliance name used in creating the group name. Currently, the options are Full name and Ticker.
- Replace spaces allows you to replace spaces in the autogroup name with the value in the replace spaces with field. This can be blank.
## Permissions
Auto Groups are configured via models in the Admin Interface, a user will require the `Staff` Flag in addition to the following permissions.
```eval_rst
```{eval-rst}
+-------------------------------------------+------------------+----------------+
| Permission | Admin Site | Auth Site |
+===========================================+==================+================+

View File

@@ -12,13 +12,13 @@ Add `'allianceauth.corputils',` to your `INSTALLED_APPS` list in your auth proje
## Creating a Corp Stats
Upon initial install, nothing will be visible. For every Corp, a model will have to be created before data can be viewed.
Upon initial installation, nothing will be visible. For every Corp, a model will have to be created before data can be viewed.
![nothing is visible](/_static/images/features/apps/corpstats/blank_header.png)
If you are a superuser, the add button will be immediate visible to you. If not, your user account requires the `add_corpstats` permission.
If you are a superuser, the "add" button will be immediately visible to you. If not, your user account requires the `add_corpstats` permission.
Corp Stats requires an EVE SSO token to access data from the EVE Swagger Interface. Upon pressing the Add button, you will be prompted to authenticated. Please select the character who is in the Corporation you want data for.
Corp Stats requires an EVE SSO token to access data from the EVE Swagger Interface. Upon pressing the Add button, you will be prompted to authenticate. Please select the character who is in the Corporation you want data for.
![authorize from the EVE site](/_static/images/features/apps/corpstats/eve_sso_authorization.png)
@@ -26,8 +26,8 @@ You will return to auth where you are asked to select a token with the green arr
![select an SSO token to create with](/_static/images/features/apps/corpstats/select_sso_token.png)
If this works (and you have permission to view the Corp Stats you just created) you'll be returned to a view of the Corp Stats.
If it fails an error message will be displayed.
If this works (and you have permission to view the Corp Stats you just created), you'll be returned to a view of the Corp Stats.
If it fails, an error message will be displayed.
## Corp Stats View
@@ -63,13 +63,13 @@ Each view contains a sortable and searchable table. The number of listings shown
![main list](/_static/images/features/apps/corpstats/main_list.png)
This list contains all main characters in registered in the selected Corporation and their alts. Each character has a link to [zKillboard](https://zkillboard.com).
This list contains all main characters registered in the selected Corporation and their alts. Each character has a link to [zKillboard](https://zkillboard.com).
#### Member List
![member list](/_static/images/features/apps/corpstats/member_list.png)
The list contains all characters in the Corporation. Red backgrounds means they are not registered in auth. A link to [zKillboard](https://zkillboard.com) is present for all characters.
The list contains all characters in the Corporation. Red backgrounds mean they are not registered in auth. A link to [zKillboard](https://zkillboard.com) is present for all characters.
If registered, the character will also have a main character, main Corporation, and main Alliance field.
#### Unregistered List
@@ -90,7 +90,7 @@ Characters from all Corp Stats to which the user has view access will be display
To use this feature, users will require some of the following:
```eval_rst
```{eval-rst}
+---------------------------------------+------------------+----------------------------------------------------+
| Permission | Admin Site | Auth Site |
+=======================================+==================+====================================================+
@@ -108,7 +108,7 @@ Users who add a Corp Stats with their token will be granted permissions to view
## Automatic Updating
By default Corp Stats are only updated on demand. If you want to automatically refresh on a schedule, add an entry to your project's settings file:
By default, Corp Stats are only updated on demand. If you want to automatically refresh on a schedule, add an entry to your project's settings file:
```python
CELERYBEAT_SCHEDULE['update_all_corpstats'] = {
@@ -134,11 +134,11 @@ Only one Corp Stats may exist at a time for a given Corporation.
>Failed to gather corporation statistics with selected token.
During initial population, the EVE Swagger Interface did not return any member data. This aborts the creation process. Please wait for the API to start working before attempting to create again.
During the initial population, the EVE Swagger Interface did not return any member data. This aborts the creation process. Please wait for the API to start working before attempting to create again.
### Failure to update Corp Stats
Any of the following errors will result in a notification to the owning user, and deletion of the Corp Stats model.
Any of the following errors will result in a notification to the owning user and deletion of the Corp Stats model.
>Your token has expired or is no longer valid. Please add a new one to create a new CorpStats.
@@ -146,7 +146,7 @@ This occurs when the SSO token is invalid, which can occur when deleted by the u
>CorpStats for (corp name) cannot update with your ESI token as you have left corp.
The SSO token's character is no longer in the Corporation which the Corp Stats is for, and therefore membership data cannot be retrieved.
The SSO token's character is no longer in the Corporation that the Corp Stats are for, and therefore membership data cannot be retrieved.
>HTTPForbidden

View File

@@ -16,13 +16,12 @@ To administer this feature, users will require some of the following.
Users do not require any permissions to interact with FAT Links created.
```eval_rst
```{eval-rst}
+---------------------------------------+------------------+--------------------------------------------------------------------------+
| Permission | Admin Site | Auth Site |
+=======================================+==================+==========================================================================+
| auth.fleetactivitytracking | None | Create and Modify FATLinks |
+---------------------------------------+------------------+--------------------------------------------------------------------------+
| auth.fleetactivitytracking_statistics | None | Can view detailed statistics for corp models and other characters. |
| auth.fleetactivitytracking_statistics | None | Can view detailed statistics for corp models and other characters. |
+---------------------------------------+------------------+--------------------------------------------------------------------------+
```

View File

@@ -4,7 +4,7 @@ This app allows you to manage applications for multiple corporations in your all
- Define application questionnaires for corporations
- Users can apply to corporations by filling outquestionnaires
- Manage review and approval process of applications
- Manage a review and approval process of applications
![hr](/_static/images/features/apps/hr.png)
@@ -20,11 +20,11 @@ The most common task is creating ApplicationForm models for corps. Only when suc
The first step is to create questions. This is achieved by creating ApplicationQuestion models, one for each question. Titles are not unique.
Next step is to create the actual ApplicationForm model. It requires an existing EveCorporationInfo model to which it will belong. It also requires the selection of questions. ApplicationForm models are unique per Corporation: only one may exist for any given Corporation concurrently.
The next step is to create the actual ApplicationForm model. It requires an existing EveCorporationInfo model to which it will belong. It also requires the selection of questions. ApplicationForm models are unique per Corporation: only one may exist for any given Corporation concurrently.
You can adjust these questions at any time. This is the preferred method of modifying the form: deleting and recreating will cascade the deletion to all received applications from this form which is usually not intended.
You can adjust these questions at any time. This is the preferred method of modifying the form: deleting and recreating will cascade the deletion to all received applications from this form, which is usually not intended.
Once completed the Corporation will be available to receive applications.
Once completed, the Corporation will be available to receive applications.
### Reviewing Applications
@@ -32,7 +32,7 @@ Superusers can see all applications, while normal members with the required perm
Selecting an application from the management screen will provide all the answers to the questions in the form at the time the user applied.
When a reviewer assigns themselves an application, they mark it as in progress. This notifies the applicant and permanently attached the reviewer to the application.
When a reviewer assigns themselves an application, they mark it as in progress. This notifies the applicant and permanently attaches the reviewer to the application.
Only the assigned reviewer can approve/reject/delete the application if they possess the appropriate permission.
@@ -44,7 +44,7 @@ To administer this feature, users will require some of the following.
Users do not require any permission to apply to a corporation and fill out the form.
```eval_rst
```{eval-rst}
+---------------------------------------+------------------+----------------------------------------------------+
| Permission | Admin Site | Auth Site |
+=======================================+==================+====================================================+
@@ -62,25 +62,25 @@ Users do not require any permission to apply to a corporation and fill out the f
A user with `auth.human_resources` can only see applications to their own corp.
Best practice is to bundle the `auth.human_resources` permission alongside the `hrapplications.approve_application` and `hrapplications.reject_application` permissions, as in isolation these don't make much sense.
Best practice is to bundle the `auth.human_resources` permission alongside the `hrapplications.approve_application` and `hrapplications.reject_application` permissions, as in isolation these make little sense.
## Models
### ApplicationQuestion
This is the model representation of a question. It contains a title, and a field for optional "helper" text. It is referenced by ApplicationForm models but acts independently. Modifying the question after it has been created will not void responses, so it's not advisable to edit the title or the answers may not make sense to reviewers.
This is the model representation of a question. It contains a title and a field for optional "helper" text. It is referenced by ApplicationForm models but acts independently. Modifying the question after it has been created will not void responses, so it's not advisable to edit the title or the answers may not make sense to reviewers.
### ApplicationForm
This is the template for an application. It points at a Corporation, with only one form allowed per Corporation. It also points at ApplicationQuestion models. When a user creates an application, they will be prompted with each question the form includes at the given time. Modifying questions in a form after it has been created will not be reflected in existing applications, so it's perfectly fine to adjust them as you see fit. Changing Corporations however is not advisable, as existing applications will point at the wrong Corporation after they've been submitted, confusing reviewers.
This is the template for an application. It points at a Corporation, with only one form allowed per Corporation. It also points at ApplicationQuestion models. When a user creates an application, they will be prompted with each question the form includes at the given time. Modifying questions in a form after it has been created will not be reflected in existing applications, so it's perfectly fine to adjust them as you see fit. Changing corporations, however, is not advisable, as existing applications will point at the wrong Corporation after they've been submitted, confusing reviewers.
### Application
This is the model representation of a completed application. It references an ApplicationForm from which it was spawned which is where the Corporation specificity comes from. It points at a user, contains info regarding its reviewer, and has a status. Shortcut properties also provide the applicant's main character, the applicant's APIs, and a string representation of the reviewer (for cases when the reviewer doesn't have a main character or the model gets deleted).
This is the model representation of a completed application. It references an ApplicationForm from which it was spawned, which is where the Corporation specificity comes from. It points at a user, contains info regarding its reviewer, and has a status. Shortcut properties also provide the applicant's main character, the applicant's APIs, and a string representation of the reviewer (for cases when the reviewer doesn't have a main character or the model gets deleted).
### ApplicationResponse
This is an answer to a question. It points at the Application to which it belongs, to the ApplicationQuestion which it is answering, and contains the answer text. Modifying any of these fields in dangerous.
This is an answer to a question. It points at the Application to which it belongs, to the ApplicationQuestion which it is answering, and contains the answer text. Modifying any of these fields is dangerous.
### ApplicationComment
@@ -90,8 +90,8 @@ This is a reviewer's comment on an application. Points at the application, point
### No corps accepting applications
Ensure there are ApplicationForm models in the admin site. Ensure the user does not already have an application to these Corporations. If the users wishes to re-apply they must first delete their completed application
Ensure there are ApplicationForm models in the admin site. Ensure the user does not already have an application to these Corporations. If the users wish to re-apply, they must first delete their completed application
### Reviewer unable to complete application
Reviewers require a permission for each of the three possible outcomes of an application, Approve Reject or Delete. Any user with the human resources permission can mark an application as in-progress, but if they lack these permissions then the application will get stuck. Either grant the user the required permissions or change the assigned reviewer in the admin site. Best practice is to bundle the `auth.human_resources` permission alongside the `hrapplications.approve_application` and `hrapplications.reject_application` permissions, as in isolation these don't serve much purpose.
Reviewers require permission for each of the three possible outcomes of an application, Approve Reject or Delete. Any user with the human resources permission can mark an application as in-progress, but if they lack these permissions, then the application will get stuck. Either grant the user the required permissions or change the assigned reviewer in the admin site. Best practice is to bundle the `auth.human_resources` permission alongside the `hrapplications.approve_application` and `hrapplications.reject_application` permissions, as in isolation these serve little purpose.

View File

@@ -1,17 +1,16 @@
# Apps
**Alliance Auth** comes with a set of apps (also called plugin-apps) which provide basic functions useful to many organizations in Eve Online like a fleet schedule and a timerboard. This section describes which apps are available and how to install and use them. Please note that any app need to be installed before it can be used.
**Alliance Auth** comes with a set of apps (also called plugin-apps) which provide basic functions useful to many organizations in Eve Online like a fleet schedule and a timerboard. This section describes which apps are available and how to install and use them. Please note that any app needs to be installed before it can be used.
```eval_rst
.. toctree::
:maxdepth: 1
:::{toctree}
:maxdepth: 1
autogroups
corpstats
fleetactivitytracking
hrapplications
optimer
permissions_tool
srp
timerboard
```
autogroups
corpstats
fleetactivitytracking
hrapplications
optimer
permissions_tool
srp
timerboard
:::

View File

@@ -12,7 +12,7 @@ Add `'allianceauth.optimer',` to your `INSTALLED_APPS` list in your auth project
To use and administer this feature, users will require some of the following.
```eval_rst
```{eval-rst}
+---------------------------------------+------------------+--------------------------------------------------------------------------+
| Permission | Admin Site | Auth Site |
+=======================================+==================+==========================================================================+

View File

@@ -1,6 +1,6 @@
# Permissions Auditing
Access to most of Alliance Auth's features are controlled by Django's permissions system. In order to help you secure your services, Alliance Auth provides a permissions auditing tool.
Access to most of Alliance Auth's features is controlled by Django's permissions system. To help you secure your services, Alliance Auth provides a permission auditing tool.
This is an optional app that needs to be installed.
@@ -10,9 +10,9 @@ To install it add `'allianceauth.permissions_tool',` to your `INSTALLED_APPS` li
### Access
In order to grant users access to the permissions auditing tool they will need to be granted the `permissions_tool.audit_permissions` permission or be a superuser.
To grant users access to the permission auditing tool, they will need to be granted the `permissions_tool.audit_permissions` permission or be a superuser.
When a user has access to the tool they will see the "Permissions Audit" menu item under the "Util" sub menu.
When a user has access to the tool, they will see the "Permissions Audit" menu item.
### Permissions Overview
@@ -42,7 +42,7 @@ Please note that users may appear multiple times if this permission is granted v
To use this feature, users will require some of the following.
```eval_rst
```{eval-rst}
+---------------------------------------+------------------+--------------------------------------------------------------------------+
| Permission | Admin Site | Auth Site |
+=======================================+==================+==========================================================================+

View File

@@ -12,7 +12,7 @@ Add `'allianceauth.srp',` to your `INSTALLED_APPS` list in your auth project's s
To use and administer this feature, users will require some of the following.
```eval_rst
```{eval-rst}
+----------------------+------------------+------------------------------------------------------------+
| Permission | Admin Site | Auth Site |
+======================+==================+============================================================+

View File

@@ -12,7 +12,7 @@ Add `'allianceauth.timerboard',` to your `INSTALLED_APPS` list in your auth proj
To use and administer this feature, users will require some of the following.
```eval_rst
```{eval-rst}
+---------------------------------------+------------------+--------------------------------------------------------------------------+
| Permission | Admin Site | Auth Site |
+=======================================+==================+==========================================================================+

View File

@@ -1,7 +1,7 @@
# Community Contributions
Another key feature of **Alliance Auth** is that it can be easily extended. Our great community is providing a variety of plug-in apps and services, which you can choose from to add more functions to your AA installation.
Another key feature of **Alliance Auth** is that it can be easily extended. Our great community is providing a variety of plug-in apps and services, which you can choose from to add more functions to your AA installation.
Check out the [Community Creations](https://gitlab.com/allianceauth/community-creations) repo for more details.
Or if you have specific needs you can of course always develop your own plugin- apps and services. Please see the [Development](/development/index.md) chapter for details.
Or if you have specific needs, you can always develop your own plugin-apps and services. Please see the [Development](/development/index.md) chapter for details.

View File

@@ -1,51 +1,49 @@
# Admin Site
The admin site allows administrators to configure, manage and trouble shoot Alliance Auth and all it's applications and services. E.g. you can create new groups and assign groups to users.
The admin site allows administrators to configure, manage and troubleshoot Alliance Auth and all its applications and services. E.g., you can create new groups and assign groups to users.
You can open the admin site by clicking on "Admin" in the drop down menu for a user that has access.
You can open the admin site by clicking on "Admin" in the drop-down menu for a user that has access.
![Admin Site](/_static/images/features/core/admin_site.png)
## Setup for small to medium size installations
For small to medium size alliances it is often sufficient to have no more then two superuser admins (admins that also are superusers). Having two admins usually makes sense, so you can have one primary and one backup.
For small to medium size alliances, it is often sufficient to have no more than two superuser admins (admins that also are superusers). Having two admins usually makes sense, so you can have one primary and one backup.
```eval_rst
.. warning::
Superusers have read & write access to everything on your AA installation. Superusers also automatically have all permissions and therefore access to all features of your apps. Therefore we recommend to be very careful to whom you give superuser privileges.
```
:::{warning}
Superusers have read & write access to everything on your AA installation. Superuser also automatically have all permissions and therefore access to all features of your apps. Therefore, we recommend to be very careful to whom you give superuser privileges.
:::
## Setup for large installations
For large alliances and coalitions you may want to have a couple of administrators to be able to distribute and handle the work load. However, having a larger number of superusers may be a security concern.
For large alliances and coalitions, you may want to have a couple of administrators to be able to distribute and handle the work load. However, having a larger number of superusers may be a security concern.
As an alternative to superusers admins you can define staff admins. Staff admins can perform most of the daily admin work, but are not superusers and therefore can be restricted in what they can access.
As an alternative to superusers admins, you can define staff admins. Staff admins can perform most of the daily admin work, but are not superusers and therefore can be restricted in what they can access.
To create a staff admin you need to do two things:
To create a staff admin, you need to do two things:
1. Enable the `is_staff` property for a user
1. Give the user permissions for admin tasks
```eval_rst
.. note::
Note that staff admins have the following limitations:
:::{note}
Note that staff admins have the following limitations:
- Can not promote users to staff
- Can not promote users to superuser
- Can not add/remove permissions for users, groups and states
- Cannot promote users to staff
- Cannot promote users to superuser
- Cannot add/remove permissions for users, groups and states
These limitations exist to prevent staff admins to promote themselves to quasi superusers. Only superusers can perform these actions.
```
These limitations exist to prevent staff admins from promoting themselves to quasi superusers. Only superusers can perform these actions.
:::
### Staff property
Access to the admin site is restricted. Users needs to have the `is_staff` property to be able to open the site at all. The superuser that is created during the installation
Access to the admin site is restricted. Users need to have the `is_staff` property to be able to open the site at all. The superuser created during the installation
process will automatically have access to the admin site.
```eval_rst
.. hint::
Without any permissions a "staff user" can open the admin site, but can neither view nor edit anything except for viewing the list of permissions.
```
:::{hint}
Without any permissions, a "staff user" can open the admin site, but can neither view nor edit anything except for viewing the list of permissions.
:::
### Permissions for common admin tasks
@@ -93,4 +91,4 @@ Here is a list of permissions a staff admin would need to perform some common ad
### Permissions for other apps
The permissions a staff admin needs to perform tasks for other applications depends on how the applications are configured. the default is to have four permissions (change, delete, edit view) for each model of the applications. The view permission is usually required to see the model list on the admin site and the other three permissions are required to perform the respective action to an object of that model. However, app developer can chose to define permissions differently.
The permission a staff admin needs to perform tasks for other applications depends on how the applications are configured. The default is to have four permissions (change, delete, edit view) for each model of the applications. The view permission is usually required to see the model list on the admin site, and the other three permissions are required to perform the respective action to an object of that model. However, an app developer can choose to define permissions differently.

View File

@@ -6,7 +6,7 @@
Before you proceed, please read through this page and/or raise any concerns on the Alliance Auth discord. This data helps us make AA better.
To Opt-Out, modify our pre-loaded token using the Admin dashboard */admin/analytics/analyticstokens/1/change/
To opt out, modify our preloaded token using the Admin dashboard */admin/analytics/analyticstokens/1/change/
Each of the three features Daily Stats, Celery Events and Page Views can be enabled/Disabled independently.
@@ -20,13 +20,13 @@ ANALYTICS_DISABLED = True
## What
Alliance Auth has taken great care to anonymize the data sent. In order to identify _unique_ installs we generate a UUIDv4, a random mathematical construct which does not contain any identifying information [UUID - UUID Objects](https://docs.python.org/3/library/uuid.html#uuid.uuid4)
Alliance Auth has taken great care to anonymize the data sent. To identify _unique_ installs, we generate a UUIDv4, a random mathematical construct which does not contain any identifying information [UUID - UUID Objects](https://docs.python.org/3/library/uuid.html#uuid.uuid4)
Analytics comes pre-loaded with our Google Analytics Token, and the Three Types of task can be opted out independently. Analytics can also be loaded with your _own_ GA token and the analytics module will act any/all tokens loaded.
Analytics comes preloaded with our Google Analytics token, and the three types of tasks can be opted out independently. Analytics can also be loaded with your _own_ GA token, and the analytics module will act any/all tokens loaded.
Our Daily Stats contain the following:
- A phone-in task to identify a servers existence
- A phone-in task to identify a server's existence
- A task to send the Number of User models
- A task to send the Number of Token Models
- A task to send the Number of Installed Apps
@@ -36,7 +36,7 @@ Our Daily Stats contain the following:
Our Celery Events contain the following:
- Unique Identifier (The UUID)
- Celery Namespace of the task eg allianceauth.eveonline
- Celery Namespace of the task e.g., allianceauth.eveonline
- Celery Task
- Task Success or Exception
- A context number for bulk tasks or sometimes a binary True/False
@@ -47,24 +47,24 @@ Our Page Views contain the following:
- Page Path
- Page Title
- The locale of the users browser
- The User-Agent of the users browser
- The User-Agent of the user's browser
- The Alliance Auth Version
## Why
This data allows Alliance Auth development to gather accurate statistics on our install base, as well as how those installs are used.
This data allows Alliance Auth development to gather accurate statistics on our installation base, as well as how those installations are used.
This allows us to better target our development time to commonly used modules and features and test them at the scales in use.
## Where
This data is stored in a Team Google Analytics Dashboard. The Maintainers all have Management permissions here, and if you have contributed to the Alliance Auth project or third party applications feel free to ask in the Alliance Auth discord for access.
This data is stored in a Team Google Analytics Dashboard. The Maintainers all have Management permissions here, and if you have contributed to the Alliance Auth project or third party applications, feel free to ask in the Alliance Auth discord for access.
## Using Analytics in my App
### Analytics Event
```eval_rst
```{eval-rst}
.. automodule:: allianceauth.analytics.tasks
:members: analytics_event
:undoc-members:

View File

@@ -1,10 +1,10 @@
# Dashboard
The dashboard is the main page of the **Alliance Auth** website and the first page every logged in user will see.
The dashboard is the main page of the **Alliance Auth** website, and the first page every logged-in user will see.
The content of the dashboard is specific to the logged in user. It has a sidebar, which will display the list of apps a user currently as access to based on his permissions. And it also shows which character the user has registered and to which group he belongs.
The content of the dashboard is specific to the logged-in user. It has a sidebar, which will display the list of apps a user currently as access to based on his permissions. And it also shows which character the user has registered and to which group he belongs.
For admin users the dashboard shows additional technical information about the AA instance.
For admin users, the dashboard shows additional technical information about the AA instance.
![dashboard](/_static/images/features/core/dashboard/dashboard.png)
@@ -13,7 +13,7 @@ For admin users the dashboard shows additional technical information about the
Here is a list of available settings for the dashboard. They can be configured by adding them to your AA settings file (``local.py``).
Note that all settings are optional and the app will use the documented default settings if they are not used.
```eval_rst
```{eval-rst}
+-----------------------------------------------------+-------------------------------------------------------------------------+-----------+
| Name | Description | Default |
+=====================================================+=========================================================================+===========+

View File

@@ -14,7 +14,7 @@ Here you have several options:
### Internal
Users cannot see, join or request to join this group. This is primarily used for Auth's internally managed groups, though can be useful if you want to prevent users from managing their membership of this group themselves. This option will override the Hidden, Open and Public options when enabled.
Users cannot see, join or request to join this group. This is primarily used for Auth's internally managed groups, though it can be useful if you want to prevent users from managing their membership of this group themselves. This option will override the Hidden, Open and Public options when enabled.
By default, every new group created will be an internal group.
@@ -36,28 +36,27 @@ Group is accessible to any registered user, even when they do not have permissio
The key difference is that the group is completely unmanaged by Auth. **Once a member joins they will not be removed unless they leave manually, you remove them manually, or their account is deliberately set inactive or deleted.**
Most people won't have a use for public groups, though it can be useful if you wish to allow public access to some services. You can grant service permissions on a public group to allow this behavior.
Most people won't have a use for public groups, though it can be useful if you wish to allow public access to some services. You can grant service permissions to a public group to allow this behavior.
### Restricted
When a group is restricted only superuser admins can directly add or remove them to/from users. The purpose of this property is prevent staff admins from assigning themselves to groups that are security sensitive. The "restricted" property can be combined with all the other properties.
When a group is restricted, only superuser admins can directly add or remove them to/from users. The purpose of this property is to prevent staff admins from assigning themselves to groups that are security sensitive. The "restricted" property can be combined with all the other properties.
```eval_rst
```{eval-rst}
.. _ref-reserved-group-names:
```
## Reserved group names
When using Alliance Auth to manage external services like Discord, Auth will automatically duplicate groups on those services. E.g. on Discord Auth will create roles of the same name as groups. However, there may be cases where you want to manage groups on external services by yourself or by another bot. For those cases you can define a list of reserved group names. Auth will ensure that you can not create groups with a reserved name. You will find this list on the admin site under groupmanagement.
When using Alliance Auth to manage external services like Discord, Auth will automatically duplicate groups on those services. E.g., on Discord Auth will create roles of the same name as groups. However, there may be cases where you want to manage groups on external services by yourself or by another bot. For those cases, you can define a list of reserved group names. Auth will ensure that you cannot create groups with a reserved name. You will find this list on the admin site under groupmanagement.
```eval_rst
.. note::
While this feature can help to avoid naming conflicts with groups on external services, the respective service component in Alliance Auth also needs to be build in such a way that it knows how to prevent these conflicts. Currently only the Discord and Teamspeak3 services have this ability.
```
:::{note}
While this feature can help to avoid naming conflicts with groups on external services, the respective service component in Alliance Auth also needs to be built in such a way that it knows how to prevent these conflicts. Currently only the Discord and Teamspeak3 services have this ability.
:::
## Managing groups
In order to access group management, users need to be either a superuser, granted the `auth | user | group_management ( Access to add members to groups within the alliance )` permission or a group leader (discussed later).
To access group management, users need to be either a superuser, granted the `auth | user | group_management ( Access to add members to groups within the alliance )` permission or a group leader (discussed later).
### Group Requests
@@ -65,7 +64,7 @@ When a user joins or leaves a group which is not marked as "Open", their group r
### Group Membership
The group membership tab gives an overview of all of the non-internal groups.
The group membership tab gives an overview of all the non-internal groups.
![Group overview](/_static/images/features/core/groupmanagement/group-membership.png)
@@ -90,7 +89,7 @@ Group leaders have the same abilities as users with the `group_management` permi
- Approve requests for groups they are a leader of.
- View the Group Membership and Group Members of groups they are leaders of.
This allows you to more finely control who has access to manage which groups.
This allows you to more fine control who has access to manage which groups.
### Auto Leave
@@ -101,17 +100,16 @@ By default, in AA both requests and leaves for non-open groups must be approved
GROUPMANAGEMENT_AUTO_LEAVE = True
```
```eval_rst
.. note::
Before you set `GROUPMANAGEMENT_AUTO_LEAVE = True`, make sure there are no pending leave requests, as this option will hide the "Leave Requests" tab.
```
:::{note}
Before you set `GROUPMANAGEMENT_AUTO_LEAVE = True`, make sure there are no pending leave requests, as this option will hide the "Leave Requests" tab.
:::
## Settings
Here is a list of available settings for Group Management. They can be configured by adding them to your AA settings file (``local.py``).
Note that all settings are optional and the app will use the documented default settings if they are not used.
```eval_rst
```{eval-rst}
+---------------------------------------------+---------------------------------------------------------------------------+------------+
| Name | Description | Default |
+=============================================+===========================================================================+============+
@@ -123,18 +121,17 @@ Note that all settings are optional and the app will use the documented default
## Permissions
In order to join a group other than a public group, the permission `groupmanagement.request_groups` (`Can request non-public groups` in the admin panel) must be active on their account, either via a group or directly applied to their User account.
To join a group other than a public group, the permission `groupmanagement.request_groups` (`Can request non-public groups` in the admin panel) must be active on their account, either via a group or directly applied to their User account.
When a user loses this permission, they will be removed from all groups _except_ Public groups.
```eval_rst
.. note::
By default, the ``groupmanagement.request_groups`` permission is applied to the ``Member`` group. In most instances this, and perhaps adding it to the ``Blue`` group, should be all that is ever needed. It is unsupported and NOT advisable to apply this permission to a public group. See #697 for more information.
```
:::{note}
By default, the ``groupmanagement.request_groups`` permission is applied to the ``Member`` group. In most instances this, and perhaps adding it to the ``Blue`` group, should be all that is ever needed. It is unsupported and NOT advisable to apply this permission to a public group. See #697 for more information.
:::
Group Management should be mostly done using group leaders, a series of permissions are included below for thoroughness:
```eval_rst
```{eval-rst}
+--------------------------------+-------------------+------------------------------------------------------------------------------------+
| Permission | Admin Site | Auth Site |
+================================+===================+====================================================================================+

View File

@@ -1,15 +1,14 @@
# Core Features
Managing access to applications and services is one of the core functions of **Alliance Auth**. The related key concepts and functionalities are describes in this section.
Managing access to applications and services is one of the core functions of **Alliance Auth**. The related key concepts and functionalities are described in this section.
```eval_rst
.. toctree::
:maxdepth: 1
:::{toctree}
:maxdepth: 1
dashboard
states
groups
analytics
notifications
admin_site
```
dashboard
states
groups
analytics
notifications
admin_site
:::

View File

@@ -1,14 +1,14 @@
# Notifications
Alliance Auth has a build in notification system. The purpose of the notification system is to provide an easy and quick way to send messages to users of Auth. For example some apps are using it to inform users about results after long running tasks have completed and admins will automatically get notifications about system errors.
Alliance Auth has a build in notification system. The purpose of the notification system is to provide an easy and quick way to send messages to users of Auth. For example, some apps are using it to inform users about results after long-running tasks have been completed, and admins will automatically get notifications about system errors.
The number of unread notifications is shown to the user in the top menu. And the user can click on the notification count to open the notifications app.
The number of unread notifications is shown to the user in the top menu. And the user can click on the notification count to open the Notifications app.
![notification app](/_static/images/features/core/notifications.png)
## Settings
The notifications app can be configured through settings.
The Notifications app can be configured through settings.
- `NOTIFICATIONS_REFRESH_TIME`: The unread count in the top menu is automatically refreshed to keep the user informed about new notifications. This setting allows to set the time between each refresh in seconds. You can also set it to `0` to turn off automatic refreshing. Default: `30`
- `NOTIFICATIONS_MAX_PER_USER`: Maximum number of notifications that are stored per user. Older notifications are replaced by newer once. Default: `50`
- `NOTIFICATIONS_REFRESH_TIME`: The unread count in the top menu is automatically refreshed to keep the user informed about new notifications. This setting allows setting the time between each refresh in seconds. You can also set it to `0` to turn off automatic refreshing. Default: `30`
- `NOTIFICATIONS_MAX_PER_USER`: Maximum number of notifications that are stored per user. Newer replace older notifications. Default: `50`

View File

@@ -1,10 +1,10 @@
# States
States define the basic role of a user based on his affiliation with your organization. A user that has a character in your organization (e.g. alliance) will usually have the `Member` state. And a user, that has no characters in your organization will usually have the `Guest` state.
States define the basic role of a user based on his affiliation with your organization. A user that has a character in your organization (e.g., alliance) will usually have the `Member` state. And a user, that has no characters in your organization will usually have the `Guest` state.
States are assigned and updated automatically. So a user which character just left your organization will automatically loose his `Member` state and get the `Guest` state instead.
States are assigned and updated automatically. So a user which character just left your organization will automatically lose his `Member` state and get the `Guest` state instead.
The main purpose of states like `Member` is to have one place where you can assign all permissions that should apply to all users with that particular state. For example if all your members should have access to the SRP app you would add the permission that gives access to the SRP app to the `Member` state.
The main purpose of states like `Member` is to have one place where you can assign all permissions that should apply to all users with that particular state. For example, if all your members should have access to the SRP app, you would add the permission that gives access to the SRP app to the `Member` state.
## Creating a State
@@ -14,7 +14,7 @@ A number of fields are available and are described below.
### Name
This is the displayed name of a state. Should be self-explanatory.
This is the displayed name of a state. It should be self-explanatory.
### Permissions
@@ -50,9 +50,9 @@ This lets you select which factions the state is available to. Factions can be a
States are mutually exclusive, meaning a user can only be in one at a time.
Membership is determined based on a user's main character. States are tested in order of descending priority - the first one which allows membership to the main character is assigned to the user.
Membership is determined based on a user's main character. States are tested in order of descending priority - the first one, which allows membership to the main character, is assigned to the user.
States are automatically assigned when a user registers to the site, their main character changes, they are activated or deactivated, or states are edited. Note that editing states triggers lots of state checks so it can be a very slow process.
States are automatically assigned when a user registers to the site, their main character changes, they are activated or deactivated, or states are edited. Note that editing states triggers lots of state checks, so it can be a very slow process.
Assigned states are visible in the `Users` section of the `Authentication` admin site.
@@ -60,4 +60,4 @@ Assigned states are visible in the `Users` section of the `Authentication` admin
If no states are available to a user's main character, or their account has been deactivated, they are assigned to a catch-all `Guest` state. This state cannot be deleted nor can its name be changed.
The `Guest` state allows permissions to be granted to users who would otherwise not get any. For example access to public services can be granted by giving the `Guest` state a service access permission.
The `Guest` state allows permissions to be granted to users who would otherwise not get any. For example, access to public services can be granted by giving the `Guest` state a service access permission.

View File

@@ -2,13 +2,12 @@
Learn about the features of **Alliance Auth** and how to install and use them.
```eval_rst
.. toctree::
:maxdepth: 1
:::{toctree}
:maxdepth: 1
overview
core/index
services/index
apps/index
community/index
```
overview
core/index
services/index
apps/index
community/index
:::

View File

@@ -1,17 +1,17 @@
# Overview
**Alliance Auth** (AA) is a web site that helps Eve Online organizations efficiently manage access to applications and external services.
**Alliance Auth** (AA) is a website that helps Eve Online organizations efficiently manage access to applications and external services.
It has the following key features:
- Automatically grants or revokes users 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](/features/core/states) and [groups](/features/core/groups)
- Provides a central web site where users can directly access web apps (e.g. SRP requests) and manage their access to external services and groups.
- Provides a central website where users can directly access web apps (e.g., SRP requests) and manage their access to external services and groups.
- Includes a set of connectors (called ["services"](/features/services/index)) for integrating access management with many popular external services like Discord, Mumble, Teamspeak 3, SMF and others
- Includes a set of web [apps](/features/apps/index) which add many useful functions, e.g.: fleet schedule, timer board, SRP request management, fleet activity tracker
- Can be easily extended with additional services and apps. Many are provided by the [community](/features/community/index).
- It can be easily extended with additional services and apps. Many are provided by the [community](/features/community/index).
- Chinese, English, German and Spanish localization

View File

@@ -33,26 +33,23 @@ CELERYBEAT_SCHEDULE['discord.update_all_usernames'] = {
}
```
```eval_rst
.. note::
You will have to add most the values for these settings, e.g. your Discord server ID (aka guild ID), later in the setup process.
```
:::{note}
You will have to add most of the values for these settings, e.g., your Discord server ID (aka guild ID), later in the setup process.
:::
### Creating a Server
Navigate to the [Discord site](https://discord.com/) and register an account, or log in if you have one already.
On the left side of the screen youll see a circle with a plus sign. This is the button to create a new server. Go ahead and do that, naming it something obvious.
On the left side of the screen, youll see a circle with a plus sign. This is the button to create a new server. Go ahead and do that, naming it something obvious.
Now retrieve the server ID [following this procedure.](https://support.discord.com/hc/en-us/articles/206346498-Where-can-I-find-my-User-Server-Message-ID-)
Update your auth project's settings file, inputting the server ID as `DISCORD_GUILD_ID`
```eval_rst
.. note::
If you already have a Discord server skip the creation step, but be sure to retrieve the server ID
```
:::{note}
If you already have a Discord server, skip the creation step, but be sure to retrieve the server ID
:::
### Registering an Application
Navigate to the [Discord Developers site.](https://discord.com/developers/applications/me) Press the plus sign to create a new application.
@@ -61,7 +58,7 @@ Give it a name and description relating to your auth site. Add a redirect to `ht
Update your auth project's settings file, inputting this redirect address as `DISCORD_CALLBACK_URL`
On the application summary page, press Create a Bot User.
On the application summary page, press "Create a Bot User".
Update your auth project's settings file with these pieces of information from the summary page:
@@ -71,15 +68,15 @@ Update your auth project's settings file with these pieces of information from t
### Preparing Auth
Before continuing it is essential to run migrations and restart Gunicorn and Celery.
Before continuing, it is essential to run migrations and restart Gunicorn and Celery.
### Adding a Bot to the Server
Once created, navigate to the services page of your Alliance Auth install as the superuser account. At the top there is a big green button labelled Link Discord Server. Click it, then from the drop down select the server you created, and then Authorize.
Once created, navigate to the "Services" page of your Alliance Auth install as the superuser account. At the top there is a big green button labeled "Link Discord Server". Click it, then from the drop-down select the server you created, and then Authorize.
This adds a new user to your Discord server with a `BOT` tag, and a new role with the same name as your Discord application. Don't touch either of these. If for some reason the bot loses permissions or is removed from the server, click this button again.
To manage roles, this bot role must be at the top of the hierarchy. Edit your Discord server, roles, and click and drag the role with the same name as your application to the top of the list. This role must stay at the top of the list for the bot to work. Finally, the owner of the bot account must enable 2 Factor Authentication (this is required from Discord for kicking and modifying member roles). If you are unsure what 2FA is or how to set it up, refer to [this support page](https://support.discord.com/hc/en-us/articles/219576828). It is also recommended to force 2FA on your server (this forces any admins or moderators to have 2fa enabled to perform similar functions on discord).
To manage roles, this bot role must be at the top of the hierarchy. Edit your Discord server, roles, and click and drag the role with the same name as your application to the top of the list. This role must stay at the top of the list for the bot to work. Finally, the owner of the bot account must enable 2-Factor Authentication (this is required from Discord for kicking and modifying member roles). If you are unsure what 2FA is or how to set it up, refer to [this support page](https://support.discord.com/hc/en-us/articles/219576828). It is also recommended to force 2FA on your server (this forces any admins or moderators to have 2FA enabled to perform similar functions on discord).
Note that the bot will never appear online as it does not participate in chat channels.
@@ -93,41 +90,39 @@ If you want users to have their Discord nickname changed to their in-game charac
## Managing Roles
Once users link their accounts youll notice Roles get populated on Discord. These are the equivalent to groups on every other service. The default permissions should be enough for members to use text and audio communications. Add more permissions to the roles as desired through the server management window.
Once users link their accounts, youll notice Roles get populated on Discord. These are the equivalent to groups on every other service. The default permissions should be enough for members to use text and audio communications. Add more permissions to the roles as desired through the server management window.
By default Alliance Auth is taking over full control of role assignments on Discord. This means that users on Discord can in general only have roles that correlate to groups on Auth. However, there are two exceptions to this rule.
By default, Alliance Auth is taking over full control of role assignments on Discord. This means that users in Discord can in general only have roles that correlate to groups on Auth. However, there are two exceptions to this rule.
### Internal Discord roles
First, users will keep their so called "Discord managed roles". Those are internal roles created by Discord e.g. for Nitro.
First, users will keep their so-called "Discord managed roles". Those are internal roles created by Discord, e.g., for Nitro.
### Excluding roles from being managed by Auth
Second, it is possible to exclude Discord roles from being managed by Auth at all. This can be useful if you have other bots on your Discord server that are using their own roles and which would otherwise conflict with Auth. This would also allow you to manage a role manually on Discord if you so chose.
To exclude roles from being managed by Auth you only have to add them to the list of reserved group names in Group Management.
To exclude roles from being managed by Auth, you only have to add them to the list of reserved group names in Group Management.
```eval_rst
.. note::
Role names on Discord are case sensitive, while reserved group names on Auth are not. Therefore reserved group names will cover all roles regardless of their case. For example if you have reserved the group name "alpha", then the Discord roles "alpha" and "Alpha" will both be persisted.
```
:::{note}
Role names on Discord are case-sensitive, while reserved group names on Auth are not. Therefore, reserved group names will cover all roles regardless of their case. For example, if you have reserved the group name "alpha", then the Discord roles "alpha" and "Alpha" will both be persisted.
:::
```eval_rst
```{eval-rst}
.. seealso::
For more information see :ref:`ref-reserved-group-names`.
```
## Tasks
The Discord service contains a number of tasks that can be run to manually perform updates to all users.
You can run any of these tasks from the command line. Please make sure that you are in your venv and then you can run this command from the same folder that your manage.py is located:
You can run any of these tasks from the command line. Please make sure that you are in your venv, and then you can run this command from the same folder that your manage.py is located:
```bash
```shell
celery -A myauth call discord.update_all_groups
```
```eval_rst
```{eval-rst}
======================== ====================================================
Name Description
======================== ====================================================
@@ -137,17 +132,15 @@ Name Description
`update_all` Update groups, nicknames, usernames of all users
======================== ====================================================
```
```eval_rst
.. note::
Depending on how many users you have, running these tasks can take considerable time to finish. You can calculate roughly 1 sec per user for all tasks, except update_all, which needs roughly 3 secs per user.
```
:::{note}
Depending on how many users you have, running these tasks can take considerable time to finish. You can calculate roughly 1 sec per user for all tasks, except update_all, which needs roughly 3 secs per user.
:::
## Settings
You can configure your Discord services with the following settings:
```eval_rst
```{eval-rst}
=================================== ============================================================================================= =======
Name Description Default
=================================== ============================================================================================= =======
@@ -163,19 +156,17 @@ Name Description
`DISCORD_TASKS_MAX_RETRIES` max retries of tasks after an error occurred `3`
=================================== ============================================================================================= =======
```
## Permissions
To use this service, users will require some of the following.
```eval_rst
```{eval-rst}
+---------------------------------------+------------------+--------------------------------------------------------------------------+
| Permission | Admin Site | Auth Site |
+=======================================+==================+==========================================================================+
| discord.access_discord | None | Can Access the Discord Service |
+---------------------------------------+------------------+--------------------------------------------------------------------------+
```
## Troubleshooting
### "Unknown Error" on Discord site when activating service
@@ -184,8 +175,8 @@ This indicates your callback URL doesn't match. Ensure the `DISCORD_CALLBACK_URL
### "Add/Remove" Errors in Discord Service
If you are receiving errors in your Notifications after verifying that your settings are all correct try the following:
If you are receiving errors in your Notifications after verifying that your settings are all correct, try the following:
- Ensure that the bot's role in Discord is at the top of the roles list. Each time you add it to your server you will need to do this again.
- Make sure that the bot is not trying to modify the Owner of the discord, as it will fail. A holding discord account added with invite link will mitigate this.
- Ensure that the bot role in Discord is at the top of the roles list. Each time you add it to your server, you will need to do this again.
- Make sure that the bot is not trying to modify the Owner of the discord, as it will fail. A holding discord account added with an invite link will mitigate this.
- Make sure that the bot role on discord has all needed permissions, Admin etc., remembering that these will need to be set every time you add the bot to the Discord server.

View File

@@ -17,7 +17,7 @@ DISCOURSE_SSO_SECRET = ''
## Install Docker
```bash
```shell
wget -qO- https://get.docker.io/ | sh
```
@@ -25,14 +25,14 @@ wget -qO- https://get.docker.io/ | sh
### Download Discourse
```bash
```shell
mkdir /var/discourse
git clone https://github.com/discourse/discourse_docker.git /var/discourse
```
### Configure
```bash
```shell
cd /var/discourse
cp samples/standalone.yml containers/app.yml
nano containers/app.yml
@@ -68,27 +68,27 @@ Or any other port will do, if taken. Remember this number.
### Build and launch
```bash
```shell
nano /etc/default/docker
```
Uncomment this line:
```ini
DOCKER_OPTS="--dns 8.8.8.8 --dns 8.8.4.4"
DOCKER_OPTS="--dns 8.8.8.8 --dns 8.8.4.4"
```
Restart Docker:
```bash
service docker restart
```shell
service docker restart
```
Now build:
```bash
./launcher bootstrap app
./launcher start app
```shell
./launcher bootstrap app
./launcher start app
```
## Web Server Configuration
@@ -124,16 +124,16 @@ server {
From the `/var/discourse` directory,
```bash
```shell
./launcher enter app
rake admin:create
```
Follow prompts, being sure to answer `y` when asked to allow admin privileges.
### Create API key
### Create an API key
Navigate to `discourse.example.com` and log on. Top right press the 3 lines and select `Admin`. Go to API tab and press `Generate Master API Key`.
Navigate to `discourse.example.com` and log on. Top right, press the 3 lines and select `Admin`. Go to API tab and press `Generate Master API Key`.
Add the following values to your auth project's settings file:
@@ -149,15 +149,15 @@ Navigate to `discourse.example.com` and log in. Back to the admin site, scroll d
- `sso_url`: `http://example.com/discourse/sso`
- `sso_secret`: some secure key
Save, now set `DISCOURSE_SSO_SECRET` in your auth project's settings file to the secure key you just put in Discourse.
Now set `DISCOURSE_SSO_SECRET` in your auth project's settings file to the secure key you put in Discourse.
Finally run migrations and restart Gunicorn and Celery.
Finally, run migrations and restart Gunicorn and Celery.
## Permissions
To use this service, users will require some of the following.
```eval_rst
```{eval-rst}
+---------------------------------------+------------------+--------------------------------------------------------------------------+
| Permission | Admin Site | Auth Site |
+=======================================+==================+==========================================================================+

View File

@@ -4,26 +4,24 @@
## Supported Services
```eval_rst
.. toctree::
:maxdepth: 1
:::{toctree}
:maxdepth: 1
discord
discourse
mumble
openfire
phpbb3
smf
teamspeak3
xenforo
```
discord
discourse
mumble
openfire
phpbb3
smf
teamspeak3
xenforo
:::
## Tools
```eval_rst
.. toctree::
:maxdepth: 1
:::{toctree}
:maxdepth: 1
nameformats
permissions
```
nameformats
permissions
:::

View File

@@ -1,60 +1,64 @@
# Mumble
Mumble is a free voice chat server. While not as flashy as TeamSpeak, it has all the functionality and is easier to customize. And is better. I may be slightly biased.
Mumble is a free voice chat server. While not as flashy as TeamSpeak, it has all the functionality and is easier to customize. And it is better. I may be slightly biased.
```eval_rst
.. note::
Note that this guide assumes that you have installed Auth with the official :doc:`/installation/allianceauth` guide under ``/home/allianceserver`` and that it is called ``myauth``. Accordingly it assumes that you have a service user called ``allianceserver`` that is used to run all Auth services under supervisor.
```
```eval_rst
.. warning::
This guide is currently for Ubuntu only.
```
:::{note}
Note that this guide assumes that you have installed Auth with the official :doc:`/installation/allianceauth` guide under ``/home/allianceserver`` and that it is called ``myauth``. Accordingly, it assumes that you have a service user called ``allianceserver`` that is used to run all Auth services under supervisor.
:::
:::{warning}
This guide is currently for Ubuntu only.
:::
## Installations
### Installing Mumble Server
::::{tabs}
:::{group-tab} Ubuntu 2004, 2204
The mumble server package can be retrieved from a repository, which we need to add:
```bash
```shell
sudo apt-add-repository ppa:mumble/release
```
```bash
```shell
sudo apt-get update
```
Now three packages need to be installed:
```bash
```shell
sudo apt-get install python-software-properties mumble-server libqt5sql5-mysql
```
:::
::::
### Installing Mumble Authenticator
Next, we need to download the latest authenticator release from the [authenticator repository](https://gitlab.com/allianceauth/mumble-authenticator).
```bash
```shell
git clone https://gitlab.com/allianceauth/mumble-authenticator /home/allianceserver/mumble-authenticator
```
We will now install the authenticator into your Auth virtual environment. Please make sure to activate it first:
```bash
```shell
source /home/allianceserver/venv/auth/bin/activate
```
Install the python dependencies for the mumble authenticator. Note that this process can take 2-10 minutes to complete.
Install the python dependencies for the mumble authenticator. Note that this process can take 2 to 10 minutes to complete.
```bash
```shell
pip install -r requirements.txt
```
## Configuring Mumble Server
The mumble server needs it's own database. Open an SQL shell with `mysql -u root -p` and execute the SQL commands to create it:
The mumble server needs its own database. Open an SQL shell with `mysql -u root -p` and execute the SQL commands to create it:
```sql
CREATE DATABASE alliance_mumble CHARACTER SET utf8mb4;
@@ -64,9 +68,9 @@ CREATE DATABASE alliance_mumble CHARACTER SET utf8mb4;
GRANT ALL PRIVILEGES ON alliance_mumble . * TO 'allianceserver'@'localhost';
```
Mumble ships with a configuration file that needs customization. By default its located at `/etc/mumble-server.ini`. Open it with your favorite text editor:
Mumble ships with a configuration file that needs customization. By default, its located at `/etc/mumble-server.ini`. Open it with your favorite text editor:
```bash
```shell
sudo nano /etc/mumble-server.ini
```
@@ -90,7 +94,7 @@ Save and close the file.
To get Mumble superuser account credentials, run the following:
```bash
```shell
sudo dpkg-reconfigure mumble-server
```
@@ -98,7 +102,7 @@ Set the password to something youll remember and write it down. This is your
Now restart the server to see the changes reflected.
```bash
```shell
sudo service mumble-server restart
```
@@ -110,7 +114,7 @@ The ICE authenticator lives in the mumble-authenticator repository, cd to the di
Make a copy of the default config:
```bash
```shell
cp authenticator.ini.example authenticator.ini
```
@@ -124,19 +128,19 @@ Edit `authenticator.ini` and change these values:
Test your configuration by starting it:
```bash
```shell
python /home/allianceserver/mumble-authenticator/authenticator.py
```
And finally ensure the allianceserver user has read/write permissions to the mumble authenticator files before proceeding:
And finally, ensure the allianceserver user has read/write permissions to the mumble authenticator files before proceeding:
```bash
```shell
sudo chown -R allianceserver:allianceserver /home/allianceserver/mumble-authenticator
```
The authenticator needs to be running 24/7 to validate users on Mumble. This can be achieved by adding a section to your auth project's supervisor config file like the following example:
```text
```ini
[program:authenticator]
command=/home/allianceserver/venv/auth/bin/python authenticator.py
directory=/home/allianceserver/mumble-authenticator
@@ -149,17 +153,17 @@ startsecs=10
priority=996
```
In addition we'd recommend to add the authenticator to Auth's restart group in your supervisor conf. For that you need to add it to the group line as shown in the following example:
In addition, we'd recommend adding the authenticator to Auth's restart group in your supervisor conf. For that, you need to add it to the group line as shown in the following example:
```text
```ini
[group:myauth]
programs=beat,worker,gunicorn,authenticator
priority=999
```
To enable the changes in your supervisor configuration you need to restart the supervisor process itself. And before we do that we are shutting down the current Auth supervisors gracefully:
To enable the changes in your supervisor configuration, you need to restart the supervisor process itself. And before we do that, we are shutting down the current Auth supervisors gracefully:
```bash
```shell
sudo supervisor stop myauth:
sudo systemctl restart supervisor
```
@@ -187,11 +191,11 @@ MUMBLE_URL = "mumble.example.com"
Finally, run migrations and restart your supervisor to complete the setup:
```bash
```shell
python /home/allianceserver/myauth/manage.py migrate
```
```bash
```shell
supervisorctl restart myauth:
```
@@ -199,7 +203,7 @@ supervisorctl restart myauth:
To use this service, users will require some of the following.
```eval_rst
```{eval-rst}
+---------------------------------------+------------------+--------------------------------------------------------------------------+
| Permission | Admin Site | Auth Site |
+=======================================+==================+==========================================================================+
@@ -221,28 +225,28 @@ The needs and available resources will vary between Alliance Auth installations.
### Bandwidth
<https://wiki.mumble.info/wiki/Murmur.ini#bandwidth>
This is likely the most important setting for scaling a Mumble install, The default maximum Bandwidth is 72000bps Per User. Reducing this value will cause your clients to automatically scale back their bandwidth transmitted, while causing a reduction in voice quality. A value thats still high may cause robotic voices or users with bad connections to drop due entirely due to network load.
This is likely the most important setting for scaling a Mumble installation, The default maximum Bandwidth is 72000bps Per User. Reducing this value will cause your clients to automatically scale back their bandwidth transmitted, while causing a reduction in voice quality. A value that's still high may cause robotic voices or users with bad connections to drop due entirely due to the network load.
Please tune this value to your individual needs, the below scale may provide a rough starting point.
72000 - Superior voice quality - Less than 50 users.
54000 - No noticeable reduction in quality - 50+ Users or many channels with active audio.
36000 - Mild reduction in quality - 100+ Users
30000 - Noticeable reduction in quality but not function - 250+ Users
`72000` - Superior voice quality - Less than 50 users.
`54000` - No noticeable reduction in quality - 50+ Users or many channels with active audio.
`36000` - Mild reduction in quality - 100+ Users
`30000` - Noticeable reduction in quality but not function - 250+ Users
### Forcing Opus
<https://wiki.mumble.info/wiki/Murmur.ini#opusthreshold>
A Mumble server by default, will fall back to the older CELT codec as soon as a single user connects with an old client. This will significantly reduce your audio quality and likely place higher load on your server. We _highly_ reccommend setting this to Zero, to force OPUS to be used at all times. Be aware any users with Mumble clients prior to 1.2.4 (From 2013...) Will not hear any audio.
A Mumble server, by default, will fall back to the older CELT codec as soon as a single user connects with an old client. This will significantly reduce your audio quality and likely place a higher load on your server. We _highly_ reccommend setting this to Zero, to force OPUS to be used at all times. Be aware any users with Mumble clients prior to 1.2.4 (From 2013...) Will not hear any audio.
`opusthreshold=0`
### AutoBan and Rate Limiting
<https://wiki.mumble.info/wiki/Murmur.ini#autobanAttempts.2C_autobanTimeframe_and_autobanTime>
The AutoBan feature has some sensible settings by default, You may wish to tune these if your users keep locking themselves out by opening two clients by mistake, or if you are receiving unwanted attention
The AutoBan feature has some sensible settings by default. You may wish to tune these if your users keep locking themselves out by opening two clients by mistake, or if you are receiving unwanted attention
<https://wiki.mumble.info/wiki/Murmur.ini#messagelimit_and_messageburst>
This too, is set to a sensible configuration by default. Take note on upgrading older installs, as this may actually be set too restrictively and will rate-limit your admins accidentally, take note of the configuration in <https://github.com/mumble-voip/mumble/blob/master/scripts/murmur.ini#L156>
This, too, is set to a sensible configuration by default. Take note on upgrading older installs, as this may actually be set too restrictively and will rate-limit your admins accidentally, take note of the configuration in <https://github.com/mumble-voip/mumble/blob/master/scripts/murmur.ini#L156>
### "Suggest" Options
@@ -260,34 +264,34 @@ If Push to Talk is to your tastes, configure the suggestion as follows
### Setting a server password
With the default configuration your mumble server is public. Meaning that everyone who has the address can at least connect to it and might also be able join all channels that don't have any permissions set (Depending on your ACL configured for the root channel). If you want only registered member being able to join your mumble, you have to set a server password. To do so open your mumble server configuration which is by default located at `/etc/mumble-server.ini`.
With the default configuration, your mumble server is public. Meaning that everyone who has the address can at least connect to it and might also be able to join all channels that don't have any permissions set (Depending on your ACL configured for the root channel). If you want only registered member being able to join your mumble, you have to set a server password. To do so open your mumble server configuration which is by default located at `/etc/mumble-server.ini`.
```bash
```shell
sudo nano /etc/mumble-server.ini
```
Now search for `serverpassword=` and set your password here. If there is no such line, simply add it.
Now search for `serverpassword=` and set your password here. If there is no such line, add it.
```text
```ini
serverpassword=YourSuperSecretServerPassword
```
Save the file and restart your mumble server afterwards.
Save the file and restart your mumble server afterward.
```bash
```shell
sudo service mumble-server restart
```
From now on, only registered member can join your mumble server. Now if you still want to allow guests to join you have 2 options.
From now on, only registered member can join your mumble server. Now if you still want to allow guests to join, you have two options.
- Allow the "Guest" state to activate the Mumble service in your Auth instance
- Use [Mumble temporary links](https://github.com/pvyParts/allianceauth-mumble-temp)
### Enabling Avatars in Overlay (V1.0.0+)
Ensure you have an up to date Mumble-Authenticator, this feature was added in V1.0.0
Ensure you have an up-to-date Mumble-Authenticator. This feature was added in V1.0.0
Edit `authenticator.ini` and change (or add for older installs) This code block.
Edit `authenticator.ini` and change (or add for older installations) This code block.
```ini
;If enabled, textures are automatically set as player's EvE avatar for use on overlay.

View File

@@ -4,9 +4,9 @@ This app allows you to customize how usernames for services are created.
Each service's username or nickname, depending on which the service supports, can be customized through the use of the Name Formatter config provided the service supports custom formats. This config can be found in the admin panel under **Services -> Name format config**
Currently the following services support custom name formats:
Currently, the following services support custom name formats:
```eval_rst
```{eval-rst}
+-------------+-----------+-------------------------------------+
| Service | Used with | Default Formatter |
+=============+===========+=====================================+
@@ -29,15 +29,13 @@ Currently the following services support custom name formats:
| Xenforo | Username | ``{character_name}`` |
+-------------+-----------+-------------------------------------+
```
```eval_rst
.. note::
It's important to note here, before we get into what you can do with a name formatter, that before the generated name is passed off to the service to create an account it will be sanitized to remove characters (the letters and numbers etc.) that the service cannot support. This means that, despite what you configured, the service may display something different. It is up to you to test your formatter and understand how your format may be disrupted by a certain services sanitization function.
```
:::{note}
It's important to note here, before we get into what you can do with a name formatter, that before the generated name is passed off to the service to create an account it will be sanitized to remove characters (the letters and numbers etc.) that the service cannot support. This means that, despite what you configured, the service may display something different. It is up to you to test your formatter and understand how your format may be disrupted by a certain services sanitization function.
:::
## Available format data
The following fields are available from a users account and main character:
The following fields are available for a user account and main character:
- `username` - Alliance Auth username
- `character_id`
@@ -55,11 +53,11 @@ The following fields are available from a users account and main character:
The name formatter uses the advanced string formatting specified by [PEP-3101](https://www.python.org/dev/peps/pep-3101/). Anything supported by this specification is supported in a name formatter.
A more digestible documentation of string formatting in Python is available on the [PyFormat](https://pyformat.info/) website.
More digestible documentation of string formatting in Python is available on the [PyFormat](https://pyformat.info/) website.
Some examples of strings you could use:
```eval_rst
```{eval-rst}
+------------------------------------------+---------------------------+
| Formatter | Result |
+==========================================+===========================+
@@ -71,12 +69,10 @@ Some examples of strings you could use:
+------------------------------------------+---------------------------+
```
```eval_rst
.. important::
For most services, name formats only take effect when a user creates an account. This means if you create or update a name formatter it wont retroactively alter the format of users names. There are some exceptions to this where the service updates nicknames on a periodic basis. Check the service's documentation to see which of these apply.
```
:::{important}
For most services, name formats only take effect when a user creates an account. This means if you create or update a name formatter, it won't retroactively alter the format of users' names. There are some exceptions to this where the service updates nicknames on a periodic basis. Check the service's documentation to see which of these apply.
:::
```eval_rst
.. important::
You must only create one formatter per service per state. E.g. don't create two formatters for Mumble for the Member state. In this case one of the formatters will be used and it may not be the formatter you are expecting.
```
:::{important}
You must only create one formatter per service per state. E.g., don't create two formatters for Mumble for the Member state. In this case, one of the formatters will be used, and it may not be the formatter you are expecting:
:::

View File

@@ -23,59 +23,82 @@ BROADCAST_SERVICE_NAME = "broadcast"
Openfire require a Java 8 runtime environment.
Ubuntu 1804, 2004, 2204:
::::{tabs}
:::{group-tab} Ubuntu 2004, 2204
```bash
```shell
sudo apt-get install openjdk-11-jre
```
Centos 7:
:::
:::{group-tab} CentOS 7
```bash
```shell
sudo yum install java-11-openjdk java-11-openjdk-devel
```
Centos Stream 8, Stream 9:
```bash
:::
:::{group-tab} CentOS Stream 8
```shell
sudo dnf install java-11-openjdk java-11-openjdk-devel
```
:::
:::{group-tab} CentOS Stream 9
```shell
sudo dnf install java-11-openjdk java-11-openjdk-devel
```
:::
::::
## Setup
### Download Installer
Openfire is not available through repositories so we need to get a package from the developer.
Openfire is not available through repositories, so we need to get a package from the developer.
On your PC, navigate to the [Ignite Realtime downloads section](https://www.igniterealtime.org/downloads/index.jsp), and under Openfire select Linux, click on the Ubuntu: Debian package (second from bottom of list, ends with .deb) or CentOS: RPM Package (no JRE bundled, as we have installed it on the host)
On your PC, navigate to the [Ignite Realtime downloads section](https://www.igniterealtime.org/downloads/index.jsp), and under Openfire select Linux, click on the Ubuntu: Debian package (second from bottom of the list, ends with .deb) or CentOS: RPM Package (no JRE bundled, as we have installed it on the host)
Retrieve the file location by copying the URL from the “click here” link, depending on your browser you may have a Copy Link or similar option in your right click menu.
Retrieve the file location by copying the URL from the “click here” link. Depending on your browser, you may have a Copy Link or similar option in your right click menu.
In the console, ensure youre in your users home directory:
```bash
```shell
cd ~
```
Download and install the package, replacing the URL with the latest you got from the Openfire download page earlier
Ubuntu 1804, 2004, 2204:
::::{tabs}
:::{group-tab} Ubuntu 2004, 2204
```bash
wget https://www.igniterealtime.org/downloadServlet?filename=openfire/openfire_4.7.2_all.deb
:::
:::{group-tab} CentOS 7
wget <https://www.igniterealtime.org/downloadServlet?filename=openfire/openfire_4.7.2_all.deb>
dpkg -i openfire_4.7.2_all.deb
```
Centos 7, Stream 8, Stream 9:
```bash
wget https://www.igniterealtime.org/downloadServlet?filename=openfire/openfire-4.7.2-1.noarch.rpm
:::
:::{group-tab} CentOS Stream 8
wget <https://www.igniterealtime.org/downloadServlet?filename=openfire/openfire-4.7.2-1.noarch.rpm>
yum install -y openfire-4.7.2-1.noarch.rpm
```
:::
:::{group-tab} CentOS Stream 9
wget <https://www.igniterealtime.org/downloadServlet?filename=openfire/openfire-4.7.2-1.noarch.rpm>
yum install -y openfire-4.7.2-1.noarch.rpm
:::
::::
### Create Database
Performance is best when working from a SQL database. If you installed MySQL or MariaDB alongside your auth project, go ahead and create a database for Openfire:
Performance is best when working from an SQL database. If you installed MySQL or MariaDB alongside your auth project, go ahead and create a database for Openfire:
```bash
```shell
mysql -u root -p
```
```sql
create database alliance_jabber;
grant all privileges on alliance_jabber . * to 'allianceserver'@'localhost';
exit;
@@ -83,7 +106,7 @@ exit;
### Web Configuration
The remainder of the setup occurs through Openfires web interface. Navigate to http://example.com:9090, or if youre behind CloudFlare, go straight to your servers IP:9090.
The remainder of the setup occurs through Openfires web interface. Navigate to <http://example.com:9090>, or if youre behind CloudFlare, go straight to your servers IP:9090.
Select your language. I sure hope its English if youre reading this guide.
@@ -105,11 +128,11 @@ Create an administrator account. The actual name is irrelevant, just dont los
Finally, log in to the console with your admin account.
Edit your auth project's settings file and enter the values you just set:
Edit your auth project's settings file and enter the values you set:
- `JABBER_URL` is the pubic address of your jabber server
- `JABBER_URL` is the public address of your jabber server
- `JABBER_PORT` is the port for clients to connect to (usually 5223)
- `JABBER_SERVER` is the name of the jabber server. If you didn't alter it during install it'll usually be your domain (eg `example.com`)
- `JABBER_SERVER` is the name of the jabber server. If you didn't alter it during the installation, it'll usually be your domain (eg `example.com`)
- `OPENFIRE_ADDRESS` is the web address of Openfire's web interface. Use http:// with port 9090 or https:// with port 9091 if you configure SSL in Openfire
### REST API Setup
@@ -165,7 +188,7 @@ ACL is achieved by assigning groups to each of the three tiers: `Owners`, `Admin
To use this service, users will require some of the following.
```eval_rst
```{eval-rst}
+---------------------------------------+------------------+--------------------------------------------------------------------------+
| Permission | Admin Site | Auth Site |
+=======================================+==================+==========================================================================+

View File

@@ -4,30 +4,28 @@ In the past, access to services was dictated by a list of settings in `settings.
## Permissions based access
Instead of granting access to services by the previous rigid structure, access to services is now granted by the built in Django permissions system. This means that service access can be more granular, allowing only certain states, certain groups, for instance Corp CEOs, or even individual user access to each enabled service.
Instead of granting access to services by the previous rigid structure, access to services is now granted by the built-in Django permissions system. This means that service access can be more granular, allowing only certain states, certain groups, for instance, Corp CEOs, or even individual user access to each enabled service.
```eval_rst
.. important::
If you grant access to an individual user, they will have access to that service regardless of whether or not they are a member.
```
:::{important}
If you grant access to an individual user, they will have access to that service regardless of whether they are a member.
:::
Each service has an access permission defined, named like `Can access the <service name> service`.
To mimick the old behaviour of enabling services for all members, you would select the `Member` group from the admin panel, add the required service permission to the group and save. Likewise for Blues, select the `Blue` group and add the required permission.
To mimic the old behaviour of enabling services for all members, you would select the `Member` group from the admin panel, add the required service permission to the group and save. Likewise for Blues, select the `Blue` group and add the required permission.
A user can be granted the same permission from multiple sources. e.g. they may have it granted by several groups and directly granted on their account as well. Auth will not remove their account until all instances of the permission for that service have been revoked.
A user can be granted the same permission from multiple sources. e.g., they may have it granted by several groups and directly granted on their account as well. Auth will not remove their account until all instances of the permission for that service have been revoked.
## Removing access
```eval_rst
.. danger::
Access removal is processed immediately after removing a permission from a user or group. If you remove access from a large group, such as Member, it will immediately remove all users from that service.
```
:::{danger}
Access removal is processed immediately after removing a permission from a user or group. If you remove access from a large group, such as Member, it will immediately remove all users from that service.
:::
When you remove a service permission from a user, a signal is triggered which will activate an immediate permission check. For users this will trigger an access check for all services. For groups, due to the potential extra load, only the services whose permissions have changed will be verified, and only the users in that group.
When you remove a service permission from a user, a signal is triggered which will activate an immediate permission check. For users, this will trigger an access check for all services. For groups, due to the potential extra load, only the services whose permissions have changed will be verified, and only the users in that group.
If a user no longer has permission to access the service when this permissions check is triggered, that service will be immediately disabled for them.
If a user no longer has permission to access the service when this permission check is triggered, that service will be immediately disabled for them.
### Disabling user accounts
When you unset a user as active in the admin panel, all of that users service accounts will be immediately disabled or removed. This is due to the built in behaviour of the Django permissions system, which will return False for all permissions if a users account is disabled, regardless of their actual permissions state.
When you unset a user as active in the admin panel, all of that user's service accounts will be immediately disabled or removed. This is due to the built-in behaviour of the Django permissions system, which will return False for all permissions if a user's account is disabled, regardless of their actual permissions state.

View File

@@ -34,7 +34,7 @@ DATABASES['phpbb3'] = {
Create a database to install phpBB3 in.
```bash
```shell
mysql -u root -p
create database alliance_forum;
grant all privileges on alliance_forum . * to 'allianceserver'@'localhost';
@@ -51,28 +51,28 @@ In the console, navigate to your users home directory: `cd ~`
Now download using wget, replacing the URL with the URL for the package you just retrieved
```bash
```shell
wget https://download.phpbb.com/pub/release/3.3/3.3.8/phpBB-3.3.8.zip
```
This needs to be unpackaged. Unzip it, replacing the file name with that of the file you just downloaded
```bash
```shell
unzip phpBB-3.3.8.zip
```
Now we need to move this to our web directory. Usually `/var/www/forums`.
```bash
```shell
mv phpBB3 /var/www/forums
```
The web server needs read/write permission to this folder
The web server needs read/write permissions to this folder
Apache: `chown -R www-data:www-data /var/www/forums`
Nginx: `chown -R nginx:nginx /var/www/forums`
```eval_rst
```{eval-rst}
.. tip::
Nginx: Some distributions use the ``www-data:www-data`` user:group instead of ``nginx:nginx``. If you run into problems with permissions try it instead.
..
@@ -80,7 +80,7 @@ Nginx: `chown -R nginx:nginx /var/www/forums`
### Configuring Web Server
You will need to configure you web server to serve PHPBB3 before proceeding with installation.
You will need to configure your web server to serve PHPBB3 before proceeding with installation.
A minimal Apache config file might look like:
@@ -128,7 +128,7 @@ Enter your forum's web address as the `PHPBB3_URL` setting in your auth project'
### Web Install
Navigate to your forums web address where you will be presented with an installer.
Navigate to your forum web address where you will be presented with an installer.
Click on the `Install` tab.
@@ -155,9 +155,9 @@ phpBB will then write its own config file.
### Open the Forums
Before users can see the forums, we need to remove the install directory
Before users can see the forums, we need to remove the installation directory
```bash
```shell
rm -rf /var/www/forums/install
```
@@ -171,7 +171,7 @@ You can allow members to overwrite the portrait with a custom image if desired.
Users generated via Alliance Auth do not have a default theme set. You will need to set this on the phpbb_users table in SQL
```bash
```shell
mysql -u root -p
use alliance_forum;
alter table phpbb_users change user_style user_style int not null default 1
@@ -187,7 +187,7 @@ Once settings have been configured, run migrations and restart Gunicorn and Cele
To use this service, users will require some of the following.
```eval_rst
```{eval-rst}
+---------------------------------------+------------------+--------------------------------------------------------------------------+
| Permission | Admin Site | Auth Site |
+=======================================+==================+==========================================================================+

View File

@@ -11,6 +11,7 @@ SMF requires PHP installed in your web server. Apache has `mod_php`, NGINX requi
## Prepare Your Settings
In your auth project's settings file, do the following:
- Add `'allianceauth.services.modules.smf',` to your `INSTALLED_APPS` list
- Append the following to the bottom of the settings file:
@@ -31,44 +32,44 @@ DATABASES['smf'] = {
### Download SMF
Using your browser, you can download the latest version of SMF to your desktop computer. All SMF downloads can be found at SMF Downloads. The latest recommended version will always be available at http://www.simplemachines.org/download/index.php/latest/install/. Retrieve the file location from the hyperlinked box icon for the zip full install, depending on your browser you may have a Copy Link or similar option in your right click menu.
Using your browser, you can download the latest version of SMF to your desktop computer. All SMF downloads can be found at SMF Downloads. The latest recommended version will always be available at <http://www.simplemachines.org/download/index.php/latest/install/>. Retrieve the file location from the hyperlinked box icon for the zip full install, depending on your browser, you may have a Copy Link or similar option in your right click menu.
Download using wget, replacing the URL with the URL for the package you just retrieved
```bash
```shell
wget https://download.simplemachines.org/index.php?thanks;filename=smf_2-1-2_install.tar.gz
```
This needs to be unpackaged. Unzip it, replacing the file name with that of the file you just downloaded
```bash
```shell
unzip smf_2-1-2_install.zip
```
Now we need to move this to our web directory. Usually `/var/www/forums`.
```bash
mv smf /var/www/forums
````
The web server needs read/write permission to this folder
```shell
mv smf /var/www/forums
```
The web server needs read/write permissions to this folder
Apache: `chown -R www-data:www-data /var/www/forums`
Nginx: `chown -R nginx:nginx /var/www/forums`
```eval_rst
.. tip::
Nginx: Some distributions use the ``www-data:www-data`` user:group instead of ``nginx:nginx``. If you run into problems with permissions try it instead.
..
```
:::{tip}
Nginx: Some distributions use the ``www-data:www-data`` user:group instead of ``nginx:nginx``. If you run into problems with permissions, try it instead.
:::
### Database Preparation
SMF needs a database. Create one:
```shell
mysql -u root -p
```
```mysql
```sql
create database alliance_smf;
grant all privileges on alliance_smf . * to 'allianceserver'@'localhost';
exit;
@@ -81,7 +82,8 @@ Enter the database information into the `DATABASES['smf']` section of your auth
Your web server needs to be configured to serve SMF.
A minimal Apache config might look like:
```apache
```ini
<VirtualHost *:80>
ServerName forums.example.com
DocumentRoot /var/www/forums
@@ -92,7 +94,8 @@ A minimal Apache config might look like:
````
A minimal Nginx config might look like:
```nginx
```ini
server {
listen 80;
server_name forums.example.com;
@@ -108,18 +111,20 @@ server {
include fastcgi_params;
}
}
````
```
Enter the web address to your forums into the `SMF_URL` setting in your auth project's settings file.
### Web Install
Navigate to your forums address where you will be presented with an installer.
Navigate to your forum address where you will be presented with an installer.
Click on the `Install` tab.
All the requirements should be met. Press `Start Install`.
Under Database Settings, set the following:
- Database Type is `MySQL`
- Database Server Hostname is `127.0.0.1`
- Database Server Port is left blank
@@ -139,7 +144,7 @@ Once settings are entered, apply migrations and restart Gunicorn and Celery.
To use this service, users will require some of the following.
```eval_rst
```{eval-rst}
+---------------------------------------+------------------+--------------------------------------------------------------------------+
| Permission | Admin Site | Auth Site |
+=======================================+==================+==========================================================================+

View File

@@ -34,18 +34,18 @@ CELERYBEAT_SCHEDULE['run_ts3_group_update'] = {
### Download Installer
To install we need a copy of the server. You can find the latest version from the [TeamSpeak site](https://www.teamspeak.com/downloads#)). Be sure to get a link to the Linux version.
To install, we need a copy of the server. You can find the latest version on the [TeamSpeak website](https://www.teamspeak.com/downloads#). Be sure to get a link to the Linux version.
Download the server, replacing the link with the link you got earlier.
``` bash
```shell
cd ~
wget https://files.teamspeak-services.com/releases/server/3.13.7/teamspeak3-server_linux_amd64-3.13.7.tar.bz2
```
Now we need to extract the file.
```bash
```shell
tar -xf teamspeak3-server_linux_amd64-3.13.7.tar.bz2
```
@@ -53,7 +53,7 @@ tar -xf teamspeak3-server_linux_amd64-3.13.7.tar.bz2
TeamSpeak needs its own user.
```bash
```shell
adduser --disabled-login teamspeak
```
@@ -61,7 +61,7 @@ adduser --disabled-login teamspeak
Now we move the server binary somewhere more accessible and change its ownership to the new user.
```bash
```shell
mv teamspeak3-server_linux_amd64 /usr/local/teamspeak
chown -R teamspeak:teamspeak /usr/local/teamspeak
```
@@ -70,14 +70,14 @@ chown -R teamspeak:teamspeak /usr/local/teamspeak
Now we generate a startup script so TeamSpeak comes up with the server.
```bash
```shell
ln -s /usr/local/teamspeak/ts3server_startscript.sh /etc/init.d/teamspeak
update-rc.d teamspeak defaults
```
Finally we start the server.
Finally, we start the server.
```bash
```shell
service teamspeak start
```
@@ -85,7 +85,7 @@ service teamspeak start
Set your Teamspeak Serveradmin password to a random string
```bash
```shell
./ts3server_minimal_runscript.sh inifile=ts3server.ini serveradmin_password=pleasegeneratearandomstring
```
@@ -109,7 +109,7 @@ Click the URL provided to automatically connect to our server. It will prompt yo
### Groups
Now we need to make groups. AllianceAuth handles groups in teamspeak differently: instead of creating groups it creates an association between groups in TeamSpeak and groups in AllianceAuth. Go ahead and make the groups you want to associate with auth groups, keeping in mind multiple TeamSpeak groups can be associated with a single auth group.
Now we need to make groups. AllianceAuth handles groups in teamspeak differently: instead of creating groups, it creates an association between groups in TeamSpeak and groups in AllianceAuth. Go ahead and make the groups you want to associate with auth groups, keeping in mind multiple TeamSpeak groups can be associated with a single auth group.
Navigate back to the AllianceAuth admin interface (example.com/admin) and under `Teamspeak3`, select `Auth / TS Groups`.
@@ -127,7 +127,7 @@ To enable advanced permissions, on your client go to the `Tools` menu, `Applicat
### TS group models not populating on admin site
The method which populates these runs every 30 minutes. To populate manually you start the process from the admin site or from the Django shell.
The method which populates these runs every 30 minutes. To populate manually, you start the process from the admin site or from the Django shell.
#### Admin Site
@@ -139,7 +139,7 @@ Then, in the top-right corner click, click on `Update TS3 Groups` to start the p
Start a django shell with:
```bash
```shell
python manage.py shell
```
@@ -156,7 +156,7 @@ Ensure that command does not return an error.
This usually occurs because auth is trying to remove a user from the `Guest` group (group ID 8). The guest group is only assigned to a user when they have no other groups, unless you have changed the default teamspeak server config.
Teamspeak servers v3.0.13 and up are especially susceptible to this. Ensure the Channel Admin Group is not set to `Guest (8)`. Check by right clicking on the server name, `Edit virtual server`, and in the middle of the panel select the `Misc` tab.
Teamspeak servers v3.0.13 and up are especially susceptible to this. Ensure the Channel Admin Group is not set to `Guest (8)`. Check by right-clicking on the server name, `Edit virtual server`, and in the middle of the panel select the `Misc` tab.
### `TypeError: string indices must be integers, not str`
@@ -174,13 +174,13 @@ The serverquery account login specified in local.py is incorrect. Please verify
### `2568 insufficient client permissions`
This usually occurs if you've created a separate serverquery user to use with auth. It has not been assigned sufficient permissions to complete all the tasks required of it. The full list of required permissions is not known, so assign liberally.
This usually occurs if you've created a separate serverquery user to use with auth. It has not been assigned sufficient permissions to complete all the tasks required of it. The full list of required permissions is not known, so assign them liberally.
## Permissions
To use and configure this service, users will require some of the following.
```eval_rst
```{eval-rst}
+---------------------------------------+------------------+--------------------------------------------------------------------------+
| Permission | Admin Site | Auth Site |
+=======================================+==================+==========================================================================+

View File

@@ -2,7 +2,7 @@
## Overview
[XenForo](https://xenforo.com/) is a popular paid forum. This guide will assume that you already have XenForo installed with a valid license (please keep in mind that XenForo is not free nor open-source, therefore you need to purchase a license first). If you come across any problems related with the installation of XenForo please contact their support service.
[XenForo](https://xenforo.com/) is a popular, paid forum. This guide will assume that you already have XenForo installed with a valid license (please keep in mind that XenForo is not free nor open-source, therefore, you need to purchase a license first). If you come across any problems related with the installation of XenForo please contact their support service.
## Prepare Your Settings
@@ -20,12 +20,12 @@ XENFORO_APIKEY = 'yourapikey'
## XenAPI
By default XenForo does not support any kind of API, however there is a third-party package called [XenAPI](https://github.com/Contex/XenAPI) which provides a simple REST interface by which we can access XenForo's functions in order to create and edit users.
By default, XenForo does not support any kind of API, however, there is a third-party package called [XenAPI](https://github.com/Contex/XenAPI) which provides a simple REST interface by which we can access XenForo's functions to create and edit users.
The installation of XenAPI is pretty straight forward. The only thing you need to do is to download the `api.php` from the official repository and upload it in the root folder of your XenForo installation. The final result should look like this:
*forumswebsite.com/***api.php**
Now that XenAPI is installed the only thing left to do is to provide a key.
Now that XenAPI is installed, the only thing left to do is to provide a key.
```php
$restAPI = new RestAPI('REPLACE_THIS_WITH_AN_API_KEY');
@@ -37,7 +37,7 @@ The settings you created earlier now need to be filled out.
`XENFORO_ENDPOINT` is the address to the API you added. No leading `http://`, but be sure to include the `/api.php` at the end.
`XENFORO_DEFAULT_GROUP` is the ID of the group in XenForo auth users will be added to. Unfortunately XenAPI **cannot create new groups**, therefore you have to create a group manually and then get its ID.
`XENFORO_DEFAULT_GROUP` is the ID of the group in XenForo auth users will be added to. Unfortunately, XenAPI **cannot create new groups**, therefore, you have to create a group manually and then get its ID.
`XENFORO_API_KEY` is the API key value you set earlier.
@@ -47,7 +47,7 @@ Once these are entered, run migrations and restart Gunicorn and Celery.
To use this service, users will require some of the following.
```eval_rst
```{eval-rst}
+---------------------------------------+------------------+--------------------------------------------------------------------------+
| Permission | Admin Site | Auth Site |
+=======================================+==================+==========================================================================+

View File

@@ -7,16 +7,15 @@ Welcome to the official documentation for **Alliance Auth**!
**Alliance Auth** is a web site that helps Eve Online organizations efficiently manage access to applications and external services.
```eval_rst
.. toctree::
:maxdepth: 2
:caption: Contents
:::{toctree}
:maxdepth: 2
:caption: Contents
installation/index
features/index
maintenance/index
support/index
customizing/index
development/index
contributing/index
```
installation/index
features/index
maintenance/index
support/index
customizing/index
development/index
contributing/index
:::

View File

@@ -2,10 +2,9 @@
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 :doc:`/features/index` for details.
```
:::{note}
There are additional installation steps for activating services and apps that come with **Alliance Auth**. Please see the page for the respective service or apps in chapter :doc:`/features/index` for details.
:::
## Dependencies
@@ -15,7 +14,6 @@ Alliance Auth can be installed on any in-support *nix operating system.
Our install documentation targets the following operating systems.
- Ubuntu 18.04
- Ubuntu 20.04
- Ubuntu 22.04
- Centos 7
@@ -26,236 +24,217 @@ To install on your favorite flavour of Linux, identify and install equivalent pa
### OS Maintenance
It is recommended to ensure your OS is fully up to date before proceeding. We may also add Package Repositories here, used later in the documentation.
It is recommended to ensure your OS is fully up-to-date before proceeding. We may also add Package Repositories here, used later in the documentation.
Ubuntu 1804, 2004, 2204:
::::{tabs}
:::{group-tab} Ubuntu 2004, 2204
```bash
```shell
sudo apt-get update
```
```bash
sudo apt-get upgrade
```
```bash
sudo do-dist-upgrade
```
CentOS 7:
:::
:::{group-tab} CentOS 7
```bash
```shell
yum install epel-release
```
```bash
sudo yum upgrade
```
CentOS Stream 8:
:::
:::{group-tab} CentOS Stream 8
```bash
```shell
sudo dnf config-manager --set-enabled powertools
```
```bash
sudo dnf install epel-release epel-next-release
```
```bash
sudo yum upgrade
```
CentOS Stream 9:
:::
:::{group-tab} CentOS Stream 9
```bash
```shell
sudo dnf config-manager --set-enabled crb
```
```bash
dnf install epel-release epel-next-release
```
```bash
sudo dnf install epel-release epel-next-release
sudo yum upgrade
```
:::
::::
### Python
Install Python 3.10 and related tools on your system.
Install Python 3.11 and related tools on your system.
Ubuntu 1804, 2004:
::::{tabs}
```bash
:::{group-tab} Ubuntu 2004, 2204
```shell
sudo add-apt-repository ppa:deadsnakes/ppa
```
```bash
sudo apt-get update
sudo apt-get install python3.11 python3.11-dev python3.11-venv
```
```bash
sudo apt-get install python3.10 python3.10-dev python3.10-venv
```
Ubuntu 2204:
```eval_rst
.. note::
Ubuntu 2204 ships with Python 3.10 already, but some important tools are missing in the default installation.
```
```bash
sudo apt-get install python3.10-dev python3.10-venv
```
CentOS 7:
:::
:::{group-tab} CentOS 7
We need to build Python from source
Centos Stream 8/9:
```eval_rst
.. note::
A Python 3.9 Package is available for Stream 8 and 9. You _may_ use this instead of building your own package. But our documentation will assume Python3.10 and you may need to substitute as necessary
sudo dnf install python39 python39-devel
```
```bash
cd ~
```
```bash
sudo yum install gcc openssl-devel bzip2-devel libffi-devel wget
```
```bash
wget https://www.python.org/ftp/python/3.10.5/Python-3.10.5.tgz
```
```bash
tar xvf Python-3.10.5.tgz
```
```bash
cd Python-3.10.5/
```
```bash
wget https://www.python.org/ftp/python/3.11.5/Python-3.11.5.tgz
tar xvf Python-3.11.5.tgz
cd Python-3.11.5/
./configure --enable-optimizations --enable-shared
```
```bash
sudo make altinstall
```
### Database
It's recommended to use a database service instead of SQLite. Many options are available, but this guide will use MariaDB.
```eval_rst
.. note::
Ubuntu distributions prior to 20.04 come with an older version of Maria DB, which is not compatible with **Alliance Auth**. You need Maria DB 10.3 or higher!
For 20.04 we still recommend to install Maria DB from the link below in order to get the newest stable version.
For 22.04 we recommend installing from the default Ubuntu distro, since it comes with the newest stable version.
```
Ubuntu 1804, 2004:
```eval_rst
.. warning::
Please follow these steps to update MariaDB
https://mariadb.org/download/?t=repo-config&d=20.04+%22focal%22&v=10.6&r_m=osuosl
```
Ubuntu 1804, 2004, 2204
:::
:::{group-tab} CentOS Stream 8
We need to build Python from source
```bash
cd ~
sudo yum install gcc openssl-devel bzip2-devel libffi-devel wget
wget https://www.python.org/ftp/python/3.11.5/Python-3.11.5.tgz
tar xvf Python-3.11.5.tgz
cd Python-3.11.5/
./configure --enable-optimizations --enable-shared
sudo make altinstall
```
:::
:::{group-tab} CentOS Stream 9
We need to build Python from source
```bash
cd ~
sudo yum install gcc openssl-devel bzip2-devel libffi-devel wget
wget https://www.python.org/ftp/python/3.11.5/Python-3.11.5.tgz
tar xvf Python-3.11.5.tgz
cd Python-3.11.5/
./configure --enable-optimizations --enable-shared
sudo make altinstall
```
:::
::::
### Database
It's recommended to use a database service instead of SQLite. Many options are available, but this guide will use MariaDB 10.11
::::{tabs}
:::{group-tab} Ubuntu 2004, 2204
Follow the instructions at <https://mariadb.org/download/?t=repo-config&d=20.04+%22focal%22&v=10.11&r_m=osuosl> to add the MariaDB repository to your host.
```shell
sudo apt-get install mariadb-server mariadb-client libmysqlclient-dev
```
CentOS 7:
:::
:::{group-tab} CentOS 7
Follow the instructions at <https://mariadb.org/download/?t=repo-config&d=CentOS+7&v=10.11&r_m=osuosl> to add the MariaDB repository to your host.
```eval_rst
.. warning::
Please follow these steps to update MariaDB
https://mariadb.org/download/?t=repo-config&d=CentOS+7+%28x86_64%29&v=10.6&r_m=osuosl
```
```bash
```shell
sudo yum install MariaDB-server MariaDB-client MariaDB-devel MariaDB-shared
```
CentOS Stream 8/9:
:::
:::{group-tab} CentOS Stream 8
Follow the instructions at <https://mariadb.org/download/?t=repo-config&d=CentOS+Stream&v=10.11&r_m=osuosl> to add the MariaDB repository to your host.
```eval_rst
.. note::
We recommend using the built in AppStream, as they are maintained by CentOS. Currently an AppStream is not available for 10.6
```
```bash
sudo dnf module enable mariadb:10.5
```
```bash
```shell
sudo dnf install mariadb mariadb-server mariadb-devel
```
```bash
sudo systemctl enable mariadb
:::
:::{group-tab} CentOS Stream 9
Follow the instructions at <https://mariadb.org/download/?t=repo-config&d=CentOS+Stream&v=10.11&r_m=osuosl> to add the MariaDB repository to your host.
```shell
sudo dnf install mariadb mariadb-server mariadb-devel
```
```bash
sudo systemctl start mariadb
```
:::
::::
```eval_rst
.. important::
If you don't plan on running the database on the same server as auth you still need to install the ``libmysqlclient-dev`` package on Ubuntu or ``mariadb-devel`` package on CentOS.
```
:::::{important}
::::{tabs}
:::{group-tab} Ubuntu 2004, 2204
If you don't plan on running the database on the same server as auth you still need to install the `libmysqlclient-dev` package
:::
:::{group-tab} CentOS 7
If you don't plan on running the database on the same server as auth you still need to install the `mariadb-devel` package
:::
:::{group-tab} CentOS Stream 8
If you don't plan on running the database on the same server as auth you still need to install the `mariadb-devel` package
:::
:::{group-tab} CentOS Stream 9
If you don't plan on running the database on the same server as auth you still need to install the `mariadb-devel` package
:::
::::
:::::
### Redis and Other Tools
A few extra utilities are also required for installation of packages.
Ubuntu 1804, 2004, 2204:
::::{tabs}
```bash
:::{group-tab} Ubuntu 2004, 2204
```shell
sudo apt-get install unzip git redis-server curl libssl-dev libbz2-dev libffi-dev build-essential pkg-config
```
CentOS 7:
:::
:::{group-tab} CentOS 7
```bash
```shell
sudo yum install gcc gcc-c++ unzip git redis curl bzip2-devel openssl-devel libffi-devel wget pkg-config
```
```bash
```shell
sudo systemctl enable redis.service
```
```bash
sudo systemctl start redis.service
```
CentOS Stream 8, Stream 9:
:::
:::{group-tab} CentOS Stream 8
```bash
```shell
sudo dnf install gcc gcc-c++ unzip git redis curl bzip2-devel openssl-devel libffi-devel wget
```
```bash
```shell
sudo systemctl enable redis.service
```
```bash
sudo systemctl start redis.service
```
:::
:::{group-tab} CentOS Stream 9
```shell
sudo dnf install gcc gcc-c++ unzip git redis curl bzip2-devel openssl-devel libffi-devel wget
```
```shell
sudo systemctl enable redis.service
sudo systemctl start redis.service
```
:::
::::
## Database Setup
Alliance Auth needs a MySQL user account and database. Open an SQL shell with
```bash
```shell
sudo mysql -u root
```
@@ -271,22 +250,24 @@ Once your database is set up, you can leave the SQL shell with `exit`.
Add timezone tables to your mysql installation:
```bash
```shell
mysql_tzinfo_to_sql /usr/share/zoneinfo | sudo mysql -u root mysql
```
```eval_rst
.. note::
You may see errors when you add the timezone tables. To make sure that they were correctly added run the following commands and check for the ``time_zone`` tables::
:::{note}
You may see errors when you add the timezone tables. To make sure that they were correctly added run the following commands and check for the ``time_zone`` tables
mysql -u root -p
use mysql;
show tables;
```shell
mysql -u root -p
use mysql;
show tables;
```
:::
Close the SQL shell and secure your database server with this command:
```bash
```shell
mysql_secure_installation
```
@@ -295,133 +276,136 @@ mysql_secure_installation
### User Account
For security and permissions, its highly recommended you create a separate user to install auth under. Do not log in as this account.
::::{tabs}
Ubuntu 1804, 2004, 2204:
:::{group-tab} Ubuntu 2004, 2204
```bash
```shell
sudo adduser --disabled-login allianceserver
```
CentOS 7, Stream 8, Stream 9:
:::
:::{group-tab} CentOS 7
```bash
sudo useradd -s /bin/bash allianceserver
```
```bash
```shell
sudo passwd -l allianceserver
```
:::
:::{group-tab} CentOS Stream 8
```shell
sudo passwd -l allianceserver
```
:::
:::{group-tab} CentOS Stream 9
```shell
sudo passwd -l allianceserver
```
:::
::::
### Prepare Directories
```bash
```shell
sudo mkdir -p /var/www/myauth/static
```
```bash
```shell
sudo chown -R allianceserver:allianceserver /var/www/myauth/static/
```
```eval_rst
.. note::
When installing and performing maintenance on Alliance Auth, using the allianceserver user will greatly simplify permission management::
:::{warning}
When installing and performing maintenance on Alliance Auth, virtual environments and python packages, _sudo_ means _superuser_ _do_, this will not use your venv or your allianceserver user and will routinely break your permission structure.
sudo su allianceserver
Only use sudo for _system_ management or if you are unsure, when explicitly instructed to do so.
```shell
sudo su allianceserver
```
:::
### Virtual Environment
Switch to the allianceserver user.
```bash
```shell
sudo su allianceserver
```
And switch to it's home directory:
And switch to its home directory:
```bash
cd
```
```eval_rst
.. note::
In general using the allianceserver user will greatly simplify permission management, when installing and performing maintenance on Alliance Auth.
```shell
cd ~
```
Create a Python virtual environment and put it somewhere convenient (e.g. `/home/allianceserver/venv/auth/`)
```eval_rst
.. note::
Your python3.x command/version may vary depending on your installed python version.
:::{note}
Your python3.x command/version may vary depending on your installed python version.
:::
```shell
python3.11 -m venv /home/allianceserver/venv/auth/
```
```bash
python3.10 -m venv /home/allianceserver/venv/auth/
```
```eval_rst
.. tip::
A virtual environment provides support for creating a lightweight "copy" of Python with their own site directories. Each virtual environment has its own Python binary (allowing creation of environments with various Python versions) and can have its own independent set of installed Python packages in its site directories. You can read more about virtual environments on the Python_ docs.
.. _Python: https://docs.python.org/3/library/venv.html
```
:::{tip}
A virtual environment provides support for creating a lightweight "copy" of Python with their own site directories. Each virtual environment has its own Python binary (allowing creation of environments with various Python versions) and can have its own independent set of installed Python packages in its site directories. You can read more about virtual environments on the Python_ docs. <https://docs.python.org/3/library/venv.html>
:::
Activate the virtual environment with (Note the `/bin/activate` on the end of the path):
```bash
```shell
source /home/allianceserver/venv/auth/bin/activate
```
```eval_rst
.. hint::
Each time you come to do maintenance on your Alliance Auth installation, you should activate your virtual environment first. When finished, deactivate it with the ``deactivate`` command.
```
:::{hint}
Each time you come to do maintenance on your Alliance Auth installation, you should activate your virtual environment first. When finished, deactivate it with the ``deactivate`` command.
:::
### Eve Online SSO
You need to have a dedicated Eve SSO app for Alliance auth. Please go to [EVE Developer](https://developers.eveonline.com/applications) to create one.
For **scopes** your SSO app needs to have at least `publicData`. Additional scopes depends on which Alliance Auth apps you will be using. For convenience, we recommend adding all available ESO scopes to your SSO app. Note that Alliance Auth will always ask the users to approve specific scopes before they are used.
For **scopes** your SSO app needs to have at least `publicData`. Additional scopes depend on which Alliance Auth apps you will be using. For convenience, we recommend adding all available ESO scopes to your SSO app. Note that Alliance Auth will always ask the users to approve specific scopes before they are used.
As **callback URL** you want to define the URL of your Alliance Auth site plus the route: `/sso/callback`. Example for a valid callback URL: `https://auth.example.com/sso/callback`
### Alliance Auth Project
```eval_rst
.. warning::
Before installing any Python packages please double-check that you have activated in the virtual environment. This is usually indicated by your command line in the terminal starting with: `(auth)`.
```
:::{warning}
Before installing any Python packages, please double-check that you have activated in the virtual environment. This is usually indicated by your command line in the terminal starting with: `(auth)`.
:::
#### Install Python packages
Update & install basic tools before installing further Python packages:
```bash
```shell
pip install -U pip setuptools wheel
```
You can install **Alliance Auth** with the following command. This will install AA and all its Python dependencies.
You can install **Alliance Auth** with the following command. This will install AA, AA's Python dependencies, superlance for memory monitoring and gunicorn as a wsgi server
```bash
pip install allianceauth
```shell
pip install allianceauth superlance gunicorn
```
You should also install Gunicorn now unless you want to use another WSGI server (see [Gunicorn](#gunicorn) for details):
```bash
pip install gunicorn
```
#### Create Alliance Auth project
#### Create the Alliance Auth project
Now you need to create the Django project that will run **Alliance Auth**. Ensure you are in the allianceserver home directory by issuing:
```bash
```shell
cd /home/allianceserver
```
The following command bootstraps a Django project which will run your **Alliance Auth** instance. You can rename it from `myauth` to anything you'd like. Note that this name is shown by default as the site name but that can be changed later.
```bash
```shell
allianceauth start myauth
```
@@ -429,7 +413,7 @@ allianceauth start myauth
Your settings file needs configuring:
```bash
```shell
nano myauth/myauth/settings/local.py
```
@@ -443,42 +427,44 @@ nano myauth/myauth/settings/local.py
#### Install database & static files
Django needs to setup the database before it can start.
Django needs to set up the database before it can start.
```bash
```shell
python /home/allianceserver/myauth/manage.py migrate
```
Now we need to round up all the static files required to render templates. Make a directory to serve them from and populate it.
```bash
```shell
python /home/allianceserver/myauth/manage.py collectstatic --noinput
```
Check to ensure your settings are valid.
```bash
```shell
python /home/allianceserver/myauth/manage.py check
```
```eval_rst
.. hint::
If you are using root, ensure the allianceserver user has read/write permissions to this directory before proceeding::
:::{hint}
If you are using root, ensure the allianceserver user has read/write permissions to this directory before proceeding::
chown -R allianceserver:allianceserver /home/allianceserver/myauth
```shell
chown -R allianceserver:allianceserver /home/allianceserver/myauth
```
:::
#### Setup superuser
Before using your auth site, it is essential to create a superuser account. This account will have all permissions in Alliance Auth. It's OK to use this as your personal auth account.
```bash
```shell
python /home/allianceserver/myauth/manage.py createsuperuser
```
Once your install is complete, the superuser account is accessed by logging in via the admin site at `https://example.com/admin`.
Once your installation is complete, the superuser account is accessed by logging in via the admin site at `https://example.com/admin`.
If you intend to use this account as your personal auth account you need to add a main character. Navigate to the normal user dashboard (at `https://example.com`) after logging in via the admin site and select `Change Main`. Once a main character has been added, it is possible to use SSO to login to this account.
If you intend to use this account as your personal auth account, you need to add a main character. Navigate to the normal user dashboard (at `https://example.com`) after logging in via the admin site and select `Change Main`. Once a main character has been added, it is possible to use SSO to log in to this account.
## Services
@@ -486,7 +472,9 @@ Alliance Auth needs some additional services to run, which we will set up and co
### Gunicorn
To run the **Alliance Auth** website a [WSGI Server](https://www.fullstackpython.com/wsgi-servers.html) is required. For this [Gunicorn](http://gunicorn.org/) is highly recommended for its ease of configuring. It can be manually run from within your `myauth` base directory with `gunicorn --bind 0.0.0.0 myauth.wsgi` or automatically run using Supervisor.
To run the **Alliance Auth** website, a [WSGI Server](https://www.fullstackpython.com/wsgi-servers.html) is required. For this [Gunicorn](http://gunicorn.org/) is highly recommended for its ease of configuring. It can be manually run from within your `myauth` base directory with `gunicorn --bind 0.0.0.0 myauth.wsgi` or automatically run using Supervisor.
If you don't see any errors, this means that Gunicorn is running fine. You can stop it with `Ctrl+C` now.
The default configuration is good enough for most installations. Additional information is available in the [gunicorn](gunicorn.md) doc.
@@ -494,120 +482,165 @@ The default configuration is good enough for most installations. Additional info
[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.
```eval_rst
.. note::
:::{note}
You will need to exit the allianceserver user back to a user with sudo capabilities to install supervisor::
exit
```shell
exit
```
Ubuntu 1804, 2004, 2204:
:::
```bash
::::{tabs}
:::{group-tab} Ubuntu 2004, 2204
```shell
sudo apt-get install supervisor
```
CentOS 7:
:::
:::{group-tab} CentOS 7
```bash
```shell
sudo dnf install supervisor
```
```bash
```shell
sudo systemctl enable supervisord.service
```
```bash
```shell
sudo systemctl start supervisord.service
```
CentOS Stream 8, Stream 9:
:::
:::{group-tab} CentOS Stream 8
```bash
```shell
sudo dnf install supervisor
```
```bash
```shell
sudo systemctl enable supervisord.service
```
```bash
```shell
sudo systemctl start supervisord.service
```
:::
:::{group-tab} CentOS Stream 9
```shell
sudo dnf install supervisor
```
```shell
sudo systemctl enable supervisord.service
```
```shell
sudo systemctl start supervisord.service
```
:::
::::
Once installed, it needs a configuration file to know which processes to watch. Your Alliance Auth project comes with a ready-to-use template which will ensure the Celery workers, Celery task scheduler and Gunicorn are all running.
::::{tabs}
Ubuntu 1804, 2004:
:::{group-tab} Ubuntu 2004, 2204
```bash
```shell
ln -s /home/allianceserver/myauth/supervisor.conf /etc/supervisor/conf.d/myauth.conf
```
CentOS:
:::
:::{group-tab} CentOS 7
```bash
```shell
sudo ln -s /home/allianceserver/myauth/supervisor.conf /etc/supervisord.d/myauth.ini
```
:::
:::{group-tab} CentOS Stream 8
```shell
sudo ln -s /home/allianceserver/myauth/supervisor.conf /etc/supervisord.d/myauth.ini
```
:::
:::{group-tab} CentOS Stream 9
```shell
sudo ln -s /home/allianceserver/myauth/supervisor.conf /etc/supervisord.d/myauth.ini
```
:::
::::
Activate it with `sudo supervisorctl reload`.
You can check the status of the processes with `sudo supervisorctl status`. Logs from these processes are available in `/home/allianceserver/myauth/log` named by process.
```eval_rst
.. note::
Any time the code or your settings change you'll need to restart Gunicorn and Celery. ::
:::{note}
Any time the code or your settings change, you'll need to restart Gunicorn and Celery. ::
sudo supervisorctl restart myauth:
```shell
sudo supervisorctl restart myauth:
```
:::
## Web server
Once installed, decide on whether you're going to use [NGINX](nginx.md) or [Apache](apache.md) and follow the respective guide.
Note that Alliance Auth is designed to run with web servers on HTTPS. While running on HTTP is technically possible, it is not recommended for production use, and some functions (e.g. Email confirmation links) will not work properly.
Note that Alliance Auth is designed to run with web servers on HTTPS. While running on HTTP is technically possible, it is not recommended for production use, and some functions (e.g., Email confirmation links) will not work properly.
## Updating
Periodically [new releases](https://gitlab.com/allianceauth/allianceauth/tags) are issued with bug fixes and new features. Be sure to read the [release notes](https://gitlab.com/allianceauth/allianceauth/-/releases) which will highlight changes.
To update your install, swap to your allianceserver user
To update your installation, swap to your allianceserver user
```bash
```shell
sudo su allianceserver
```
Activate your virtual environment
```bash
```shell
source /home/allianceserver/venv/auth/bin/activate
```
and update with:
```bash
```shell
pip install -U allianceauth
```
Some releases come with changes to the base settings. Update your project's settings with:
```bash
```shell
allianceauth update /home/allianceserver/myauth
```
Some releases come with new or changed models. Update your database to reflect this with:
```bash
```shell
python /home/allianceserver/myauth/manage.py migrate
```
Finally, some releases come with new or changed static files. Run the following command to update your static files folder:
Finally, some releases come with new or changed static files. Run the following command to update your static files' folder:
```bash
```shell
python /home/allianceserver/myauth/manage.py collectstatic --noinput
```
Always restart AA, Celery and Gunicorn after updating:
```bash
```shell
supervisorctl restart myauth:
```

View File

@@ -2,74 +2,121 @@
## Overview
Alliance Auth gets served using a Web Server Gateway Interface (WSGI) script. This script passes web requests to Alliance Auth which generates the content to be displayed and returns it. This means very little has to be configured in Apache to host Alliance Auth.
Alliance Auth gets served using a Web Server Gateway Interface (WSGI) script. This script passes web requests to Alliance Auth, which generates the content to be displayed and returns it. This means very little has to be configured in Apache to host Alliance Auth.
If you're using a small VPS to host services with very limited memory, consider using [NGINX](nginx.md).
## Installation
Ubuntu 1804, 2004:
```bash
::::{tabs}
:::{group-tab} Ubuntu 2004, 2204
```shell
apt-get install apache2
```
CentOS 7:
```bash
:::
:::{group-tab} CentOS 7
```shell
yum install httpd
```
Centos Stream 8, Stream 9
```bash
:::
:::{group-tab} CentOS Stream 8
```shell
dnf install httpd
```
CentOS 7, Stream 8, Stream 9
```bash
:::
:::{group-tab} CentOS Stream 9
```shell
systemctl enable httpd
```
```bash
systemctl start httpd
```
:::
::::
CentOS 7, Stream 8, Stream 9
## Configuration
### Permissions
Apache needs to be able to read the folder containing your auth project's static files.
Ubuntu 1804, 2004:
```
::::{tabs}
:::{group-tab} Ubuntu 2004, 2204
```shell
chown -R www-data:www-data /var/www/myauth/static
```
CentOS 7, Stream 8, Stream 9
```
:::
:::{group-tab} CentOS 7
```shell
chown -R apache:apache /var/www/myauth/static
```
:::
:::{group-tab} CentOS Stream 8
```shell
chown -R apache:apache /var/www/myauth/static
```
:::
:::{group-tab} CentOS Stream 9
```shell
chown -R apache:apache /var/www/myauth/static
```
:::
::::
### Further Configuration
Apache serves sites through defined virtual hosts. These are located in `/etc/apache2/sites-available/` on Ubuntu and `/etc/httpd/conf.d/httpd.conf` on CentOS.
A virtual host for auth need only proxy requests to your WSGI server (Gunicorn if you followed the install guide) and serve static files. Examples can be found below. Create your config in its own file e.g. `myauth.conf`
### Ubuntu
A virtual host for auth needs only proxy requests to your WSGI server (Gunicorn if you followed the installation guide) and serve static files. Examples can be found below. Create your config in its own file e.g. `myauth.conf`
::::{tabs}
:::{group-tab} Ubuntu 2004, 2204
To proxy and modify headers a few mods need to be enabled.
```bash
```shell
a2enmod proxy
a2enmod proxy_http
a2enmod headers
```
Create a new config file for auth e.g. `/etc/apache2/sites-available/myauth.conf` and fill out the virtual host configuration. To enable your config use `a2ensite myauth.conf` and then reload apache with `service apache2 reload`.
:::
:::{group-tab} CentOS 7
Place your virtual host configuration in the appropriate section within `/etc/httpd/conf.d/httpd.conf` and restart the httpd service with `systemctl restart httpd`.
:::
:::{group-tab} CentOS Stream 8
Place your virtual host configuration in the appropriate section within `/etc/httpd/conf.d/httpd.conf` and restart the httpd service with `systemctl restart httpd`.
:::
:::{group-tab} CentOS Stream 9
Place your virtual host configuration in the appropriate section within `/etc/httpd/conf.d/httpd.conf` and restart the httpd service with `systemctl restart httpd`.
:::
::::
```eval_rst
.. warning::
In some scenarios, the Apache default page is still enabled. To disable it use::
a2dissite 000-default.conf
:::{warning}
In some scenarios, the Apache default page is still enabled. To disable it use
```shell
a2dissite 000-default.conf
```
:::
### CentOS
Place your virtual host configuration in the appropriate section within `/etc/httpd/conf.d/httpd.conf` and restart the httpd service with `systemctl restart httpd`.
## Sample Config File
```
```ini
<VirtualHost *:80>
ServerName auth.example.com
@@ -105,9 +152,9 @@ Place your virtual host configuration in the appropriate section within `/etc/ht
It's 2018 - there's no reason to run a site without SSL. The EFF provides free, renewable SSL certificates with an automated installer. Visit their [website](https://certbot.eff.org/) for information.
After acquiring SSL the config file needs to be adjusted. Add the following lines inside the `<VirtualHost>` block:
After acquiring SSL, the config file needs to be adjusted. Add the following lines inside the `<VirtualHost>` block:
```
```ini
RequestHeader set X-FORWARDED-PROTOCOL https
RequestHeader set X-FORWARDED-SSL On
```
@@ -116,7 +163,7 @@ After acquiring SSL the config file needs to be adjusted. Add the following line
#### Apache2 vs. Django
For some versions of Apache2 you might have to tell the Django framework explicitly
For some versions of Apache2, you might have to tell the Django framework explicitly
to use SSL, since the automatic detection doesn't work. SSL in general will work,
but internally created URLs by Django might still be prefixed with just `http://`
instead of `https://`, so it can't hurt to add these lines to

View File

@@ -2,27 +2,25 @@
[Gunicorn](http://gunicorn.org) is a Python WSGI HTTP Server for UNIX. The Gunicorn server is light on server resources, and fairly speedy.
If you find Apache's `mod_wsgi` to be a headache or want to use NGINX (or some other webserver), then Gunicorn could be for you. There are a number of other WSGI server options out there and this documentation should be enough for you to piece together how to get them working with your environment.
If you find Apache's `mod_wsgi` to be a headache or want to use NGINX (or some other webserver), then Gunicorn could be for you. There are a number of other WSGI server options out there, and this documentation should be enough for you to piece together how to get them working with your environment.
Check out the full [Gunicorn docs](http://docs.gunicorn.org/en/latest/index.html).
```eval_rst
.. note::
The page contains additional steps on how to setup and configure Gunicorn that are not required for users who decide to stick with the default Gunicorn configuration as described in the main installation guide for AA.
```
:::{note}
The page contains additional steps on how to set up and configure Gunicorn that are not required for users who decide to stick with the default Gunicorn configuration as described in the main installation guide for AA.
:::
## Setting up Gunicorn
```eval_rst
.. note::
If you're using a virtual environment, activate it now::
sudo su allianceserver
source /home/allianceserver/venv/auth/bin/activate
```
:::{note}
If you're using a virtual environment, activate it now::
sudo su allianceserver
source /home/allianceserver/venv/auth/bin/activate
:::
Install Gunicorn using pip
```bash
```shell
pip install gunicorn
```
@@ -32,13 +30,13 @@ Once you validate its running, you can kill the process with Ctrl+C and continue
## Running Gunicorn with Supervisor
If you are following this guide, we already use [Supervisor](allianceauth.md#supervisor) to keep all of Alliance Auth components running. You don't _have to_ but we will be using it to start and run Gunicorn for consistency.
If you are following this guide, we already use [Supervisor](allianceauth.md#supervisor) to keep all of Alliance Auth's components running. You don't _have to_, but we will be using it to start and run Gunicorn for consistency.
### Sample Supervisor config
You'll want to edit `/etc/supervisor/conf.d/myauth.conf` (or whatever you want to call the config file)
```text
```ini
[program:gunicorn]
user = allianceserver
directory=/home/allianceserver/myauth/
@@ -49,10 +47,11 @@ autostart=true
autorestart=true
stopsignal=INT
```
- `[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=/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.
- `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
@@ -60,7 +59,7 @@ See the [Commonly Used Arguments](http://docs.gunicorn.org/en/latest/run.html#co
##### 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.
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.
For UNIX sockets add `--bind=unix:/run/allianceauth.sock` (or to a path you wish to use). Remember that your web server will need to be able to access this socket file.
@@ -70,17 +69,18 @@ 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 `(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.
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=5` to the command.
##### Running with a virtual environment
Following this guide, you are running with a virtual environment. Therefore you'll need to add the path to the `command=` config line.
Following this guide, you are running with a virtual environment. Therefore, you'll need to add the path to the `command=` config line.
e.g. `command=/path/to/venv/bin/gunicorn myauth.wsgi`
The example config is using the myauth venv from the main installation guide:
```ini
command=/home/allianceserver/venv/auth/bin/gunicorn myauth.wsgi
```
@@ -91,12 +91,12 @@ Once you have your configuration all sorted, you will need to reload your superv
## Configuring your webserver
Any web server capable of proxy passing should be able to sit in front of Gunicorn. Consult their documentation armed with your `--bind=` address and you should be able to find how to do it relatively easy.
Any web server capable of proxy passing should be able to sit in front of Gunicorn. Consult their documentation armed with your `--bind=` address, and you should be able to find how to do it relatively easily.
## Restarting Gunicorn
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:
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:
```bash
```shell
supervisorctl restart myauth:gunicorn
```

View File

@@ -2,16 +2,15 @@
This chapter contains the main installation guides for **Alliance Auth**.
In addition to main guide for installation Alliance Auth you also find guides for configuring web servers (Apache, NGINX) and the recommended WSGI server (Gunicorn).
In addition to the main guide for installation Alliance Auth, you also find guides for configuring web servers (Apache, NGINX) and the recommended WSGI server (Gunicorn).
```eval_rst
.. toctree::
:maxdepth: 1
:::{toctree}
:maxdepth: 1
allianceauth
nginx
apache
gunicorn
upgrade_python
switch_to_non_root
```
allianceauth
nginx
apache
gunicorn
upgrade_python
switch_to_non_root
:::

View File

@@ -2,9 +2,9 @@
## Overview
Nginx (engine x) is a HTTP server known for its high performance, stability, simple configuration, and low resource consumption. Unlike traditional servers (i.e. Apache), Nginx doesn't rely on threads to serve requests, rather using an asynchronous event driven approach which permits predictable resource usage and performance under load.
Nginx (engine x) is an HTTP server known for its high performance, stability, simple configuration, and low-resource consumption. Unlike traditional servers (i.e., Apache), Nginx doesn't rely on threads to serve requests, rather using an asynchronous event-driven approach which permits predictable resource usage and performance under load.
If you're trying to cram Alliance Auth into a very small VPS of say, 1-2GB or less, then Nginx will be considerably friendlier to your resources compared to Apache.
If you're trying to cram Alliance Auth into a very small VPS of say, 1 to 2GB or less, then Nginx will be considerably friendlier to your resources compared to Apache.
You can read more about NGINX on the [NGINX wiki](https://www.nginx.com/resources/wiki/).
@@ -12,9 +12,9 @@ You can read more about NGINX on the [NGINX wiki](https://www.nginx.com/resource
If you're converting from Apache, here are some things to consider.
Nginx is lightweight for a reason. It doesn't try to do everything internally and instead concentrates on just being a good HTTP server. This means that, unlike Apache, it won't automatically run PHP scripts via mod_php and doesn't have an internal WSGI server like mod_wsgi. That doesn't mean that it can't, just that it relies on external processes to run these instead. This might be good or bad depending on your outlook. It's good because it allows you to segment your applications, restarting Alliance Auth wont impact your PHP applications. On the other hand it means more config and more management of services. For some people it will be worth it, for others losing the centralised nature of Apache may not be worth it.
Nginx is lightweight for a reason. It doesn't try to do everything internally and instead concentrates on just being a good HTTP server. This means that, unlike Apache, it won't automatically run PHP scripts via mod_php and doesn't have an internal WSGI server like mod_wsgi. That doesn't mean that it can't, just that it relies on external processes to run these instead. This might be good or bad depending on your outlook. It's good because it allows you to segment your applications, restarting Alliance Auth won't impact your PHP applications. On the other hand, it means more config and more management of services. For some people it will be worth it, for others losing the centralised nature of Apache may not be worth it.
```eval_rst
```{eval-rst}
+-----------+----------------------------------------+
| Apache | Nginx Replacement |
+===========+========================================+
@@ -22,47 +22,61 @@ Nginx is lightweight for a reason. It doesn't try to do everything internally an
+-----------+----------------------------------------+
| mod_wsgi | Gunicorn or other external WSGI server |
+-----------+----------------------------------------+
```
Your .htaccess files won't work. Nginx has a separate way of managing access to folders via the server config. Everything you can do with htaccess files you can do with Nginx config. [Read more on the Nginx wiki](https://www.nginx.com/resources/wiki/start/topics/examples/likeapache-htaccess/)
## Setting up Nginx
Install Nginx via your preferred package manager or other method. If you need help just search, there are plenty of guides on installing Nginx out there.
Install Nginx via your preferred package manager or other method. If you need help, search, there are plenty of guides on installing Nginx out there.
Nginx needs to be able to read the folder containing your auth project's static files. `chown -R nginx:nginx /var/www/myauth/static`.
```eval_rst
.. tip::
Some specific distros may use ``www-data:www-data`` instead of ``nginx:nginx``, causing static files (images, stylesheets etc) not to appear. You can confirm what user Nginx will run under by checking either its base config file ``/etc/nginx/nginx.conf`` for the "user" setting, or once Nginx has started ``ps aux | grep nginx``.
Adjust your chown commands to the correct user if needed.
..
```
:::{tip}
Some specific distros may use ``www-data:www-data`` instead of ``nginx:nginx``, causing static files (images, stylesheets etc.) not to appear. You can confirm what user Nginx will run under by checking either its base config file ``/etc/nginx/nginx.conf`` for the "user" setting, or once Nginx has started ``ps aux | grep nginx``.
Adjust your chown commands to the correct user if needed.
:::
You will need to have [Gunicorn](gunicorn.md) or some other WSGI server setup for hosting Alliance Auth.
## Install
Ubuntu 1804, 2004, 2204:
```bash
::::{tabs}
:::{group-tab} Ubuntu 2004, 2204
```shell
sudo apt-get install nginx
```
CentOS 7
```bash
:::
:::{group-tab} CentOS 7
```shell
sudo yum install nginx
```
CentOS Stream 8, Stream 9:
```bash
:::
:::{group-tab} CentOS Stream 8
```shell
sudo dnf install nginx
```
:::
:::{group-tab} CentOS Stream 9
```shell
sudo dnf install nginx
```
:::
::::
Create a config file in `/etc/nginx/sites-available` (`/etc/nginx/conf.d` on CentOS) and call it `alliance-auth.conf` or whatever your preferred name is.
Create a symbolic link to enable the site (not needed on CentOS):
```bash
```shell
ln -s /etc/nginx/sites-available/alliance-auth.conf /etc/nginx/sites-enabled/
```
@@ -70,8 +84,7 @@ ln -s /etc/nginx/sites-available/alliance-auth.conf /etc/nginx/sites-enabled/
Copy this basic config into your config file. Make whatever changes you feel are necessary.
```
```ini
server {
listen 80;
listen [::]:80;
@@ -107,7 +120,7 @@ With [Let's Encrypt](https://letsencrypt.org/) offering free SSL certificates, t
Your config will need a few additions once you've got your certificate.
```
```ini
listen 443 ssl http2; # Replace listen 80; with this
listen [::]:443 ssl http2; # Replace listen [::]:80; with this
@@ -123,7 +136,7 @@ Your config will need a few additions once you've got your certificate.
If you want to redirect all your non-SSL visitors to your secure site, below your main configs `server` block, add the following:
```
```ini
server {
listen 80;
listen [::]:80;

View File

@@ -1,12 +1,12 @@
# Switch to non-root
If you followed the official installation guide for Alliance Auth (AA) pre AA 3.x you usually ended up with a "root installation". A root installation means that you have installed AA with the root user and now need to log in as root every time to perform maintenance for AA, e.g. updating existing apps.
If you followed the official installation guide for Alliance Auth (AA) pre AA 3.x you usually ended up with a "root installation". A root installation means that you have installed AA with the root user and now need to log in as root every time to perform maintenance for AA, e.g., updating existing apps.
Since working as root is [generally not recommended](https://askubuntu.com/questions/16178/why-is-it-bad-to-log-in-as-root), this guide explains how you can easily migrate your existing "root installation" to a "non-root installation".
## How to switch to non-root
We will change the setup so that you can use your `allianceserver` user to perform most maintenance operations. In addition, you also need a sudo user for invoking root privileges, e.g. when restarting the AA services.
We will change the setup so that you can use your `allianceserver` user to perform most maintenance operations. In addition, you also need a sudo user for invoking root privileges, e.g., when restarting the AA services.
The migration itself is rather straightforward. The main idea is to change ownership for all relevant directories and files to `allianceserver`.

View File

@@ -2,90 +2,96 @@
This guide describes how to upgrade an existing Alliance Auth (AA) installation to a newer Python 3 version.
This guide shares many similarities with the Alliance Auth install guide, but it is targeted towards existing installs needing to update.
This guide shares many similarities with the Alliance Auth install guide, but it is targeted towards existing installations needing to update.
```eval_rst
.. note::
This guide will upgrade the software components only but not change any data or configuration.
```
:::{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.
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 installing an additional Python 3 version alongside your default version and using that for AA.
To install other Python versions than those included with your distribution, you need to add a new installation repository. Then you can install the specific Python 3 to your system.
Ubuntu 1804, 2004:
```eval_rst
.. note::
:::{note}
Ubuntu 2204 ships with Python 3.10 already
```
```bash
sudo add-apt-repository ppa:deadsnakes/ppa
```
```bash
sudo apt-get update
```
```bash
sudo apt-get install python3.10 python3.10-dev python3.10-venv
```
CentOS 7:
We need to build Python from source
:::
Centos Stream 8/9:
```eval_rst
.. note::
A Python 3.9 Package is available for Stream 8 and 9. You _may_ use this instead of building your own package. But our documentation will assume Python3.10 and you may need to substitute as neccessary
sudo dnf install python39 python39-devel
:::{note}
A Python 3.9 Package is available for Stream 8 and 9. You _may_ use this instead of building your own package. But our documentation will assume Python3.11, and you may need to substitute as necessary
sudo dnf install python39 python39-devel
:::
::::{tabs}
:::{group-tab} Ubuntu 2004, 2204
```shell
sudo add-apt-repository ppa:deadsnakes/ppa
sudo apt-get update
sudo apt-get install python3.11 python3.11-dev python3.11-venv
```
:::
:::{group-tab} CentOS 7
```bash
cd ~
```
```bash
sudo yum install gcc openssl-devel bzip2-devel libffi-devel wget
```
```bash
wget https://www.python.org/ftp/python/3.10.5/Python-3.10.5.tgz
```
```bash
tar xvf Python-3.10.5.tgz
```
```bash
cd Python-3.10.5/
```
```bash
wget https://www.python.org/ftp/python/3.11.5/Python-3.11.5.tgz
tar xvf Python-3.11.5.tgz
cd Python-3.11.5/
./configure --enable-optimizations --enable-shared
```
```bash
sudo make altinstall
```
:::
:::{group-tab} CentOS Stream 8
```bash
cd ~
sudo yum install gcc openssl-devel bzip2-devel libffi-devel wget
wget https://www.python.org/ftp/python/3.11.5/Python-3.11.5.tgz
tar xvf Python-3.11.5.tgz
cd Python-3.11.5/
./configure --enable-optimizations --enable-shared
sudo make altinstall
```
:::
:::{group-tab} CentOS Stream 9
```bash
cd ~
sudo yum install gcc openssl-devel bzip2-devel libffi-devel wget
wget https://www.python.org/ftp/python/3.11.5/Python-3.11.5.tgz
tar xvf Python-3.11.5.tgz
cd Python-3.11.5/
./configure --enable-optimizations --enable-shared
sudo make altinstall
```
:::
::::
## 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.
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`
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`
```eval_rst
.. note::
If you installed Alliance Auth under the allianceserver user, as reccommended. Remember to switch users for easier permission management::
:::{note}
If you installed Alliance Auth under the allianceserver user, as recommended. Remember to switch users for easier permission management::
:::
sudo su allianceserver
```bash
sudo su allianceserver
```
Activate your venv:
```bash
```shell
source /home/allianceserver/venv/auth/bin/activate
```
@@ -93,64 +99,65 @@ source /home/allianceserver/venv/auth/bin/activate
Make sure to upgrade AA to the newest version:
```bash
```shell
pip install -U allianceauth
```
Run migrations and collectstatic.
```bash
```shell
python manage.py migrate
```
```bash
```shell
python manage.py collectstatic
```
Restart your AA supervisor:
```bash
```shell
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.
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 making a list of all your apps, so you can 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.
If you unsure which apps you have installed from repos check `INSTALLED_APPS` in your settings. Alternatively, run this command to get a list of all apps in your venv.
```bash
```shell
pip list
```
Repeat as needed for your apps
```bash
```shell
pip install -U APP_NAME
```
Make sure to run migrations and collect static files for all upgraded apps.
```bash
```shell
python manage.py migrate
```
```bash
```shell
python manage.py collectstatic
```
### 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:
For a final check that there are no issues - e.g., any outstanding migrations - run this command:
```bash
```shell
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.
If you get the following result, you are good to go. Otherwise, make sure to fix any issues first before proceeding.
```bash
```shell
System check identified no issues (0 silenced).
```
@@ -158,52 +165,49 @@ System check identified no issues (0 silenced).
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.
First, we create a list of all installed packages in your venv. You can use this list later as a reference to see what packages should be installed.
```bash
```shell
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:
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)
- 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.
```
:::{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 to be manually reinstalled.
:::
:::{note}
Some guides on the Internet will suggest using 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
```shell
deactivate
```
```bash
```shell
supervisorctl stop myauth:
```
Rename and keep your old venv so we have a fallback in case of some unforeseeable issues:
Rename and keep your old venv, so we have a fallback in case of some unforeseeable issues:
```bash
```shell
mv /home/allianceserver/venv/auth /home/allianceserver/venv/auth_old
```
## Create your new venv
Now let's create our new venv with Python 3.10 and activate it:
Now let's create our new venv with Python 3.11 and activate it:
```bash
python3.10 -m venv /home/allianceserver/venv/auth
```shell
python3.11 -m venv /home/allianceserver/venv/auth
```
```bash
```shell
source /home/allianceserver/venv/auth/bin/activate
```
@@ -213,79 +217,79 @@ Now we need to reinstall all packages into your new venv.
### Install basic packages
```bash
```shell
pip install -U pip setuptools wheel
```
### Installing AA & Gunicorn
```bash
```shell
pip install allianceauth
```
```bash
```shell
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.
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:
To check whether you are missing any apps, you can also run the check command:
```bash
```shell
python manage.py check
```
Note: In case you forget to install an app you will get this error
Note: In case you forget to install an app, you will get this error
```bash
```shell
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.
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 run migrations normally.
## Restart
After you have completed installing all packages just start your AA supervisor again.
After you have completed installing all packages, start your AA supervisor again.
```bash
```shell
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.
We recommend keeping 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.
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
```shell
ls /home/allianceserver/venv/auth /home/allianceserver/venv
```
If the output shows these two folders you should be safe to proceed:
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
```shell
supervisorctl stop myauth:
```
```bash
```shell
rm -rf /home/allianceserver/venv/auth
```
```bash
```shell
mv /home/allianceserver/venv/auth_old /home/allianceserver/venv/auth
```
```bash
```shell
supervisorctl start myauth:
```

View File

@@ -11,13 +11,11 @@ Your auth project is just a regular Django project - you can add in [other Djang
## Removing Apps
The following instructions will explain how you can remove an app properly fom your Alliance Auth installation.
The following instructions will explain how you can remove an app properly from your Alliance Auth installation.
```eval_rst
.. note::
We recommend following these instructions to avoid dangling foreign keys or orphaned Python packages on your system, which might cause conflicts with other apps down the road.
```
:::{note}
We recommend following these instructions to avoid dangling foreign keys or orphaned Python packages on your system, which might cause conflicts with other apps down the road.
:::
### Step 1 - Removing database tables
@@ -27,44 +25,44 @@ First, we want to remove the app related tables from the database.
Let's first try the automatic approach by running the following command:
```sh
```shell
python manage.py migrate appname zero
```
If that worked you'll get a confirmation message.
If that works, you'll get a confirmation message.
If that did not work and you got error messages, you will need to remove the tables manually. This is pretty common btw, because many apps use sophisticated table setups, which can not be removed automatically by Django.
If that did not work, and you got error messages, you will need to remove the tables manually. This is pretty common btw, because many apps use sophisticated table setups, which cannot be removed automatically by Django.
#### Manual table removal
First, tell Django that these migrations are no longer in effect (note the additional `--fake`):
```sh
```shell
python manage.py migrate appname zero --fake
```
Then, open the mysql tool and connect to your Alliance Auth database:
```sh
```shell
sudo mysql -u root
use alliance_auth;
```
Next disable foreign key check. This makes it much easier to drop tables in any order.
Next, disable foreign key check. This makes it much easier to drop tables in any order.
```sh
```shell
SET FOREIGN_KEY_CHECKS=0;
```
Then get a list of all tables. All tables belonging to the app in question will start with `appname_`.
```sh
```shell
show tables;
```
Now, drop the tables from the app one by one like so:
```sh
```shell
drop table appname_model_1;
drop table appname_model_2;
...
@@ -72,20 +70,20 @@ drop table appname_model_2;
And finally, but very importantly, re-enable foreign key checks again and then exit:
```sh
```shell
SET FOREIGN_KEY_CHECKS=1;
exit;
```
### Step 2 - Remove the app from Alliance Auth
Once the tables have been removed, you you can remove the app from Alliance Auth. This is done by removing the applabel from the `INSTALLED_APPS` list in your local settings file.
Once the tables have been removed, you can remove the app from Alliance Auth. This is done by removing the applabel from the `INSTALLED_APPS` list in your local settings file.
### Step 3 - Remove the Python package
Finally, we want to remove the app's Python package. For that run the following command:
```sh
```shell
pip uninstall app-package-name
```
@@ -103,4 +101,4 @@ python manage.py remove_stale_contenttypes --include-stale-apps
This inbuilt Django command will step through each contenttype and offer to delete it, displaying what exactly this will cascade to delete. Pay attention and ensure you understand exactly what is being removed before answering `yes`.
This should only cleanup uninstalled apps, deprecated permissions within apps should be cleaned up using Data Migrations by each responsible application.
This should only clean up uninstalled apps, deprecated permissions within apps should be cleaned up using Data Migrations by each responsible application.

View File

@@ -1,13 +1,12 @@
# Maintenance
In the maintenance chapter you find details about where important log files are found, how you can customize your AA installation and how to solve common issues.
In the maintenance chapter, you find details about where important log files are found, how you can customize your AA installation and how to solve common issues.
```eval_rst
.. toctree::
:maxdepth: 1
:::{toctree}
:maxdepth: 1
apps
project
troubleshooting
tuning/index
```
apps
project
troubleshooting
tuning/index
:::

View File

@@ -1,6 +1,6 @@
# Folder structure
When installing Alliance Auth you are instructed to run the `allianceauth start` command which generates a folder containing your auth project. This auth project is based off Alliance Auth but can be customized how you wish.
When installing Alliance Auth, you are instructed to run the `allianceauth start` command which generates a folder containing your auth project. This auth project is based off Alliance Auth but can be customized how you wish.
## The myauth folder
@@ -26,9 +26,9 @@ And finally the settings folder.
With the settings folder lives two settings files: `base.py` and `local.py`
The base settings file contains everything needed to run Alliance Auth. It handles configuration of Django and Celery, defines logging, and many other Django-required settings. This file should not be edited. While updating Alliance Auth you may be instructed to update the base settings file - this is achieved through the `allianceauth update` command which overwrites the existing base settings file.
The base settings file contains everything needed to run Alliance Auth. It handles configuration of Django and Celery, defines logging, and many other Django-required settings. This file should not be edited. While updating Alliance Auth, you may be instructed to update the base settings file - this is achieved through the `allianceauth update` command which overwrites the existing base settings file.
The local settings file is referred to as "your auth project's settings file" and you are instructed to edit it during the install process. You can add any additional settings required by other apps to this file. Upon creation the first line is `from .base import *` meaning all settings defined in the base settings file are loaded. You can override any base setting by simply redefining it in your local settings file.
The local settings file is referred to as "your auth project's settings file" and you are instructed to edit it during the installation process. You can add any additional settings required by other apps to this file. Upon creation the first line is `from .base import *` meaning all settings defined in the base settings file are loaded. You can override any base setting by simply redefining it in your local settings file.
## Log Files
@@ -39,4 +39,4 @@ Your auth project comes with four log file definitions by default. These are cre
- `beat.log` contains logging messages from the background task scheduler. This is of limited use unless the scheduler isn't starting.
- `gunicorn.log` contains logging messages from Gunicorn workers. This contains all web-sourced messages found in `allianceauth.log` as well as runtime errors from the workers themselves.
When asking for assistance with your auth project be sure to first read the logs, and share any relevant entries.
When asking for assistance with your auth project, be sure to first read the logs, and share any relevant entries.

View File

@@ -2,13 +2,13 @@
## Logging
In its default configuration your auth project logs INFO and above messages to myauth/log/allianceauth.log. If you're encountering issues it's a good idea to view DEBUG messages as these greatly assist the troubleshooting process. These are printed to the console with manually starting the webserver via `python manage.py runserver`.
In its default configuration, your auth project logs INFO and higher messages to myauth/log/allianceauth.log. If you're encountering issues, it's a good idea to view DEBUG messages as these greatly assist the troubleshooting process. These are printed to the console with manually starting the webserver via `python manage.py runserver`.
To record DEBUG messages in the log file, alter a setting in your auth project's settings file: `LOGGING['handlers']['log_file']['level'] = 'DEBUG'`. After restarting gunicorn and celery your log file will record all logging messages.
To record DEBUG messages in the log file, alter a setting in your auth project's settings file: `LOGGING['handlers']['log_file']['level'] = 'DEBUG'`. After restarting gunicorn and celery, your log file will record all logging messages.
## Common Problems
### I'm getting an error 500 trying to connect to the website on a new install
### I'm getting error 500 when trying to connect to the website on a new installation
*Great.* Error 500 is the generic message given by your web server when *anything* breaks. The actual error message is hidden in one of your auth project's log files. Read them to identify it.
@@ -24,9 +24,9 @@ Make sure the background processes are running: `supervisorctl status myauth:`.
Stop celery workers with `supervisorctl stop myauth:worker` then clear the queue:
```bash
redis-cli FLUSHALL
celery -A myauth worker --purge
```shell
redis-cli FLUSHALL
celery -A myauth worker --purge
```
Press Control+C once.
@@ -39,7 +39,7 @@ This usually indicates an issue with your email settings. Ensure these are corre
### No images are available to users accessing the website
This is likely due to a permissions mismatch. Check the setup guide for your web server. Additionally ensure the user who owns `/var/www/myauth/static` is the same user as running your webserver, as this can be non-standard.
This is likely due to a permission mismatch. Check the setup guide for your web server. Additionally ensure the user who owns `/var/www/myauth/static` is the same user as running your webserver, as this can be non-standard.
### Unable to execute 'gunicorn myauth.wsgi' or ImportError: No module named 'myauth.wsgi'
@@ -49,10 +49,10 @@ Gunicorn needs to have context for its running location, `/home/alllianceserver/
Migrations may about with the following error message:
```bash
```shell
Specified key was too long; max key length is 767 bytes
```
This error will occur if one is trying to use Maria DB prior to 10.2.x, which is not compatible with Alliance Auth.
Install a never Maria DB version to fix this issue another DBMS supported by Django 2.2.
Install a newer Maria DB version to fix this issue another DBMS supported by Django 2.2.

Some files were not shown because too many files have changed in this diff Show More