mirror of
https://gitlab.com/allianceauth/allianceauth.git
synced 2025-07-11 13:30:17 +02:00
commit
48c8ccfe97
1
.gitignore
vendored
1
.gitignore
vendored
@ -8,6 +8,7 @@ __pycache__/
|
||||
# Distribution / packaging
|
||||
.Python
|
||||
env/
|
||||
venv/
|
||||
build/
|
||||
develop-eggs/
|
||||
dist/
|
||||
|
@ -1,7 +1,7 @@
|
||||
# This will make sure the app is always imported when
|
||||
# Django starts so that shared_task will use this app.
|
||||
|
||||
__version__ = '2.0b2'
|
||||
__version__ = '2.0b3'
|
||||
NAME = 'Alliance Auth v%s' % __version__
|
||||
default_app_config = 'allianceauth.apps.AllianceAuthConfig'
|
||||
|
||||
|
37
allianceauth/authentication/decorators.py
Normal file
37
allianceauth/authentication/decorators.py
Normal file
@ -0,0 +1,37 @@
|
||||
from django.conf.urls import include
|
||||
from functools import wraps
|
||||
from django.shortcuts import redirect
|
||||
from django.contrib import messages
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django.contrib.auth.decorators import login_required
|
||||
|
||||
|
||||
def user_has_main_character(user):
|
||||
return bool(user.profile.main_character)
|
||||
|
||||
|
||||
def decorate_url_patterns(urls, decorator):
|
||||
url_list, app_name, namespace = include(urls)
|
||||
|
||||
def process_patterns(url_patterns):
|
||||
for pattern in url_patterns:
|
||||
if hasattr(pattern, 'url_patterns'):
|
||||
# this is an include - apply to all nested patterns
|
||||
process_patterns(pattern.url_patterns)
|
||||
else:
|
||||
# this is a pattern
|
||||
pattern.callback = decorator(pattern.callback)
|
||||
|
||||
process_patterns(url_list)
|
||||
return url_list, app_name, namespace
|
||||
|
||||
|
||||
def main_character_required(view_func):
|
||||
@wraps(view_func)
|
||||
def _wrapped_view(request, *args, **kwargs):
|
||||
if user_has_main_character(request.user):
|
||||
return view_func(request, *args, **kwargs)
|
||||
|
||||
messages.error(request, _('A main character is required to perform that action. Add one below.'))
|
||||
return redirect('authentication:dashboard')
|
||||
return login_required(_wrapped_view)
|
@ -3,7 +3,7 @@ import logging
|
||||
from .models import CharacterOwnership, UserProfile, get_guest_state, State
|
||||
from django.contrib.auth.models import User
|
||||
from django.db.models import Q
|
||||
from django.db.models.signals import pre_save, post_save, pre_delete, m2m_changed
|
||||
from django.db.models.signals import pre_save, post_save, pre_delete, post_delete, m2m_changed
|
||||
from django.dispatch import receiver, Signal
|
||||
from esi.models import Token
|
||||
|
||||
@ -104,23 +104,23 @@ def record_character_ownership(sender, instance, created, *args, **kwargs):
|
||||
@receiver(pre_delete, sender=CharacterOwnership)
|
||||
def validate_main_character(sender, instance, *args, **kwargs):
|
||||
if instance.user.profile.main_character == instance.character:
|
||||
logger.debug("Ownership of a main character {0} has been revoked. Resetting {1} main character.".format(
|
||||
logger.info("Ownership of a main character {0} has been revoked. Resetting {1} main character.".format(
|
||||
instance.character, instance.user))
|
||||
# clear main character as user no longer owns them
|
||||
instance.user.profile.main_character = None
|
||||
instance.user.profile.save()
|
||||
|
||||
|
||||
@receiver(pre_delete, sender=Token)
|
||||
@receiver(post_delete, sender=Token)
|
||||
def validate_main_character_token(sender, instance, *args, **kwargs):
|
||||
if UserProfile.objects.filter(main_character__character_id=instance.character_id).exists():
|
||||
logger.debug(
|
||||
"Token for a main character {0} is being deleted. Ensuring there are valid tokens to refresh.".format(
|
||||
instance.character_name))
|
||||
profile = UserProfile.objects.get(main_character__character_id=instance.character_id)
|
||||
if not Token.objects.filter(character_id=instance.character_id).filter(user=profile.user).exclude(
|
||||
pk=instance.pk).require_valid().exists():
|
||||
logger.debug(
|
||||
if not Token.objects.filter(character_id=instance.character_id).filter(
|
||||
user=profile.user).filter(refresh_token__isnull=False).exists():
|
||||
logger.info(
|
||||
"No remaining tokens to validate {0} ownership of main character {1}. Resetting main character.".format(
|
||||
profile.user, profile.main_character))
|
||||
# clear main character as we can no longer verify ownership
|
||||
|
@ -57,7 +57,7 @@
|
||||
</div>
|
||||
{% endwith %}
|
||||
{% else %}
|
||||
<div class="alert alert-danger" role="alert">{% trans "Missing main character model." %}</div>
|
||||
<div class="alert alert-danger" role="alert">{% trans "No main character set." %}</div>
|
||||
{% endif %}
|
||||
<div class="clearfix"></div>
|
||||
<div class="col-xs-6">
|
||||
|
@ -8,6 +8,61 @@ from .backends import StateBackend
|
||||
from .tasks import check_character_ownership
|
||||
from allianceauth.eveonline.models import EveCharacter, EveCorporationInfo, EveAllianceInfo
|
||||
from esi.models import Token
|
||||
from allianceauth.authentication.decorators import main_character_required
|
||||
from django.test.client import RequestFactory
|
||||
from django.http.response import HttpResponse
|
||||
from django.contrib.auth.models import AnonymousUser
|
||||
from django.conf import settings
|
||||
from django.shortcuts import reverse
|
||||
from urllib import parse
|
||||
|
||||
MODULE_PATH = 'allianceauth.authentication'
|
||||
|
||||
|
||||
class DecoratorTestCase(TestCase):
|
||||
@staticmethod
|
||||
@main_character_required
|
||||
def dummy_view(*args, **kwargs):
|
||||
return HttpResponse(status=200)
|
||||
|
||||
@classmethod
|
||||
def setUpTestData(cls):
|
||||
cls.main_user = AuthUtils.create_user('main_user', disconnect_signals=True)
|
||||
cls.no_main_user = AuthUtils.create_user('no_main_user', disconnect_signals=True)
|
||||
main_character = EveCharacter.objects.create(
|
||||
character_id=1,
|
||||
character_name='Main Character',
|
||||
corporation_id=1,
|
||||
corporation_name='Corp',
|
||||
corporation_ticker='CORP',
|
||||
)
|
||||
CharacterOwnership.objects.create(user=cls.main_user, character=main_character, owner_hash='1')
|
||||
cls.main_user.profile.main_character = main_character
|
||||
|
||||
def setUp(self):
|
||||
self.request = RequestFactory().get('/test/')
|
||||
|
||||
@mock.patch(MODULE_PATH + '.decorators.messages')
|
||||
def test_login_redirect(self, m):
|
||||
setattr(self.request, 'user', AnonymousUser())
|
||||
response = self.dummy_view(self.request)
|
||||
self.assertEqual(response.status_code, 302)
|
||||
url = getattr(response, 'url', None)
|
||||
self.assertEqual(parse.urlparse(url).path, reverse(settings.LOGIN_URL))
|
||||
|
||||
@mock.patch(MODULE_PATH + '.decorators.messages')
|
||||
def test_main_character_redirect(self, m):
|
||||
setattr(self.request, 'user', self.no_main_user)
|
||||
response = self.dummy_view(self.request)
|
||||
self.assertEqual(response.status_code, 302)
|
||||
url = getattr(response, 'url', None)
|
||||
self.assertEqual(url, reverse('authentication:dashboard'))
|
||||
|
||||
@mock.patch(MODULE_PATH + '.decorators.messages')
|
||||
def test_successful_request(self, m):
|
||||
setattr(self.request, 'user', self.main_user)
|
||||
response = self.dummy_view(self.request)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
|
||||
class BackendTestCase(TestCase):
|
||||
|
@ -1,5 +1,5 @@
|
||||
from celery import shared_task
|
||||
from allianceauth.corputils import CorpStats
|
||||
from allianceauth.corputils.models import CorpStats
|
||||
|
||||
|
||||
@shared_task
|
||||
|
@ -2,11 +2,9 @@
|
||||
from django import forms
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from allianceauth.optimer.models import OpTimer
|
||||
|
||||
|
||||
class FatlinkForm(forms.Form):
|
||||
fatname = forms.CharField(label=_('Name of fat-link'), required=True)
|
||||
fleet = forms.CharField(label=_("Fleet Name"), max_length=50)
|
||||
duration = forms.IntegerField(label=_("Duration of fat-link"), required=True, initial=30, min_value=1,
|
||||
max_value=2147483647)
|
||||
fleet = forms.ModelChoiceField(label=_("Fleet"), queryset=OpTimer.objects.all().order_by('operation_name'))
|
||||
max_value=2147483647, help_text=_('minutes'))
|
||||
|
||||
|
@ -2,12 +2,10 @@
|
||||
# Generated by Django 1.10.1 on 2016-09-05 21:39
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import datetime
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
from django.utils.timezone import utc
|
||||
from django.utils import timezone
|
||||
|
||||
import allianceauth.fleetactivitytracking.models
|
||||
|
||||
@ -36,9 +34,9 @@ class Migration(migrations.Migration):
|
||||
name='Fatlink',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('fatdatetime', models.DateTimeField(default=datetime.datetime(2016, 9, 5, 21, 39, 17, 307954, tzinfo=utc))),
|
||||
('fatdatetime', models.DateTimeField(default=timezone.now)),
|
||||
('duration', models.PositiveIntegerField()),
|
||||
('fleet', models.CharField(default=b'', max_length=254)),
|
||||
('fleet', models.CharField(default='', max_length=254)),
|
||||
('name', models.CharField(max_length=254)),
|
||||
('hash', models.CharField(max_length=254, unique=True)),
|
||||
('creator', models.ForeignKey(on_delete=models.SET(
|
||||
|
@ -0,0 +1,22 @@
|
||||
# Generated by Django 2.0.2 on 2018-02-28 18:00
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('fleetactivitytracking', '0004_make_strings_more_stringy'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='fatlink',
|
||||
name='name',
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='fatlink',
|
||||
name='fleet',
|
||||
field=models.CharField(max_length=254),
|
||||
),
|
||||
]
|
@ -12,13 +12,12 @@ def get_sentinel_user():
|
||||
class Fatlink(models.Model):
|
||||
fatdatetime = models.DateTimeField(default=timezone.now)
|
||||
duration = models.PositiveIntegerField()
|
||||
fleet = models.CharField(max_length=254, default="")
|
||||
name = models.CharField(max_length=254)
|
||||
fleet = models.CharField(max_length=254)
|
||||
hash = models.CharField(max_length=254, unique=True)
|
||||
creator = models.ForeignKey(User, on_delete=models.SET(get_sentinel_user))
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
return self.fleet
|
||||
|
||||
|
||||
class Fat(models.Model):
|
||||
|
@ -16,7 +16,7 @@
|
||||
</div>
|
||||
<div class="col-lg-10 col-sm-2">
|
||||
<div class="alert alert-danger" role="alert">{% trans "Character not registered!" %}</div>
|
||||
{% trans "This character is not part of any registered API-key. You must go to" %} <a href=" {% url 'auth_api_key_management' %}">{% trans "API key management</a> and add an API with the character on before being able to click fleet attendance links." %}
|
||||
{% trans "This character is not associated with an auth account." %} <a href=" {% url 'authentication:add_character' %}">{% trans "Add it here" %}</a> {% trans "before attempting to click fleet attendance links." %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -10,12 +10,12 @@
|
||||
<h1 class="page-header text-center">{% blocktrans %}Participation data statistics for {{ month }}, {{ year }}{% endblocktrans %}
|
||||
{% if char_id %}
|
||||
<div class="text-right">
|
||||
<a href="{% url 'fatlink:user_statistics_month' char_id previous_month|date:"Y" previous_month|date:"m" %}" class="btn btn-info">{% trans "Previous month" %}</a>
|
||||
<a href="{% url 'fatlink:user_statistics_month' char_id next_month|date:"Y" next_month|date:"m" %}" class="btn btn-info">{% trans "Next month" %}</a>
|
||||
<a href="{% url 'fatlink:user_statistics_month' char_id previous_month|date:'Y' previous_month|date:'m' %}" class="btn btn-info">{% trans "Previous month" %}</a>
|
||||
<a href="{% url 'fatlink:user_statistics_month' char_id next_month|date:'Y' next_month|date:'m' %}" class="btn btn-info">{% trans "Next month" %}</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
</h1>
|
||||
<h2>{% blocktrans %}{{ user }} has collected {{ n_fats }} links this month.{% endblocktrans %}</h2>
|
||||
<h2>{% blocktrans %}{{ user }} has collected {{ n_fats }} link{{ n_fats|pluralize }} this month.{% endblocktrans %}</h2>
|
||||
<table class="table table-responsive">
|
||||
<tr>
|
||||
<th class="col-md-2 text-center">{% trans "Ship" %}</th>
|
||||
@ -29,26 +29,24 @@
|
||||
{% endfor %}
|
||||
</table>
|
||||
{% if created_fats %}
|
||||
<h2>{% blocktrans %}{{ user }} has created {{ n_created_fats }} links this month.{% endblocktrans %}</h2>
|
||||
<h2>{% blocktrans %}{{ user }} has created {{ n_created_fats }} link{{ n_created_fats|pluralize }} this month.{% endblocktrans %}</h2>
|
||||
{% if created_fats %}
|
||||
<table class="table">
|
||||
<tr>
|
||||
<th class="text-center">{% trans "Name" %}</th>
|
||||
<th class="text-center">{% trans "Creator" %}</th>
|
||||
<th class="text-center">{% trans "Fleet" %}</th>
|
||||
<th class="text-center">{% trans "Creator" %}</th>
|
||||
<th class="text-center">{% trans "Eve Time" %}</th>
|
||||
<th class="text-center">{% trans "Duration" %}</th>
|
||||
<th class="text-center">{% trans "Edit" %}</th>
|
||||
</tr>
|
||||
{% for link in created_fats %}
|
||||
<tr>
|
||||
<td class="text-center"><a href="{% url 'auth_click_fatlink_view' %}{{ link.hash }}/{{ link.name }}">{{ link.name }}</a></td>
|
||||
<td class="text-center"><a href="{% url 'fatlink:click' link.hash %}" class="label label-primary">{{ link.fleet }}</a></td>
|
||||
<td class="text-center">{{ link.creator.username }}</td>
|
||||
<td class="text-center">{{ link.fleet }}</td>
|
||||
<td class="text-center">{{ link.fatdatetime }}</td>
|
||||
<td class="text-center">{{ link.duration }}</td>
|
||||
<td class="text-center">
|
||||
<a href="{% url 'auth_modify_fatlink_view' %}{{ link.hash }}/{{ link.name }}">
|
||||
<a href="{% url 'fatlink:modify' link.hash %}">
|
||||
<button type="button" class="btn btn-info"><span
|
||||
class="glyphicon glyphicon-edit"></span></button>
|
||||
</a>
|
||||
|
@ -24,7 +24,7 @@
|
||||
{% if fats %}
|
||||
<table class="table table-responsive">
|
||||
<tr>
|
||||
<th class="text-center">{% trans "fatname" %}</th>
|
||||
<th class="text-center">{% trans "Fleet" %}</th>
|
||||
<th class="text-center">{% trans "Character" %}</th>
|
||||
<th class="text-center">{% trans "System" %}</th>
|
||||
<th class="text-center">{% trans "Ship" %}</th>
|
||||
@ -32,7 +32,7 @@
|
||||
</tr>
|
||||
{% for fat in fats %}
|
||||
<tr>
|
||||
<td class="text-center">{{ fat.fatlink.name }}</td>
|
||||
<td class="text-center">{{ fat.fatlink.fleet }}</td>
|
||||
<td class="text-center">{{ fat.character.character_name }}</td>
|
||||
{% if fat.station != "No Station" %}
|
||||
<td class="text-center">{% blocktrans %}Docked in {% endblocktrans %}{{ fat.system }}</td>
|
||||
@ -79,13 +79,13 @@
|
||||
</tr>
|
||||
{% for link in fatlinks %}
|
||||
<tr>
|
||||
<td class="text-center"><a href="{% url 'fatlink:click_fatlink' %}{{ link.hash }}/{{ link.name }}">{{ link.name }}</a></td>
|
||||
<td class="text-center"><a href="{% url 'fatlink:click' link.hash %}" class="label label-primary">{{ link.fleet }}</a></td>
|
||||
<td class="text-center">{{ link.creator.username }}</td>
|
||||
<td class="text-center">{{ link.fleet }}</td>
|
||||
<td class="text-center">{{ link.fatdatetime }}</td>
|
||||
<td class="text-center">{{ link.duration }}</td>
|
||||
<td class="text-center">
|
||||
<a href="{% url 'fatlink:modify' %}{{ link.hash }}/{{ link.name }}" class="btn btn-info">
|
||||
<a href="{% url 'fatlink:modify' link.hash %}" class="btn btn-info">
|
||||
<span class="glyphicon glyphicon-edit"></span>
|
||||
</a>
|
||||
</td>
|
||||
|
@ -25,10 +25,6 @@ urlpatterns = [
|
||||
views.fatlink_monthly_personal_statistics_view,
|
||||
name='user_statistics_month'),
|
||||
url(r'^create/$', views.create_fatlink_view, name='create'),
|
||||
url(r'^modify/$', views.modify_fatlink_view, name='modify'),
|
||||
url(r'^modify/(?P<hash>[a-zA-Z0-9_-]+)/([a-z0-9_-]+)$',
|
||||
views.modify_fatlink_view),
|
||||
url(r'^link/$', views.fatlink_view, name='click_fatlink'),
|
||||
url(r'^link/(?P<hash>[a-zA-Z0-9]+)/(?P<fatname>[a-z0-9_-]+)/$',
|
||||
views.click_fatlink_view),
|
||||
url(r'^modify/(?P<fat_hash>[a-zA-Z0-9_-]+)/$', views.modify_fatlink_view, name='modify'),
|
||||
url(r'^link/(?P<fat_hash>[a-zA-Z0-9]+)/$', views.click_fatlink_view, name='click'),
|
||||
]
|
||||
|
@ -1,8 +1,6 @@
|
||||
import datetime
|
||||
import logging
|
||||
import os
|
||||
import random
|
||||
import string
|
||||
|
||||
from allianceauth.authentication.models import CharacterOwnership
|
||||
from django.contrib import messages
|
||||
@ -17,7 +15,7 @@ from esi.decorators import token_required
|
||||
from allianceauth.eveonline.providers import provider
|
||||
from .forms import FatlinkForm
|
||||
from .models import Fatlink, Fat
|
||||
from slugify import slugify
|
||||
from django.utils.crypto import get_random_string
|
||||
|
||||
from allianceauth.eveonline.models import EveAllianceInfo
|
||||
from allianceauth.eveonline.models import EveCharacter
|
||||
@ -181,7 +179,7 @@ def fatlink_personal_statistics_view(request, year=datetime.date.today().year):
|
||||
|
||||
personal_fats = Fat.objects.select_related('fatlink').filter(user=user).order_by('id')
|
||||
|
||||
monthlystats = [0 for month in range(1, 13)]
|
||||
monthlystats = [0 for i in range(1, 13)]
|
||||
|
||||
for fat in personal_fats:
|
||||
fatdate = fat.fatlink.fatdatetime
|
||||
@ -236,8 +234,8 @@ def fatlink_monthly_personal_statistics_view(request, year, month, char_id=None)
|
||||
@login_required
|
||||
@token_required(
|
||||
scopes=['esi-location.read_location.v1', 'esi-location.read_ship_type.v1', 'esi-universe.read_structures.v1'])
|
||||
def click_fatlink_view(request, token, hash, fatname):
|
||||
fatlink = get_object_or_404(Fatlink, hash=hash, name=fatname)
|
||||
def click_fatlink_view(request, token, fat_hash=None):
|
||||
fatlink = get_object_or_404(Fatlink, hash=fat_hash)
|
||||
|
||||
if (timezone.now() - fatlink.fatdatetime) < datetime.timedelta(seconds=(fatlink.duration * 60)):
|
||||
|
||||
@ -298,12 +296,11 @@ def create_fatlink_view(request):
|
||||
logger.debug("Submitting fleetactivitytracking by user %s" % request.user)
|
||||
if form.is_valid():
|
||||
fatlink = Fatlink()
|
||||
fatlink.name = slugify(form.cleaned_data["fatname"])
|
||||
fatlink.fleet = form.cleaned_data["fleet"]
|
||||
fatlink.duration = form.cleaned_data["duration"]
|
||||
fatlink.fatdatetime = timezone.now()
|
||||
fatlink.creator = request.user
|
||||
fatlink.hash = ''.join(random.choice(string.ascii_letters + string.digits) for i in range(10))
|
||||
fatlink.hash = get_random_string(length=15)
|
||||
try:
|
||||
fatlink.full_clean()
|
||||
fatlink.save()
|
||||
@ -331,25 +328,19 @@ def create_fatlink_view(request):
|
||||
|
||||
@login_required
|
||||
@permission_required('auth.fleetactivitytracking')
|
||||
def modify_fatlink_view(request, hash=""):
|
||||
def modify_fatlink_view(request, fat_hash=None):
|
||||
logger.debug("modify_fatlink_view called by user %s" % request.user)
|
||||
if not hash:
|
||||
return redirect('fatlink:view')
|
||||
|
||||
try:
|
||||
fatlink = Fatlink.objects.get(hash=hash)
|
||||
except Fatlink.DoesNotExist:
|
||||
raise Http404
|
||||
fatlink = get_object_or_404(Fatlink, hash=fat_hash)
|
||||
|
||||
if request.GET.get('removechar', None):
|
||||
character_id = request.GET.get('removechar')
|
||||
character = EveCharacter.objects.get(character_id=character_id)
|
||||
logger.debug("Removing character %s from fleetactivitytracking %s" % (character.character_name, fatlink.name))
|
||||
logger.debug("Removing character %s from fleetactivitytracking %s" % (character.character_name, fatlink))
|
||||
|
||||
Fat.objects.filter(fatlink=fatlink).filter(character=character).delete()
|
||||
|
||||
if request.GET.get('deletefat', None):
|
||||
logger.debug("Removing fleetactivitytracking %s" % fatlink.name)
|
||||
logger.debug("Removing fleetactivitytracking %s" % fatlink)
|
||||
fatlink.delete()
|
||||
return redirect('fatlink:view')
|
||||
|
||||
|
@ -8,6 +8,7 @@ from allianceauth.tests.auth_utils import AuthUtils
|
||||
class PermissionsToolViewsTestCase(WebTest):
|
||||
def setUp(self):
|
||||
self.member = AuthUtils.create_member('auth_member')
|
||||
AuthUtils.add_main_character(self.member, 'test character', '1234', '2345', 'test corp', 'testc')
|
||||
self.member.email = 'auth_member@example.com'
|
||||
self.member.save()
|
||||
self.none_user = AuthUtils.create_user('none_user', disconnect_signals=True)
|
||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -22,9 +22,7 @@ INSTALLED_APPS += [
|
||||
|
||||
]
|
||||
|
||||
# Uncomment by removing the """ and change the database name and
|
||||
# credentials to use MySQL/MariaDB. Leave commented to use sqlite3
|
||||
"""
|
||||
# Enter credentials to use MySQL/MariaDB. Comment out to use sqlite3
|
||||
DATABASES['default'] = {
|
||||
'ENGINE': 'django.db.backends.mysql',
|
||||
'NAME': 'alliance_auth',
|
||||
@ -33,12 +31,12 @@ DATABASES['default'] = {
|
||||
'HOST': '127.0.0.1',
|
||||
'PORT': '3306',
|
||||
}
|
||||
"""
|
||||
|
||||
# Register an application at https://developers.eveonline.com for Authentication
|
||||
# & API Access and fill out these settings. Be sure to set the callback URL
|
||||
# to https://example.com/sso/callback substituting your domain for example.com
|
||||
# Select publicData and all available scopes starting with esi-
|
||||
# Logging in to auth requires the publicData scope (can be overridden through the
|
||||
# LOGIN_TOKEN_SCOPES setting). Other apps may require more (see their docs).
|
||||
ESI_SSO_CLIENT_ID = ''
|
||||
ESI_SSO_CLIENT_SECRET = ''
|
||||
ESI_SSO_CALLBACK_URL = ''
|
||||
|
@ -32,7 +32,7 @@ SCOPES = [
|
||||
'guilds.join',
|
||||
]
|
||||
|
||||
GROUP_CACHE_MAX_AGE = int(getattr(settings, 'DISCORD_GROUP_CACHE_MAX_AGE', 2 * 60 * 60)) # 2 hours default
|
||||
GROUP_CACHE_MAX_AGE = getattr(settings, 'DISCORD_GROUP_CACHE_MAX_AGE', 2 * 60 * 60) # 2 hours default
|
||||
|
||||
|
||||
class DiscordApiException(Exception):
|
||||
@ -301,13 +301,38 @@ class DiscordOAuthManager:
|
||||
def _create_group(name):
|
||||
return DiscordOAuthManager.__generate_role(name)
|
||||
|
||||
@staticmethod
|
||||
def _get_user(user_id):
|
||||
custom_headers = {'content-type': 'application/json', 'authorization': 'Bot ' + settings.DISCORD_BOT_TOKEN}
|
||||
path = DISCORD_URL + "/guilds/" + str(settings.DISCORD_GUILD_ID) + "/members/" + str(user_id)
|
||||
r = requests.get(path, headers=custom_headers)
|
||||
r.raise_for_status()
|
||||
return r.json()
|
||||
|
||||
@staticmethod
|
||||
def _get_user_roles(user_id):
|
||||
user = DiscordOAuthManager._get_user(user_id)
|
||||
return user['roles']
|
||||
|
||||
@staticmethod
|
||||
def _modify_user_role(user_id, role_id, method):
|
||||
custom_headers = {'content-type': 'application/json', 'authorization': 'Bot ' + settings.DISCORD_BOT_TOKEN}
|
||||
path = DISCORD_URL + "/guilds/" + str(settings.DISCORD_GUILD_ID) + "/members/" + str(user_id) + "/roles/" + str(
|
||||
role_id)
|
||||
r = getattr(requests, method)(path, headers=custom_headers)
|
||||
r.raise_for_status()
|
||||
logger.debug("%s role %s for user %s" % (method, role_id, user_id))
|
||||
|
||||
@staticmethod
|
||||
@api_backoff
|
||||
def update_groups(user_id, groups):
|
||||
custom_headers = {'content-type': 'application/json', 'authorization': 'Bot ' + settings.DISCORD_BOT_TOKEN}
|
||||
group_ids = [DiscordOAuthManager._group_name_to_id(DiscordOAuthManager._sanitize_group_name(g)) for g in groups]
|
||||
path = DISCORD_URL + "/guilds/" + str(settings.DISCORD_GUILD_ID) + "/members/" + str(user_id)
|
||||
data = {'roles': group_ids}
|
||||
r = requests.patch(path, headers=custom_headers, json=data)
|
||||
logger.debug("Received status code %s after setting user roles" % r.status_code)
|
||||
r.raise_for_status()
|
||||
user_group_ids = DiscordOAuthManager._get_user_roles(user_id)
|
||||
for g in group_ids:
|
||||
if g not in user_group_ids:
|
||||
DiscordOAuthManager._modify_user_role(user_id, g, 'put')
|
||||
time.sleep(1) # we're gonna be hammering the API here
|
||||
for g in user_group_ids:
|
||||
if g not in group_ids:
|
||||
DiscordOAuthManager._modify_user_role(user_id, g, 'delete')
|
||||
time.sleep(1)
|
||||
|
@ -145,6 +145,7 @@ class DiscordHooksTestCase(TestCase):
|
||||
class DiscordViewsTestCase(WebTest):
|
||||
def setUp(self):
|
||||
self.member = AuthUtils.create_member('auth_member')
|
||||
AuthUtils.add_main_character(self.member, 'test character', '1234', '2345', 'test corp', 'testc')
|
||||
add_permissions()
|
||||
|
||||
def login(self):
|
||||
@ -326,51 +327,51 @@ class DiscordManagerTestCase(TestCase):
|
||||
# Assert
|
||||
self.assertTrue(result)
|
||||
|
||||
@mock.patch(MODULE_PATH + '.manager.DiscordOAuthManager._get_user_roles')
|
||||
@mock.patch(MODULE_PATH + '.manager.DiscordOAuthManager._get_groups')
|
||||
@requests_mock.Mocker()
|
||||
def test_update_groups(self, group_cache, m):
|
||||
def test_update_groups(self, group_cache, user_roles, m):
|
||||
# Arrange
|
||||
groups = ['Member', 'Blue', 'SpecialGroup']
|
||||
|
||||
group_cache.return_value = [{'id': 111, 'name': 'Member'},
|
||||
{'id': 222, 'name': 'Blue'},
|
||||
{'id': 333, 'name': 'SpecialGroup'},
|
||||
{'id': 444, 'name': 'NotYourGroup'}]
|
||||
group_cache.return_value = [{'id': '111', 'name': 'Member'},
|
||||
{'id': '222', 'name': 'Blue'},
|
||||
{'id': '333', 'name': 'SpecialGroup'},
|
||||
{'id': '444', 'name': 'NotYourGroup'}]
|
||||
user_roles.return_value = ['444']
|
||||
|
||||
headers = {'content-type': 'application/json', 'authorization': 'Bot ' + settings.DISCORD_BOT_TOKEN}
|
||||
user_id = 12345
|
||||
request_url = '{}/guilds/{}/members/{}'.format(manager.DISCORD_URL, settings.DISCORD_GUILD_ID, user_id)
|
||||
user_request_url = '{}/guilds/{}/members/{}'.format(manager.DISCORD_URL, settings.DISCORD_GUILD_ID, user_id)
|
||||
group_request_urls = ['{}/guilds/{}/members/{}/roles/{}'.format(manager.DISCORD_URL, settings.DISCORD_GUILD_ID, user_id, g['id']) for g in group_cache.return_value]
|
||||
|
||||
m.patch(request_url,
|
||||
request_headers=headers)
|
||||
m.patch(user_request_url, request_headers=headers)
|
||||
[m.put(url, request_headers=headers) for url in group_request_urls[:-1]]
|
||||
m.delete(group_request_urls[-1], request_headers=headers)
|
||||
|
||||
# Act
|
||||
DiscordOAuthManager.update_groups(user_id, groups)
|
||||
|
||||
# Assert
|
||||
self.assertEqual(len(m.request_history), 1, 'Must be one HTTP call made')
|
||||
history = json.loads(m.request_history[0].text)
|
||||
self.assertIn('roles', history, "'The request must send JSON object with the 'roles' key")
|
||||
self.assertIn(111, history['roles'], 'The group id 111 must be added to the request')
|
||||
self.assertIn(222, history['roles'], 'The group id 222 must be added to the request')
|
||||
self.assertIn(333, history['roles'], 'The group id 333 must be added to the request')
|
||||
self.assertNotIn(444, history['roles'], 'The group id 444 must NOT be added to the request')
|
||||
self.assertEqual(len(m.request_history), 4, 'Must be 4 HTTP calls made')
|
||||
|
||||
@mock.patch(MODULE_PATH + '.manager.cache')
|
||||
@mock.patch(MODULE_PATH + '.manager.DiscordOAuthManager._get_groups')
|
||||
@mock.patch(MODULE_PATH + '.manager.DiscordOAuthManager._get_user_roles')
|
||||
@mock.patch(MODULE_PATH + '.manager.DiscordOAuthManager._group_name_to_id')
|
||||
@requests_mock.Mocker()
|
||||
def test_update_groups_backoff(self, group_cache, djcache, m):
|
||||
def test_update_groups_backoff(self, name_to_id, user_groups, djcache, m):
|
||||
# Arrange
|
||||
groups = ['Member']
|
||||
group_cache.return_value = [{'id': 111, 'name': 'Member'}]
|
||||
user_groups.return_value = []
|
||||
name_to_id.return_value = '111'
|
||||
|
||||
headers = {'content-type': 'application/json', 'authorization': 'Bot ' + settings.DISCORD_BOT_TOKEN}
|
||||
user_id = 12345
|
||||
request_url = '{}/guilds/{}/members/{}'.format(manager.DISCORD_URL, settings.DISCORD_GUILD_ID, user_id)
|
||||
request_url = '{}/guilds/{}/members/{}/roles/{}'.format(manager.DISCORD_URL, settings.DISCORD_GUILD_ID, user_id, name_to_id.return_value)
|
||||
|
||||
djcache.get.return_value = None # No existing backoffs in cache
|
||||
|
||||
m.patch(request_url,
|
||||
m.put(request_url,
|
||||
request_headers=headers,
|
||||
headers={'Retry-After': '200000'},
|
||||
status_code=429)
|
||||
@ -390,20 +391,22 @@ class DiscordManagerTestCase(TestCase):
|
||||
self.assertTrue(datetime.datetime.strptime(args[1], manager.cache_time_format) > datetime.datetime.now())
|
||||
|
||||
@mock.patch(MODULE_PATH + '.manager.cache')
|
||||
@mock.patch(MODULE_PATH + '.manager.DiscordOAuthManager._get_groups')
|
||||
@mock.patch(MODULE_PATH + '.manager.DiscordOAuthManager._get_user_roles')
|
||||
@mock.patch(MODULE_PATH + '.manager.DiscordOAuthManager._group_name_to_id')
|
||||
@requests_mock.Mocker()
|
||||
def test_update_groups_global_backoff(self, group_cache, djcache, m):
|
||||
def test_update_groups_global_backoff(self, name_to_id, user_groups, djcache, m):
|
||||
# Arrange
|
||||
groups = ['Member']
|
||||
group_cache.return_value = [{'id': 111, 'name': 'Member'}]
|
||||
user_groups.return_value = []
|
||||
name_to_id.return_value = '111'
|
||||
|
||||
headers = {'content-type': 'application/json', 'authorization': 'Bot ' + settings.DISCORD_BOT_TOKEN}
|
||||
user_id = 12345
|
||||
request_url = '{}/guilds/{}/members/{}'.format(manager.DISCORD_URL, settings.DISCORD_GUILD_ID, user_id)
|
||||
request_url = '{}/guilds/{}/members/{}/roles/{}'.format(manager.DISCORD_URL, settings.DISCORD_GUILD_ID, user_id, name_to_id.return_value)
|
||||
|
||||
djcache.get.return_value = None # No existing backoffs in cache
|
||||
|
||||
m.patch(request_url,
|
||||
m.put(request_url,
|
||||
request_headers=headers,
|
||||
headers={'Retry-After': '200000', 'X-RateLimit-Global': 'true'},
|
||||
status_code=429)
|
||||
|
@ -4,16 +4,20 @@ import string
|
||||
import re
|
||||
from django.db import connections
|
||||
from passlib.hash import bcrypt
|
||||
from django.conf import settings
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
TABLE_PREFIX = getattr(settings, 'IPS4_TABLE_PREFIX', '')
|
||||
|
||||
|
||||
class Ips4Manager:
|
||||
SQL_ADD_USER = r"INSERT INTO core_members (name, email, members_pass_hash, members_pass_salt, " \
|
||||
r"member_group_id) VALUES (%s, %s, %s, %s, %s)"
|
||||
SQL_GET_ID = r"SELECT member_id FROM core_members WHERE name = %s"
|
||||
SQL_UPDATE_PASSWORD = r"UPDATE core_members SET members_pass_hash = %s, members_pass_salt = %s WHERE name = %s"
|
||||
SQL_DEL_USER = r"DELETE FROM core_members WHERE member_id = %s"
|
||||
SQL_ADD_USER = r"INSERT INTO %score_members (name, email, members_pass_hash, members_pass_salt, " \
|
||||
r"member_group_id) VALUES (%%s, %%s, %%s, %%s, %%s)" % TABLE_PREFIX
|
||||
SQL_GET_ID = r"SELECT member_id FROM %score_members WHERE name = %%s" % TABLE_PREFIX
|
||||
SQL_UPDATE_PASSWORD = r"UPDATE %score_members SET members_pass_hash = %%s, members_pass_salt = %%s WHERE name = %%s" % TABLE_PREFIX
|
||||
SQL_DEL_USER = r"DELETE FROM %score_members WHERE member_id = %%s" % TABLE_PREFIX
|
||||
|
||||
MEMBER_GROUP_ID = 3
|
||||
|
||||
|
@ -5,26 +5,30 @@ import re
|
||||
|
||||
from django.db import connections
|
||||
from passlib.hash import bcrypt
|
||||
from django.conf import settings
|
||||
|
||||
# requires yum install libffi-devel and pip install bcrypt
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
TABLE_PREFIX = getattr(settings, 'MARKET_TABLE_PREFIX', 'fos_')
|
||||
|
||||
|
||||
class MarketManager:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
SQL_ADD_USER = r"INSERT INTO fos_user (username, username_canonical, email, email_canonical, enabled, salt," \
|
||||
SQL_ADD_USER = r"INSERT INTO %suser (username, username_canonical, email, email_canonical, enabled, salt," \
|
||||
r"password, locked, expired, roles, credentials_expired, characterid, characterName)" \
|
||||
r"VALUES (%s, %s, %s, %s, 1,%s, %s, 0, 0, 'a:0:{}', 0, %s, %s) "
|
||||
SQL_GET_USER_ID = r"SELECT id FROM fos_user WHERE username = %s"
|
||||
SQL_DISABLE_USER = r"UPDATE fos_user SET enabled = '0' WHERE username = %s"
|
||||
SQL_ENABLE_USER = r"UPDATE fos_user SET enabled = '1' WHERE username = %s"
|
||||
SQL_UPDATE_PASSWORD = r"UPDATE fos_user SET password = %s, salt = %s WHERE username = %s"
|
||||
SQL_CHECK_EMAIL = r"SELECT email FROM fos_user WHERE email = %s"
|
||||
SQL_CHECK_USERNAME = r"SELECT username FROM fos_user WHERE username = %s"
|
||||
SQL_UPDATE_USER = r"UPDATE fos_user SET password = %s, salt = %s, enabled = '1' WHERE username = %s"
|
||||
r"VALUES (%%s, %%s, %%s, %%s, 1,%%s, %%s, 0, 0, 'a:0:{}', 0, %%s, %%s) " % TABLE_PREFIX
|
||||
SQL_GET_USER_ID = r"SELECT id FROM %suser WHERE username = %%s" % TABLE_PREFIX
|
||||
SQL_DISABLE_USER = r"UPDATE %suser SET enabled = '0' WHERE username = %%s" % TABLE_PREFIX
|
||||
SQL_ENABLE_USER = r"UPDATE %suser SET enabled = '1' WHERE username = %%s" % TABLE_PREFIX
|
||||
SQL_UPDATE_PASSWORD = r"UPDATE %suser SET password = %%s, salt = %%s WHERE username = %%s" % TABLE_PREFIX
|
||||
SQL_CHECK_EMAIL = r"SELECT email FROM %suser WHERE email = %%s" % TABLE_PREFIX
|
||||
SQL_CHECK_USERNAME = r"SELECT username FROM %suser WHERE username = %%s" % TABLE_PREFIX
|
||||
SQL_UPDATE_USER = r"UPDATE %suser SET password = %%s, salt = %%s, enabled = '1' WHERE username = %%s" % TABLE_PREFIX
|
||||
|
||||
@staticmethod
|
||||
def __santatize_username(username):
|
||||
|
@ -14,40 +14,43 @@ from django.conf import settings
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
TABLE_PREFIX = getattr(settings, 'PHPBB3_TABLE_PREFIX', 'phpbb_')
|
||||
|
||||
|
||||
class Phpbb3Manager:
|
||||
SQL_ADD_USER = r"INSERT INTO phpbb_users (username, username_clean, " \
|
||||
SQL_ADD_USER = r"INSERT INTO %susers (username, username_clean, " \
|
||||
r"user_password, user_email, group_id, user_regdate, user_permissions, " \
|
||||
r"user_sig, user_lang) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, 'en')"
|
||||
r"user_sig, user_lang) VALUES (%%s, %%s, %%s, %%s, %%s, %%s, %%s, %%s, 'en')" % TABLE_PREFIX
|
||||
|
||||
SQL_DEL_USER = r"DELETE FROM phpbb_users where username = %s"
|
||||
SQL_DEL_USER = r"DELETE FROM %susers where username = %%s" % TABLE_PREFIX
|
||||
|
||||
SQL_DIS_USER = r"UPDATE phpbb_users SET user_email= %s, user_password=%s WHERE username = %s"
|
||||
SQL_DIS_USER = r"UPDATE %susers SET user_email= %%s, user_password=%%s WHERE username = %%s" % TABLE_PREFIX
|
||||
|
||||
SQL_USER_ID_FROM_USERNAME = r"SELECT user_id from phpbb_users WHERE username = %s"
|
||||
SQL_USER_ID_FROM_USERNAME = r"SELECT user_id from %susers WHERE username = %%s" % TABLE_PREFIX
|
||||
|
||||
SQL_ADD_USER_GROUP = r"INSERT INTO phpbb_user_group (group_id, user_id, user_pending) VALUES (%s, %s, %s)"
|
||||
SQL_ADD_USER_GROUP = r"INSERT INTO %suser_group (group_id, user_id, user_pending) VALUES (%%s, %%s, %%s)" % TABLE_PREFIX
|
||||
|
||||
SQL_GET_GROUP_ID = r"SELECT group_id from phpbb_groups WHERE group_name = %s"
|
||||
SQL_GET_GROUP_ID = r"SELECT group_id from %sgroups WHERE group_name = %%s" % TABLE_PREFIX
|
||||
|
||||
SQL_ADD_GROUP = r"INSERT INTO phpbb_groups (group_name,group_desc,group_legend) VALUES (%s,%s,0)"
|
||||
SQL_ADD_GROUP = r"INSERT INTO %sgroups (group_name,group_desc,group_legend) VALUES (%%s,%%s,0)" % TABLE_PREFIX
|
||||
|
||||
SQL_UPDATE_USER_PASSWORD = r"UPDATE phpbb_users SET user_password = %s WHERE username = %s"
|
||||
SQL_UPDATE_USER_PASSWORD = r"UPDATE %susers SET user_password = %%s WHERE username = %%s" % TABLE_PREFIX
|
||||
|
||||
SQL_REMOVE_USER_GROUP = r"DELETE FROM phpbb_user_group WHERE user_id=%s AND group_id=%s "
|
||||
SQL_REMOVE_USER_GROUP = r"DELETE FROM %suser_group WHERE user_id=%%s AND group_id=%%s " % TABLE_PREFIX
|
||||
|
||||
SQL_GET_ALL_GROUPS = r"SELECT group_id, group_name FROM phpbb_groups"
|
||||
SQL_GET_ALL_GROUPS = r"SELECT group_id, group_name FROM %sgroups" % TABLE_PREFIX
|
||||
|
||||
SQL_GET_USER_GROUPS = r"SELECT phpbb_groups.group_name FROM phpbb_groups , phpbb_user_group WHERE " \
|
||||
r"phpbb_user_group.group_id = phpbb_groups.group_id AND user_id=%s"
|
||||
SQL_GET_USER_GROUPS = r"SELECT %(prefix)sgroups.group_name FROM %(prefix)sgroups , %(prefix)suser_group WHERE " \
|
||||
r"%(prefix)suser_group.group_id = %(prefix)sgroups.group_id AND user_id=%%s" % {'prefix': TABLE_PREFIX}
|
||||
|
||||
SQL_ADD_USER_AVATAR = r"UPDATE phpbb_users SET user_avatar_type=2, user_avatar_width=64, user_avatar_height=64, " \
|
||||
"user_avatar=%s WHERE user_id = %s"
|
||||
SQL_ADD_USER_AVATAR = r"UPDATE %susers SET user_avatar_type=2, user_avatar_width=64, user_avatar_height=64, " \
|
||||
"user_avatar=%%s WHERE user_id = %%s" % TABLE_PREFIX
|
||||
|
||||
SQL_CLEAR_USER_PERMISSIONS = r"UPDATE phpbb_users SET user_permissions = '' WHERE user_Id = %s"
|
||||
SQL_CLEAR_USER_PERMISSIONS = r"UPDATE %susers SET user_permissions = '' WHERE user_id = %%s" % TABLE_PREFIX
|
||||
|
||||
SQL_DEL_SESSION = r"DELETE FROM phpbb_sessions where session_user_id = %s"
|
||||
SQL_DEL_SESSION = r"DELETE FROM %ssessions where session_user_id = %%s" % TABLE_PREFIX
|
||||
|
||||
SQL_DEL_AUTOLOGIN = r"DELETE FROM phpbb_sessions_keys where user_id = %s"
|
||||
SQL_DEL_AUTOLOGIN = r"DELETE FROM %ssessions_keys where user_id = %%s" % TABLE_PREFIX
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
@ -12,35 +12,38 @@ from django.conf import settings
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
TABLE_PREFIX = getattr(settings, 'SMF_TABLE_PREFIX', 'smf_')
|
||||
|
||||
|
||||
class SmfManager:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
SQL_ADD_USER = r"INSERT INTO smf_members (member_name, passwd, email_address, date_registered, real_name," \
|
||||
SQL_ADD_USER = r"INSERT INTO %smembers (member_name, passwd, email_address, date_registered, real_name," \
|
||||
r" buddy_list, message_labels, openid_uri, signature, ignore_boards) " \
|
||||
r"VALUES (%s, %s, %s, %s, %s, 0, 0, 0, 0, 0)"
|
||||
r"VALUES (%%s, %%s, %%s, %%s, %%s, 0, 0, 0, 0, 0)" % TABLE_PREFIX
|
||||
|
||||
SQL_DEL_USER = r"DELETE FROM smf_members where member_name = %s"
|
||||
SQL_DEL_USER = r"DELETE FROM %smembers where member_name = %%s" % TABLE_PREFIX
|
||||
|
||||
SQL_DIS_USER = r"UPDATE smf_members SET email_address = %s, passwd = %s WHERE member_name = %s"
|
||||
SQL_DIS_USER = r"UPDATE %smembers SET email_address = %%s, passwd = %%s WHERE member_name = %%s" % TABLE_PREFIX
|
||||
|
||||
SQL_USER_ID_FROM_USERNAME = r"SELECT id_member from smf_members WHERE member_name = %s"
|
||||
SQL_USER_ID_FROM_USERNAME = r"SELECT id_member from %smembers WHERE member_name = %%s" % TABLE_PREFIX
|
||||
|
||||
SQL_ADD_USER_GROUP = r"UPDATE smf_members SET additional_groups = %s WHERE id_member = %s"
|
||||
SQL_ADD_USER_GROUP = r"UPDATE %smembers SET additional_groups = %%s WHERE id_member = %%s" % TABLE_PREFIX
|
||||
|
||||
SQL_GET_GROUP_ID = r"SELECT id_group from smf_membergroups WHERE group_name = %s"
|
||||
SQL_GET_GROUP_ID = r"SELECT id_group from %smembergroups WHERE group_name = %%s" % TABLE_PREFIX
|
||||
|
||||
SQL_ADD_GROUP = r"INSERT INTO smf_membergroups (group_name,description) VALUES (%s,%s)"
|
||||
SQL_ADD_GROUP = r"INSERT INTO %smembergroups (group_name,description) VALUES (%%s,%%s)" % TABLE_PREFIX
|
||||
|
||||
SQL_UPDATE_USER_PASSWORD = r"UPDATE smf_members SET passwd = %s WHERE member_name = %s"
|
||||
SQL_UPDATE_USER_PASSWORD = r"UPDATE %smembers SET passwd = %%s WHERE member_name = %%s" % TABLE_PREFIX
|
||||
|
||||
SQL_REMOVE_USER_GROUP = r"UPDATE smf_members SET additional_groups = %s WHERE id_member = %s"
|
||||
SQL_REMOVE_USER_GROUP = r"UPDATE %smembers SET additional_groups = %%s WHERE id_member = %%s" % TABLE_PREFIX
|
||||
|
||||
SQL_GET_ALL_GROUPS = r"SELECT id_group, group_name FROM smf_membergroups"
|
||||
SQL_GET_ALL_GROUPS = r"SELECT id_group, group_name FROM %smembergroups" % TABLE_PREFIX
|
||||
|
||||
SQL_GET_USER_GROUPS = r"SELECT additional_groups FROM smf_members WHERE id_member = %s"
|
||||
SQL_GET_USER_GROUPS = r"SELECT additional_groups FROM %smembers WHERE id_member = %%s" % TABLE_PREFIX
|
||||
|
||||
SQL_ADD_USER_AVATAR = r"UPDATE smf_members SET avatar = %s WHERE id_member = %s"
|
||||
SQL_ADD_USER_AVATAR = r"UPDATE %smembers SET avatar = %%s WHERE id_member = %%s" % TABLE_PREFIX
|
||||
|
||||
@staticmethod
|
||||
def _sanitize_groupname(name):
|
||||
|
@ -9,9 +9,9 @@ import allianceauth.authentication.urls
|
||||
import allianceauth.notifications.urls
|
||||
import allianceauth.groupmanagement.urls
|
||||
import allianceauth.services.urls
|
||||
from allianceauth.authentication.decorators import main_character_required, decorate_url_patterns
|
||||
from allianceauth import NAME
|
||||
from allianceauth import views
|
||||
|
||||
from allianceauth.authentication import hmac_urls
|
||||
from allianceauth.hooks import get_hooks
|
||||
|
||||
@ -42,13 +42,14 @@ urlpatterns = [
|
||||
url(r'', include(allianceauth.groupmanagement.urls)),
|
||||
|
||||
# Services
|
||||
url(r'', include(allianceauth.services.urls)),
|
||||
url(r'', decorate_url_patterns(allianceauth.services.urls.urlpatterns, main_character_required)),
|
||||
|
||||
# Night mode
|
||||
url(r'^night/', views.NightModeRedirectView.as_view(), name='nightmode')
|
||||
]
|
||||
|
||||
|
||||
# Append app urls
|
||||
app_urls = get_hooks('url_hook')
|
||||
for app in app_urls:
|
||||
urlpatterns += [app().include_pattern]
|
||||
urlpatterns += [url(r'', decorate_url_patterns([app().include_pattern], main_character_required))]
|
||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1,10 +1,5 @@
|
||||
# Menu Hooks
|
||||
|
||||
```eval_rst
|
||||
.. note::
|
||||
Currently most menu items are statically defined in the `base.html` template. Ideally this behaviour will change over time with each module of Alliance Auth providing all of its menu items via the hook. New modules should aim to use the hook over statically adding menu items to the base template.
|
||||
```
|
||||
|
||||
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:
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
```eval_rst
|
||||
.. note::
|
||||
Currently most URL patterns are statically defined in the project's core urls.py file. Ideally this behaviour will change over time with each module of Alliance Auth providing all of its menu items via the hook. New modules should aim to use the hook over statically adding URL patterns to the project's patterns.
|
||||
URLs added through URL Hooks are protected by a decorator which ensures the requesting user is logged in and has a main character set.
|
||||
```
|
||||
|
||||
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.
|
||||
|
@ -10,7 +10,7 @@ Auto groups allows you to automatically place users of certain states into Corp
|
||||
|
||||
## Installation
|
||||
|
||||
Add `allianceauth.eveonline.autogroups` to your `INSTALLED_APPS` and run migrations. All other settings are controlled via the admin panel under the `Eve_Autogroups` section.
|
||||
Add `'allianceauth.eveonline.autogroups',` to your `INSTALLED_APPS` list and run migrations. All other settings are controlled via the admin panel under the `Eve_Autogroups` section.
|
||||
|
||||
|
||||
## Configuring a group
|
||||
|
@ -4,11 +4,9 @@ This module is used to check the registration status of corp members and to dete
|
||||
|
||||
## Installation
|
||||
|
||||
Add `allianceauth.corputils` to your `INSTALLED_APPS` setting and run migrations. In `myauth/settings/local.py`:
|
||||
Corp Stats requires access to the `esi-corporations.read_corporation_membership.v1` SSO scope. Update your application on the [EVE Developers site](https://developers.eveonline.com) to ensure it is available.
|
||||
|
||||
INSTALLED_APPS += ['allianceauth.corputils']
|
||||
|
||||
Run migrations to complete installation.
|
||||
Add `'allianceauth.corputils',` to your `INSTALLED_APPS` list in your auth project's settings file. Run migrations to complete installation.
|
||||
|
||||
## Creating a Corp Stats
|
||||
|
||||
|
@ -2,8 +2,6 @@
|
||||
|
||||
## Installation
|
||||
|
||||
Add `allianceauth.fleetactivitytracking` to your `INSTALLED_APPS` setting. In `myauth/settings/local.py`:
|
||||
Fleet Activity Tracking requires access to the `esi-location.read_location.v1`, `esi-location.read_ship_type.v1`, and `esi-universe.read_structures.v1` SSO scopes. Update your application on the [EVE Developers site](https://developers.eveonline.com) to ensure these are available.
|
||||
|
||||
INSTALLED_APPS += ['allianceauth.fleetactivitytracking']
|
||||
|
||||
Run migrations to complete installation.
|
||||
Add `'allianceauth.fleetactivitytracking',` to your `INSTALLED_APPS` list in your auth project's settings file. Run migrations to complete installation.
|
@ -2,9 +2,7 @@
|
||||
|
||||
## Installation
|
||||
|
||||
Add `allianceauth.fleetup` to your auth project's `INSTALLED_APPS` setting.
|
||||
|
||||
INSTALLED_APPS += ['allianceauth.fleetup']
|
||||
Add `'allianceauth.fleetup',` to your auth project's `INSTALLED_APPS` list.
|
||||
|
||||
Additional settings are required. Append the following settings to the end of your auth project's settings file and fill them out.
|
||||
|
||||
|
@ -2,11 +2,7 @@
|
||||
|
||||
## Installation
|
||||
|
||||
Add `allianceauth.hrapplications` to your `INSTALLED_APPS` setting. In `myauth/settings/local.py`:
|
||||
|
||||
INSTALLED_APPS += ['allianceauth.hrapplications']
|
||||
|
||||
Run migrations to complete installation.
|
||||
Add `'allianceauth.hrapplications',` to your `INSTALLED_APPS` list in your auth project's settings file. Run migrations to complete installation.
|
||||
|
||||
## Management
|
||||
|
||||
|
@ -2,8 +2,4 @@
|
||||
|
||||
## Installation
|
||||
|
||||
Add `allianceauth.optimer` to your `INSTALLED_APPS` setting. In `myauth/settings/local.py`:
|
||||
|
||||
INSTALLED_APPS += ['allianceauth.optimer']
|
||||
|
||||
Run migrations to complete installation.
|
||||
Add `'allianceauth.optimer',` to your `INSTALLED_APPS` list in your auth project's settings file. Run migrations to complete installation.
|
@ -9,9 +9,7 @@ Access to most of Alliance Auth's features are controlled by Django's permission
|
||||
|
||||
## Installation
|
||||
|
||||
Add `allianceauth.permissions_tool` to your `INSTALLED_APPS` setting. In `myauth/settings/local.py`:
|
||||
|
||||
INSTALLED_APPS += ['allianceauth.permissions_tool']
|
||||
Add `'allianceauth.permissions_tool',` to your `INSTALLED_APPS` list in your auth project's settings file.
|
||||
|
||||
## Usage
|
||||
|
||||
|
@ -2,8 +2,4 @@
|
||||
|
||||
## Installation
|
||||
|
||||
Add `allianceauth.srp` to your `INSTALLED_APPS` setting. In `myauth/settings/local.py`:
|
||||
|
||||
INSTALLED_APPS += ['allianceauth.srp']
|
||||
|
||||
Run migrations to complete installation.
|
||||
Add `'allianceauth.srp',` to your `INSTALLED_APPS` list in your auth project's settings file. Run migrations to complete installation.
|
@ -2,8 +2,4 @@
|
||||
|
||||
## Installation
|
||||
|
||||
Add `allianceauth.timerboard` to your `INSTALLED_APPS` setting. In `myauth/settings/local.py`:
|
||||
|
||||
INSTALLED_APPS += ['allianceauth.timerboard']
|
||||
|
||||
Run migrations to complete installation.
|
||||
Add `'allianceauth.timerboard',` to your `INSTALLED_APPS` list in your auth project's settings file. Run migrations to complete installation.
|
@ -66,11 +66,17 @@ CentOS:
|
||||
Alliance Auth needs a MySQL user account and database. Open an SQL shell with `mysql -u root -p` and create them as follows, replacing `PASSWORD` with an actual secure password:
|
||||
|
||||
CREATE USER 'allianceserver'@'localhost' IDENTIFIED BY 'PASSWORD';
|
||||
CREATE DATABASE alliance_auth;
|
||||
CREATE DATABASE alliance_auth CHARACTER SET utf8;
|
||||
GRANT ALL PRIVILEGES ON alliance_auth . * TO 'allianceserver'@'localhost';
|
||||
|
||||
Close the SQL shell and secure your database server with the `mysql_secure_installation` command.
|
||||
|
||||
If you're updating from v1, populate this database with a copy of the data from your v1 database.
|
||||
|
||||
mysqldump -u root -p v1_database_name_here | mysql -u root -p alliance_auth
|
||||
|
||||
Note this command will prompt you for the root password twice.
|
||||
|
||||
## Auth Install
|
||||
|
||||
### User Account
|
||||
@ -129,7 +135,6 @@ Now we need to round up all the static files required to render templates. Make
|
||||
|
||||
mkdir -p /var/www/myauth/static
|
||||
python /home/allianceserver/myauth/manage.py collectstatic
|
||||
chown -R www-data:www-data /var/www/myauth/static
|
||||
|
||||
Check to ensure your settings are valid.
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
# Apache Setup
|
||||
# Apache
|
||||
|
||||
## Overview
|
||||
|
||||
@ -20,6 +20,8 @@ CentOS:
|
||||
|
||||
## Configuration
|
||||
|
||||
Apache needs to be able to read the folder containing your auth project's static files. On Ubuntu: `chown -R www-data:www-data /var/www/myauth/static`, and on CentOS: `chown -R apache:apache /var/www/myauth/static`
|
||||
|
||||
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 eg `myauth.conf`.
|
||||
|
@ -61,7 +61,7 @@ Change it by adding `--workers=2` to the command.
|
||||
##### Running with a virtual environment
|
||||
If you're running with a virtual environment, you'll need to add the path to the `command=` config line.
|
||||
|
||||
e.g. `command=/path/to/venv/bin/gunicorn alliance_auth.wsgi`
|
||||
e.g. `command=/path/to/venv/bin/gunicorn myauth.wsgi`
|
||||
|
||||
### Starting via Supervisor
|
||||
|
||||
@ -70,48 +70,6 @@ Once you have your configuration all sorted, you will need to reload your superv
|
||||
|
||||
## Configuring your webserver
|
||||
|
||||
### NGINX
|
||||
To your server config add:
|
||||
|
||||
```
|
||||
location / {
|
||||
proxy_pass http://127.0.0.1:8000;
|
||||
proxy_read_timeout 90;
|
||||
proxy_redirect http://127.0.0.1:8000/ http://$host/;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
```
|
||||
|
||||
Set `proxy_pass` and `proxy_redirect` to the address you set under `--bind=`. Set the second part of `proxy_redirect` to the URL you're hosting services on. Tell NGINX to reload your config, job done. Enjoy your lower memory usage and better performance!
|
||||
|
||||
If PHP is stopping you moving to NGINX, check out php-fpm as a way to run your PHP applications.
|
||||
|
||||
### Apache
|
||||
If you were using mod_wsgi before, make a backup of your old config first and then strip out all of the mod_wsgi config from your Apache VirtualHost first config.
|
||||
|
||||
Your config will need something along these lines:
|
||||
```
|
||||
ProxyPreserveHost On
|
||||
<Location />
|
||||
SSLRequireSSL
|
||||
ProxyPass http://127.0.0.1:8000/
|
||||
ProxyPassReverse http://127.0.0.1:8000/
|
||||
RequestHeader set X-FORWARDED-PROTOCOL ssl
|
||||
RequestHeader set X-FORWARDED-SSL on
|
||||
</Location>
|
||||
```
|
||||
|
||||
Set `ProxyPass` and `ProxyPassReverse` addresses to your `--bind=` address set earlier.
|
||||
|
||||
You will need to enable some Apache mods. `sudo a2enmod http_proxy` should take care of the dependencies.
|
||||
|
||||
Restart Apache and you should be done.
|
||||
|
||||
### Other web servers
|
||||
|
||||
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.
|
||||
|
||||
|
||||
|
@ -31,14 +31,25 @@ Your .htaccess files wont work. Nginx has a separate way of managing access to f
|
||||
|
||||
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.
|
||||
|
||||
Nginx needs to be able to read the folder containing your auth project's static files. On Ubuntu: `chown -R nginx:nginx /var/www/myauth/static`, and on CentOS: `chown -R nginx:nginx /var/www/myauth/static`
|
||||
|
||||
You will need to have [Gunicorn](gunicorn.md) or some other WSGI server setup for hosting Alliance Auth.
|
||||
|
||||
Create a config file in `/etc/nginx/sites-available` call it `alliance-auth.conf` or whatever your preferred name is and copy the basic config in. Make whatever changes you feel are necessary.
|
||||
### Ubuntu
|
||||
Create a config file in `/etc/nginx/sites-available` and call it `alliance-auth.conf` or whatever your preferred name is.
|
||||
|
||||
Create a symbolic link to enable the site `ln -s /etc/nginx/sites-available/alliance-auth.conf /etc/nginx/sites-enabled/`
|
||||
|
||||
### CentOS
|
||||
|
||||
Create a config file in `/etc/nginx/conf.d` and call it `alliance-auth.conf` or whatever your preferred name is.
|
||||
|
||||
Create a symbolic link to enable the site `sudo ln -s /etc/nginx/sites-available/alliance-auth.conf /etc/nginx/sites-enabled/` and then reload Nginx for the config to take effect, `sudo service nginx reload` for Ubuntu.
|
||||
|
||||
### Basic config
|
||||
|
||||
Copy this basic config into your config file. Make whatever changes you feel are necessary.
|
||||
|
||||
|
||||
```
|
||||
server {
|
||||
listen 80;
|
||||
@ -59,9 +70,11 @@ server {
|
||||
}
|
||||
```
|
||||
|
||||
Restart Nginx after making changes to the config files. On Ubuntu `service nginx restart` and on CentOS `systemctl restart nginx.service`.
|
||||
|
||||
#### Adding TLS/SSL
|
||||
|
||||
With [Let's Encrypt](https://letsencrypt.org/) offering free SSL certificates, there's no good reason to not run HTTPS anymore.
|
||||
With [Let's Encrypt](https://letsencrypt.org/) offering free SSL certificates, there's no good reason to not run HTTPS anymore. The bot can automatically configure Nginx on some operating systems. If not proceed with the manual steps below.
|
||||
|
||||
Your config will need a few additions once you've got your certificate.
|
||||
|
||||
|
@ -58,6 +58,8 @@ This adds a new user to your Discord server with a `BOT` tag, and a new role wit
|
||||
|
||||
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.discordapp.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.
|
||||
|
||||
### Linking Accounts
|
||||
Instead of the usual account creation procedure, for Discord to work we need to link accounts to AllianceAuth. When attempting to enable the Discord service, users are redirected to the official Discord site to authenticate. They will need to create an account if they don't have one prior to continuing. Upon authorization, users are redirected back to AllianceAuth with an OAuth code which is used to join the Discord server.
|
||||
|
||||
|
@ -115,7 +115,7 @@ Follow prompts, being sure to answer `y` when asked to allow admin privileges.
|
||||
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:
|
||||
- `DISCOURSE_URL`: `discourse.example.com` (do not add a trailing slash!)
|
||||
- `DISCOURSE_URL`: `https://discourse.example.com` (do not add a trailing slash!)
|
||||
- `DISCOURSE_API_USERNAME`: the username of the admin account you generated the API key with
|
||||
- `DISCOURSE_API_KEY`: the key you just generated
|
||||
|
||||
|
@ -43,11 +43,11 @@ In the console, navigate to your user’s home directory: `cd ~`
|
||||
|
||||
Now download using wget, replacing the url with the url for the package you just retrieved
|
||||
|
||||
wget https://www.phpbb.com/files/release/phpBB-3.2.0.zip
|
||||
wget https://www.phpbb.com/files/release/phpBB-3.2.2.zip
|
||||
|
||||
This needs to be unpackaged. Unzip it, replacing the file name with that of the file you just downloaded
|
||||
|
||||
unzip phpBB-3.2.0.zip
|
||||
unzip phpBB-3.2.2.zip
|
||||
|
||||
Now we need to move this to our web directory. Usually `/var/www/forums`.
|
||||
|
||||
@ -115,6 +115,8 @@ Under Database Settings, set the following:
|
||||
- Database Username is your auth MySQL user, usually `allianceserver`
|
||||
- Database Password is this user’s password
|
||||
|
||||
If you use a table prefix other than the standard `phpbb_` you need to add an additional setting to your auth project's settings file, `PHPBB3_TABLE_PREFIX = ''`, and enter the prefix.
|
||||
|
||||
You should see `Succesful Connection` and proceed.
|
||||
|
||||
Enter administrator credentials on the next page.
|
||||
|
@ -104,4 +104,6 @@ Under Database Settings, set the following:
|
||||
- Database Username is your auth MySQL user, usually `allianceserver`
|
||||
- Database Password is this user’s password
|
||||
|
||||
If you use a table prefix other than the standard `smf_` you need to add an additional setting to your auth project's settings file, `SMF_TABLE_PREFIX = ''`, and enter the prefix.
|
||||
|
||||
Follow the directions in the installer.
|
@ -1,297 +0,0 @@
|
||||
# Changelog
|
||||
|
||||
## From now on all changelogs will be included as release notes.
|
||||
https://github.com/allianceauth/allianceauth/releases
|
||||
|
||||
### 547
|
||||
Oct 16
|
||||
|
||||
Golly this is a big one. Upgrading takes a bit of work. [For full instructions click here.](https://github.com/allianceauth/allianceauth/pull/547#issue-183247630)
|
||||
|
||||
- Update django version to 1.10
|
||||
- Remove member/blue permissions
|
||||
- implement user states
|
||||
- implement Django's messaging framework for site feedback
|
||||
- remove pathfinder support
|
||||
- remove fleet fits page
|
||||
- remove wormhole tracker
|
||||
- do not store service passwords
|
||||
- supervisor configs for celery tasks and authenticator
|
||||
- buttons on admin site to sync service groups
|
||||
- show number of notifications
|
||||
- fix all button css
|
||||
- rewrite and centralize API checks
|
||||
- bulk mark read / delete for notifications
|
||||
- replace hard-coded urls with reverse by name
|
||||
- python 3 compatibility
|
||||
- correct navbar active link with translated urls
|
||||
|
||||
### 468
|
||||
June 12
|
||||
- XenForo integration added
|
||||
- Discord integration updated to use OAuth and official API
|
||||
- FleetUp fixes for empty responses
|
||||
|
||||
### 441
|
||||
May 27
|
||||
- Added option to require new API keys
|
||||
- Reduces threat of stolen keys being used to create accounts
|
||||
- Requires two new settings:
|
||||
- `REJECT_OLD_APIS`, default `False`
|
||||
- `REJECT_OLD_APIS_MARGIN`, default 50
|
||||
|
||||
### 423
|
||||
May 9
|
||||
- Added statistics to fleet activity tracking
|
||||
- Capture teamspeak error codes in logs from failed account creation
|
||||
|
||||
### 401
|
||||
Apr 29
|
||||
- Added FleetUp integration
|
||||
- Added Fleet Activity Tracking links
|
||||
- settings.py has new entries and will have to be updated
|
||||
|
||||
### 394
|
||||
Apr 17
|
||||
- Added Discourse integration
|
||||
- Added Pathfinder integration
|
||||
- settings.py has new entries and will have to be updated
|
||||
|
||||
### 386
|
||||
Apr 15 2016
|
||||
- Corrected Teamspeak group sync triggers
|
||||
- Modified username sanitization to reduce username collisions
|
||||
|
||||
### 369
|
||||
Apr 7 2016
|
||||
- Added Evernus Alliance Market Integration
|
||||
- Requires libffi-devel (centos) or libffi-dev (ubuntu) and pip install bcrypt
|
||||
|
||||
### 365
|
||||
Apr 6 2016
|
||||
- Added SMF2 Forums integration
|
||||
- Requires a settings.py file update for existing installs
|
||||
|
||||
### 360
|
||||
Apr 4 2016
|
||||
- Added a countdown / local time to the fleet operations timers
|
||||
- Fixed the corporation structure timers so the countdown shows up correctly
|
||||
|
||||
### 340
|
||||
Mar 31 2016
|
||||
- Added Support for IP Board 4 / IP Suite 4
|
||||
- You must update settings.py accordingly if updating form a previous version.
|
||||
- only allows for the member group to sync. Additional groups must be manually added
|
||||
- Fixed a bug with corporation stats not showing correct users and numbers
|
||||
|
||||
### 328
|
||||
Mar 24 2016
|
||||
- Added Enhancements to the SRP Management
|
||||
- Users can now enable and disable srp links.
|
||||
- The Approve and Reject buttons will show up depending on the srp status.
|
||||
- Fixed an issue where SRP Requests were not getting the proper status assigned.
|
||||
|
||||
### 321
|
||||
Mar 23 2016
|
||||
- Added Ship types and kill board data to the SRP management.
|
||||
- These are automatically pulled from zKillboard.
|
||||
- zKillboard is the only killboard links that the SRP Manager Accepts Now.
|
||||
|
||||
### 314
|
||||
Mar 22 2016
|
||||
- Revamp of the Human Resources Application and Management System
|
||||
- see the [docs](../features/hrapplications.md) for how to use the new system
|
||||
- a completely untested conversion script exists. If you want to view your old models, contact Adarnof to try it out
|
||||
- Moved Error Handling for the API Keys to the API Calls to better handle API server outages
|
||||
- Removed the infamous database update task
|
||||
- implemented a receiver to update service groups as they change
|
||||
|
||||
To remove the database update task from the scheduler, navigate to your django admin site, and delete the run_databaseUpdate model from the periodic tasks. Restart celery.
|
||||
|
||||
Mumble now uses an ICE authenticator. This requires an additional dependency. Please install `libbz2-dev` and `libssl-dev` prior to running the update script:
|
||||
|
||||
sudo apt-get install libbz2-dev libssl-dev
|
||||
|
||||
Now run the update script.
|
||||
|
||||
Old Mumble accounts are incompatible. Users will need to recreate them (sorry). To clear the old ones out:
|
||||
|
||||
python manage.py shell
|
||||
from services.tasks import disable_mumble
|
||||
disable_mumble()
|
||||
|
||||
To set up the authenticator, follow the [Mumble setup guide.](../installation/services/mumble.md)
|
||||
|
||||
Optional: you can delete the entire mumble database block in settings.py
|
||||
|
||||
### 304
|
||||
Mar 8 2016
|
||||
- Repurposed Signature Tracker for Wormhole Use. Combat sites are a ever changing thing therefore removed.
|
||||
- Increased run_databaseUpdate time to 10 minutes to address stability problems for larger alliances.
|
||||
|
||||
### 296
|
||||
Feb 27 2016
|
||||
- corrected an issue with populating corp stats for characters with missing api keys
|
||||
- moved log files to dedicated folder to allow apache access so it can rotate them
|
||||
- merged Corp Stats and Member Tracking apps
|
||||
- `corp_stats` and `corputils` permissions have been depreciated
|
||||
- assign either of `corp_apis` or `alliance_apis` to get access to Corp Stats app
|
||||
- `corp_apis` populates APIs of user's main corp
|
||||
- `alliance_apis` populates APIs of user's main alliance
|
||||
|
||||
### 289
|
||||
Feb 25 2016
|
||||
- Changed the start time format on the fleet operations board to use the 24 hour format
|
||||
- Fixed an issue when updating the fleet operations timers the date time picker would not work.
|
||||
|
||||
### 286
|
||||
Feb 23 2016
|
||||
- Added ability to remove notifications
|
||||
|
||||
### 278
|
||||
Feb 18 2016
|
||||
- notifications for events:
|
||||
- api failed validation during refresh
|
||||
- group request accepted/rejected
|
||||
- corp application accepted/rejected
|
||||
- services disabled
|
||||
- logging notifications include traceback
|
||||
- automatically assign alliance groups of the form "Alliance_NAME"
|
||||
- parallel corp model updates via celery broker for performance improvements
|
||||
- new functions to clear service info for decommissioning a service
|
||||
|
||||
settings.py will need to be updated to include the new settings.
|
||||
|
||||
### 265
|
||||
Feb 13 2016
|
||||
- prototype notification system
|
||||
- logging errors as notifications based on new permission `logging_notifications`
|
||||
|
||||
The logging configuration in settings.py has changed. Please update.
|
||||
|
||||
### 263
|
||||
Feb 12 2016
|
||||
- revamped `run_corp_update` function which actually works
|
||||
- fixed group syncing in discord and openfire
|
||||
|
||||
### 259
|
||||
Feb 11 2016
|
||||
- Added ability to edit structure timers
|
||||
- Added ability to edit fleet operations timers
|
||||
- Added ability to edit Signatures
|
||||
|
||||
|
||||
### 245
|
||||
Feb 7 2016
|
||||
|
||||
- ability to toggle assigning corp groups
|
||||
- users able to manually trigger api refresh
|
||||
|
||||
Two new settings in [settings.py](../installation/auth/settings.md) - `MEMBER_CORP_GROUPS` and `BLUE_CORP_GROUPS` - be sure to add them.
|
||||
|
||||
### 226
|
||||
Jan 31 2016
|
||||
|
||||
Been a while since one of these was written so a big list.
|
||||
|
||||
- corrected user permission caching for Phpbb3
|
||||
- open groups which don't require application approval
|
||||
- additional weblink data for TS3 to encourage proper usernames
|
||||
- corp-restricted timers
|
||||
- signature tracker
|
||||
- tolerate random 221 errors from EVE api servers till CCP FoxFour gets it sorted
|
||||
- new corp member auditing app
|
||||
- fleet operation timers
|
||||
- revamped member status checking and assignment
|
||||
|
||||
Loads of new permissions. See the readme for descriptions.
|
||||
|
||||
Need to install new requirements - `sudo pip install -r requirements.txt`
|
||||
|
||||
Incompatible with Python2.6 or older. Please update. Please. It's 2016 people.
|
||||
|
||||
Settings.py got nuked. Backup your current settings.py, copy the example, and repopulate.
|
||||
|
||||
New caching directory for requests - if you're using apache to serve the site, `cache/` needs to be writable by the webserver. Easiest way is to `chown -R www-data:www-data cache` from within the allianceauth install dir.
|
||||
|
||||
### 145
|
||||
Jan 6 2016
|
||||
|
||||
- complete logging system for all apps
|
||||
- custom service passwords
|
||||
- Discord token caching to prevent locking out users
|
||||
- Jabber broadcast group restrictions
|
||||
- Password reset email contains domain
|
||||
- Index page only renders forums/killboard/media if url specified
|
||||
- timestamps on hrapplication comments
|
||||
- corrected corp/alliance model creation logic
|
||||
- corrected typecasting of access masks during api checks
|
||||
- prevent TS3 from attempting to sync groups if not installed
|
||||
|
||||
New permissions - see readme.
|
||||
|
||||
Need to install new requirements.
|
||||
|
||||
Settings.py has changed. Make a new one from the example.
|
||||
|
||||
### 118
|
||||
Dec 2 2015
|
||||
|
||||
- add timers by time remaining
|
||||
- Discord support
|
||||
- corrected celerytask logic
|
||||
- handle many 500s thrown in views
|
||||
|
||||
New settings.py again. Need to reinstall requirements.
|
||||
|
||||
### 107
|
||||
Nov 28 2015
|
||||
|
||||
- added broadcast plugin support for openfire
|
||||
- timer addition by remaining time, not fixed date
|
||||
- corrected alliance model deletion logic
|
||||
- corrected name rendering on templates
|
||||
|
||||
Openfire setup guide has been updated for the new plugin.
|
||||
|
||||
### 102
|
||||
Nov 25 2015
|
||||
|
||||
- variable API requirements
|
||||
- api access mask validation during refresh
|
||||
- support for customization of templates
|
||||
- celery task resource reduction
|
||||
- vagrant support
|
||||
|
||||
All templates and staticfiles have been moved. If you've customized any of these, make a backup before pulling changes.
|
||||
|
||||
New command `python manage.py collectstatic` added to install guide. Should be run after every update.
|
||||
|
||||
New settings.py template. Make a backup of the old one, copy the example, and populate.
|
||||
|
||||
### 87
|
||||
Nov 15 2015
|
||||
|
||||
A couple quality-of-life improvements.
|
||||
|
||||
- corrected an error in the Teamspeak3 Manager improperly parsing responses
|
||||
- added the ability to hide groups from the web interface
|
||||
- added a feature for phpbb avatars to be set to the character portrait
|
||||
|
||||
New permissions for the `HiddenGroup` model only affect the admin site (default model permissions)
|
||||
|
||||
The Phpbb3 setup guide has been updated to reflect avatars.
|
||||
|
||||
### 72
|
||||
Nov 5th 2015
|
||||
|
||||
On November 5th we performed two major pulls from Adarnof’s and Kaezon’s forks.
|
||||
|
||||
Improvements include:
|
||||
|
||||
- ability to deploy for either corp or alliance
|
||||
- improved logic for member status transitions
|
||||
- group syncing to TS3
|
||||
- template corrections
|
||||
|
||||
Migration to the new version is a bit trickier because of changes to settings.py - it's easiest to archive the old one, make a copy of the new template, and repopulate it.
|
@ -4,7 +4,7 @@
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
changelog
|
||||
project
|
||||
troubleshooting
|
||||
|
||||
```
|
||||
|
88
docs/maintenance/project.md
Normal file
88
docs/maintenance/project.md
Normal file
@ -0,0 +1,88 @@
|
||||
# Your Auth Project
|
||||
|
||||
## Overview
|
||||
|
||||
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
|
||||
|
||||
The first folder created is the root directory of your auth project. This folder contains:
|
||||
- the `manage.py` management script used to interact with Django
|
||||
- a preconfigured `supervisor.conf` supervisor config for running celery (and optionally gunicorn) automatically
|
||||
- a `log` folder which contains log files generated by Alliance Auth
|
||||
|
||||
### The myauth Subfolder
|
||||
|
||||
Within your auth project root folder is another folder of the same name (a quirk of django project structures). This folder contains:
|
||||
- a celery app definition in `celery.py` for registering tasks with the background workers
|
||||
- a web server gateway interface script `wsgi.py` for processing web requests
|
||||
- the root url config `urls.py` which Django uses to direct requests to the appropriate view
|
||||
|
||||
There are also two subfolders for `static` and `templates` which allow adding new content and overriding default content shipped with Alliance Auth or Django.
|
||||
|
||||
And finally the settings folder.
|
||||
|
||||
### Settings Files
|
||||
|
||||
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 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.
|
||||
|
||||
## Log Files
|
||||
|
||||
Your auth project comes with four log file definitions by default. These are created in the `myauth/log/` folder at runtime.
|
||||
|
||||
- `allianceauth.log` contains all `INFO` level and above logging messages from Alliance Auth. This is useful for tracking who is making changes to the site, what is happening to users, and debugging any errors that may occur.
|
||||
- `worker.log` contains logging messages from the celery background task workers. This is useful for monitoring background processes such as group syncing to services.
|
||||
- `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.
|
||||
|
||||
## 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.
|
||||
|
||||
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.
|
||||
|
||||
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/allinceauth/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:
|
||||
|
||||
```
|
||||
import allianceauth.urls
|
||||
|
||||
urlpatterns = [
|
||||
url(r'', include(allianceauth.urls)),
|
||||
]
|
||||
```
|
||||
|
||||
This means every request gets passed to the Alliance Auth URL config to be interpreted.
|
||||
|
||||
If you wanted to add a URL pointing to a custom view, it can be added anywhere in the list if not already used by Alliance Auth:
|
||||
|
||||
```
|
||||
import allianceauth.urls
|
||||
import myauth.views
|
||||
|
||||
urlpatterns = [
|
||||
url(r'', include(allianceauth.urls)),
|
||||
url(r'myview/$', myauth.views.myview, name='myview'),
|
||||
]
|
||||
```
|
||||
|
||||
Additionally you can override URLs used by Alliance Auth here:
|
||||
|
||||
```
|
||||
import allianceauth.urls
|
||||
import myauth.views
|
||||
|
||||
urlpatterns = [
|
||||
url(r'account/login/$', myauth.views.login, name='auth_login_user'),
|
||||
url(r'', include(allianceauth.urls)),
|
||||
]
|
||||
```
|
@ -2,44 +2,41 @@
|
||||
|
||||
## Something broken? Stuck on an issue? Can't get it set up?
|
||||
|
||||
Start here:
|
||||
- check the [issues](https://github.com/allianceauth/allianceauth/issues?utf8=%E2%9C%93&q=is%3Aissue) - especially closed ones
|
||||
- check the [forums](https://forums.eveonline.com/default.aspx?g=posts&t=383030)
|
||||
Start by checking the [issues](https://github.com/allianceauth/allianceauth/issues?utf8=%E2%9C%93&q=is%3Aissue) - especially closed ones.
|
||||
|
||||
No answer?
|
||||
- open an [issue](https://github.com/allianceauth/allianceauth/issues)
|
||||
- harass us on [gitter](https://gitter.im/R4stl1n/allianceauth)
|
||||
- post to the [forums](https://forums.eveonline.com/default.aspx?g=posts&t=383030)
|
||||
|
||||
## Common Problems
|
||||
|
||||
### `pip install -r requirements.txt` is failing
|
||||
|
||||
Either you need to `sudo` that command, or it's a missing dependency. Check [the list](../installation/auth/dependencies.md), reinstall, and try again.
|
||||
It's probably a permissions issue. Ensure your current user can write to the virtual environment folder. That, or you're missing a dependency of some kind which will be indicated in the error message.
|
||||
|
||||
### I'm getting an error 500 trying to connect to the website on a new install
|
||||
|
||||
Read the apache error log: `sudo less /var/log/apache2/error.log`. Press Shift+G to go to the end of the file.
|
||||
|
||||
If it talks about failing to import something, google its name and install it.
|
||||
|
||||
If it whines about being unable to configure logger, see below.
|
||||
*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.
|
||||
|
||||
### Failed to configure log handler
|
||||
|
||||
Make sure the log directory is write-able: `chmod -R 777 /home/allianceserver/allianceauth/log`, then reload apache/celery/supervisor/etc.
|
||||
Make sure the log directory is write-able by the allianceserver user: `chmown -R allianceserver:allianceserver /path/to/myauth/log/`, then restart the auth supervisor processes.
|
||||
|
||||
### Groups aren't syncing to services
|
||||
|
||||
Make sure the background processes are running: `ps aux | grep celery` should return more than 1 line. More lines if you have more cores on your server's processor. If there are more than two lines starting with `SCREEN`, kill all of them with `kill #` where `#` is the process ID (second column), then restart with [these background process commands](../installation/auth/quickstart.md) from the allianceauth directory. You can't start these commands as root.
|
||||
Make sure the background processes are running: `supervisorctl status myauth:`. If `myauth:worker` or `myauth:beat` do not show `RUNNING` read their log files to identify why.
|
||||
|
||||
If that doesn't do it, try clearing the worker queue. First kill all celery processes as described above, then do the following:
|
||||
### Task queue is way too large
|
||||
|
||||
Stop celery workers with `supervisorctl stop myauth:worker` then clear the queue:
|
||||
|
||||
redis-cli FLUSHALL
|
||||
celery -A alliance_auth worker --purge
|
||||
celery -A myauth worker --purge
|
||||
|
||||
Press Control+C once.
|
||||
|
||||
Now start celery again with [these background process commands.](../installation/auth/quickstart.md)
|
||||
Now start the worker again with `supervisorctl start myauth:worker`
|
||||
|
||||
While debugging, it is useful to see if tasks are being executed. The easiest tool is [flower](http://flower.readthedocs.io/). Install it with this: `sudo pip install flower`, then start it with this: `celery flower --broker=amqp://guest:guest@localhost:5672//`. To view the status, navigate to your server IP, port 5555.
|
||||
### Proxy timeout when entering email address
|
||||
|
||||
This usually indicates an issue with your email settings. Ensure these are correct and your email server/service is properly configured.
|
||||
|
2
setup.py
2
setup.py
@ -40,7 +40,7 @@ setup(
|
||||
version=allianceauth.__version__,
|
||||
author='Alliance Auth',
|
||||
author_email='adarnof@gmail.com',
|
||||
description='Eve alliance auth for the 99 percent',
|
||||
description='An auth system for EVE Online to help in-game organizations manage online service access.',
|
||||
install_requires=install_requires,
|
||||
extras_require={
|
||||
'testing': testing_extras,
|
||||
|
Loading…
x
Reference in New Issue
Block a user