mirror of
https://gitlab.com/allianceauth/allianceauth.git
synced 2026-02-04 14:16:21 +01:00
Compare commits
79 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
399ef1917d | ||
|
|
9db443ba54 | ||
|
|
0f2f5ea0ba | ||
|
|
1f781c5037 | ||
|
|
36dedfcbd2 | ||
|
|
13a05606fb | ||
|
|
90ad7790e1 | ||
|
|
6b8341ab5a | ||
|
|
d15f42b3fd | ||
|
|
cc60b26f5a | ||
|
|
36ff0af993 | ||
|
|
f17c94a9e1 | ||
|
|
7e3ba476f3 | ||
|
|
dd1313a2a9 | ||
|
|
763003bd7d | ||
|
|
f3217443dd | ||
|
|
a713ae1914 | ||
|
|
5815bac0df | ||
|
|
6154d2c2e7 | ||
|
|
b34661b35d | ||
|
|
a9a7e03b80 | ||
|
|
23c797ef64 | ||
|
|
da102618a0 | ||
|
|
51ee281b14 | ||
|
|
9133232c20 | ||
|
|
9cbabee126 | ||
|
|
4026523a2e | ||
|
|
7fbf96623b | ||
|
|
273bda173e | ||
|
|
7bd5838ea1 | ||
|
|
b232d9ab17 | ||
|
|
a11b870664 | ||
|
|
a27aae5d1c | ||
|
|
117ef63d90 | ||
|
|
1bde3d5672 | ||
|
|
d2355b1ec8 | ||
|
|
191d474a8e | ||
|
|
ec9a9733be | ||
|
|
cf7a8cedf1 | ||
|
|
18cbb994d5 | ||
|
|
663388a0c2 | ||
|
|
7a943591ec | ||
|
|
cd189927fe | ||
|
|
8772349309 | ||
|
|
cf20100cb5 | ||
|
|
9b9c2ddc04 | ||
|
|
34839e8344 | ||
|
|
89ef4f4cbc | ||
|
|
2cc7f46aae | ||
|
|
8d255fb720 | ||
|
|
67cf68ad87 | ||
|
|
db1971d4c2 | ||
|
|
63c1521cba | ||
|
|
ba7ef11505 | ||
|
|
d2e494b9be | ||
|
|
98bab0b180 | ||
|
|
c4efb2a11f | ||
|
|
94e4895f29 | ||
|
|
70eb1b5b50 | ||
|
|
e247a94db3 | ||
|
|
714431c932 | ||
|
|
b026277ab0 | ||
|
|
11855f0b54 | ||
|
|
635fbfe2c8 | ||
|
|
b10233daf0 | ||
|
|
1aa3187491 | ||
|
|
59f17a88f0 | ||
|
|
75db3195d4 | ||
|
|
afe3fea757 | ||
|
|
1072c00a28 | ||
|
|
b221c1ce24 | ||
|
|
1617c775ee | ||
|
|
cc88a02001 | ||
|
|
ae5d0f4a2f | ||
|
|
067e2c424e | ||
|
|
d64675a3b0 | ||
|
|
17a6b3225e | ||
|
|
b83f591dc2 | ||
|
|
74651dd30a |
@@ -13,9 +13,23 @@ repos:
|
||||
- id: check-yaml
|
||||
- id: fix-byte-order-marker
|
||||
- id: trailing-whitespace
|
||||
exclude: (\.min\.css|\.min\.js|\.mo|\.po|swagger\.json)$
|
||||
exclude: |
|
||||
(?x)(
|
||||
\.min\.css|
|
||||
\.min\.js|
|
||||
\.po|
|
||||
\.mo|
|
||||
swagger\.json
|
||||
)
|
||||
- id: end-of-file-fixer
|
||||
exclude: (\.min\.css|\.min\.js|\.mo|\.po|swagger\.json)$
|
||||
exclude: |
|
||||
(?x)(
|
||||
\.min\.css|
|
||||
\.min\.js|
|
||||
\.po|
|
||||
\.mo|
|
||||
swagger\.json
|
||||
)
|
||||
- id: mixed-line-ending
|
||||
args: [ '--fix=lf' ]
|
||||
- id: fix-encoding-pragma
|
||||
@@ -25,7 +39,14 @@ repos:
|
||||
rev: 2.4.0
|
||||
hooks:
|
||||
- id: editorconfig-checker
|
||||
exclude: ^(LICENSE|allianceauth\/static\/allianceauth\/css\/themes\/bootstrap-locals.less|allianceauth\/eveonline\/swagger.json|(.*.po)|(.*.mo))
|
||||
exclude: |
|
||||
(?x)(
|
||||
LICENSE|
|
||||
allianceauth\/static\/allianceauth\/css\/themes\/bootstrap-locals.less|
|
||||
\.po|
|
||||
\.mo|
|
||||
swagger\.json
|
||||
)
|
||||
|
||||
- repo: https://github.com/asottile/pyupgrade
|
||||
rev: v2.34.0
|
||||
|
||||
7
MANIFEST.in
Normal file
7
MANIFEST.in
Normal file
@@ -0,0 +1,7 @@
|
||||
include LICENSE
|
||||
include README.md
|
||||
include MANIFEST.in
|
||||
graft allianceauth
|
||||
|
||||
global-exclude __pycache__
|
||||
global-exclude *.py[co]
|
||||
@@ -1,7 +1,7 @@
|
||||
# This will make sure the app is always imported when
|
||||
# Django starts so that shared_task will use this app.
|
||||
|
||||
__version__ = '3.0.0'
|
||||
__version__ = '3.3.0'
|
||||
__title__ = 'Alliance Auth'
|
||||
__url__ = 'https://gitlab.com/allianceauth/allianceauth'
|
||||
NAME = f'{__title__} v{__version__}'
|
||||
|
||||
@@ -8,13 +8,13 @@ from uuid import uuid4
|
||||
class AnalyticsIdentifier(models.Model):
|
||||
|
||||
identifier = models.UUIDField(default=uuid4,
|
||||
editable=False)
|
||||
editable=False)
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
if not self.pk and AnalyticsIdentifier.objects.exists():
|
||||
# Force a single object
|
||||
raise ValidationError('There is can be only one \
|
||||
AnalyticsIdentifier instance')
|
||||
AnalyticsIdentifier instance')
|
||||
self.pk = self.id = 1 # If this happens to be deleted and recreated, force it to be 1
|
||||
return super().save(*args, **kwargs)
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ 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
|
||||
|
||||
@@ -37,7 +38,13 @@ class StateBackend(ModelBackend):
|
||||
ownership = CharacterOwnership.objects.get(character__character_id=token.character_id)
|
||||
if ownership.owner_hash == token.character_owner_hash:
|
||||
logger.debug(f'Authenticating {ownership.user} by ownership of character {token.character_name}')
|
||||
return ownership.user
|
||||
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.")
|
||||
return None
|
||||
else:
|
||||
logger.debug(f'{token.character_name} has changed ownership. Creating new user account.')
|
||||
ownership.delete()
|
||||
@@ -57,13 +64,20 @@ class StateBackend(ModelBackend):
|
||||
if records.exists():
|
||||
# we've seen this character owner before. Re-attach to their old user account
|
||||
user = records[0].user
|
||||
if user.profile.main_character:
|
||||
if ownership.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.")
|
||||
return None
|
||||
|
||||
token.user = user
|
||||
co = CharacterOwnership.objects.create_by_token(token)
|
||||
logger.debug(f'Authenticating {user} by matching owner hash record of character {co.character}')
|
||||
if not user.profile.main_character:
|
||||
# set this as their main by default if they have none
|
||||
user.profile.main_character = co.character
|
||||
user.profile.save()
|
||||
|
||||
# set this as their main by default as they have none
|
||||
user.profile.main_character = co.character
|
||||
user.profile.save()
|
||||
return user
|
||||
logger.debug(f'Unable to authenticate character {token.character_name}. Creating new user.')
|
||||
return self.create_user(token)
|
||||
|
||||
@@ -18,13 +18,13 @@ class State(models.Model):
|
||||
priority = models.IntegerField(unique=True, help_text="Users get assigned the state with the highest priority available to them.")
|
||||
|
||||
member_characters = models.ManyToManyField(EveCharacter, blank=True,
|
||||
help_text="Characters to which this state is available.")
|
||||
help_text="Characters to which this state is available.")
|
||||
member_corporations = models.ManyToManyField(EveCorporationInfo, blank=True,
|
||||
help_text="Corporations to whose members this state is available.")
|
||||
help_text="Corporations to whose members this state is available.")
|
||||
member_alliances = models.ManyToManyField(EveAllianceInfo, blank=True,
|
||||
help_text="Alliances to whose members this state is available.")
|
||||
help_text="Alliances to whose members this state is available.")
|
||||
member_factions = models.ManyToManyField(EveFactionInfo, blank=True,
|
||||
help_text="Factions to whose members this state is available.")
|
||||
help_text="Factions to whose members this state is available.")
|
||||
public = models.BooleanField(default=False, help_text="Make this state available to any character.")
|
||||
|
||||
objects = StateManager()
|
||||
|
||||
@@ -6,24 +6,26 @@ CSS for allianceauth admin site
|
||||
.img-circle {
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.column-user_profile_pic {
|
||||
width: 1px;
|
||||
white-space: nowrap;
|
||||
width: 1px;
|
||||
}
|
||||
|
||||
/* tooltip */
|
||||
.tooltip {
|
||||
position: relative ;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.tooltip:hover::after {
|
||||
content: attr(data-tooltip) ;
|
||||
position: absolute ;
|
||||
top: 1.1em ;
|
||||
left: 1em ;
|
||||
min-width: 200px ;
|
||||
border: 1px #808080 solid ;
|
||||
padding: 8px ;
|
||||
color: black ;
|
||||
background-color: rgb(255, 255, 204) ;
|
||||
z-index: 1 ;
|
||||
background-color: rgb(255 255 204);
|
||||
border: 1px rgb(128 128 128) solid;
|
||||
color: rgb(0 0 0);
|
||||
content: attr(data-tooltip);
|
||||
left: 1em;
|
||||
min-width: 200px;
|
||||
padding: 8px;
|
||||
position: absolute;
|
||||
top: 1.1em;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
@@ -14,9 +14,9 @@
|
||||
<div class="panel panel-primary" style="height:100%">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">
|
||||
{% blocktrans with state=request.user.profile.state %}
|
||||
{% blocktranslate with state=request.user.profile.state %}
|
||||
Main Character (State: {{ state }})
|
||||
{% endblocktrans %}
|
||||
{% endblocktranslate %}
|
||||
</h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
@@ -103,13 +103,17 @@
|
||||
{% endif %}
|
||||
<div class="clearfix"></div>
|
||||
<div class="row">
|
||||
<div class="col-sm-6 button-wrapper">
|
||||
<a href="{% url 'authentication:add_character' %}" class="btn btn-block btn-info"
|
||||
title="Add Character">{% translate 'Add Character' %}</a>
|
||||
<div class="col-sm-6">
|
||||
<p>
|
||||
<a href="{% url 'authentication:add_character' %}" class="btn btn-block btn-info"
|
||||
title="Add Character">{% translate 'Add Character' %}</a>
|
||||
</p>
|
||||
</div>
|
||||
<div class="col-sm-6 button-wrapper">
|
||||
<a href="{% url 'authentication:change_main_character' %}" class="btn btn-block btn-info"
|
||||
title="Change Main Character">{% translate "Change Main" %}</a>
|
||||
<div class="col-sm-6">
|
||||
<p>
|
||||
<a href="{% url 'authentication:change_main_character' %}" class="btn btn-block btn-info"
|
||||
title="Change Main Character">{% translate "Change Main" %}</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -159,7 +163,7 @@
|
||||
</td>
|
||||
<td class="text-center">{{ char.character_name }}</td>
|
||||
<td class="text-center">{{ char.corporation_name }}</td>
|
||||
<td class="text-center">{{ char.alliance_name }}</td>
|
||||
<td class="text-center">{{ char.alliance_name|default:"" }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
{% extends "allianceauth/base.html" %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block page_title %}{% translate "Dashboard" %}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h1 class="page-header text-center">{% translate "Token Management" %}</h1>
|
||||
<div class="col-sm-12">
|
||||
<table class="table table-aa" id="table_tokens" style="width:100%">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{% translate "Scopes" %}</th>
|
||||
<th class="text-right">{% translate "Actions" %}</th>
|
||||
<th>{% translate "Character" %}</th>
|
||||
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for t in tokens %}
|
||||
<tr>
|
||||
<td styl="white-space:initial;">{% for s in t.scopes.all %}<span class="label label-default">{{s.name}}</span> {% endfor %}</td>
|
||||
<td nowrap class="text-right"><a href="{% url 'authentication:token_delete' t.id %}" class="btn btn-danger"><i class="fas fa-trash"></i></a> <a href="{% url 'authentication:token_refresh' t.id %}" class="btn btn-success"><i class="fas fa-sync-alt"></i></a></td>
|
||||
<td>{{t.character_name}}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% translate "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."|urlize %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block extra_javascript %}
|
||||
{% include 'bundles/datatables-js.html' %}
|
||||
{% endblock %}
|
||||
|
||||
{% block extra_css %}
|
||||
{% include 'bundles/datatables-css.html' %}
|
||||
{% endblock %}
|
||||
|
||||
{% block extra_script %}
|
||||
$(document).ready(function(){
|
||||
let grp = 2;
|
||||
var table = $('#table_tokens').DataTable({
|
||||
"columnDefs": [{ orderable: false, targets: [0,1] },{ "visible": false, "targets": grp }],
|
||||
"order": [[grp, 'asc']],
|
||||
"drawCallback": function (settings) {
|
||||
var api = this.api();
|
||||
var rows = api.rows({ page: 'current' }).nodes();
|
||||
var last = null;
|
||||
api.column(grp, { page: 'current' })
|
||||
.data()
|
||||
.each(function (group, i) {
|
||||
if (last !== group) {
|
||||
$(rows).eq(i).before('<tr class="info"><td colspan="3">' + group + '</td></tr>');
|
||||
last = group;
|
||||
}
|
||||
});
|
||||
},
|
||||
"stateSave": true,
|
||||
});
|
||||
});
|
||||
{% endblock %}
|
||||
@@ -1,4 +1,5 @@
|
||||
{% load static %}
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
@@ -7,7 +8,7 @@
|
||||
<meta name="description" content="">
|
||||
<meta name="author" content="">
|
||||
<meta property="og:title" content="{{ SITE_NAME }}">
|
||||
<meta property="og:image" content="{{ request.scheme }}://{{ request.get_host }}{% static 'allianceauth/icons/apple-touch-icon.png' %}">
|
||||
<meta property="og:image" content="{{ SITE_URL }}{% static 'allianceauth/icons/apple-touch-icon.png' %}">
|
||||
<meta property="og:description" content="Alliance Auth - An auth system for EVE Online to help in-game organizations manage online service access.">
|
||||
|
||||
{% include 'allianceauth/icons.html' %}
|
||||
@@ -31,6 +32,7 @@
|
||||
.panel-transparent {
|
||||
background: rgba(48, 48, 48, 0.7);
|
||||
color: #ffffff;
|
||||
padding-bottom: 21px;
|
||||
}
|
||||
|
||||
.panel-body {
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
{% get_language_info_list for LANGUAGES as languages %}
|
||||
{% for language in languages %}
|
||||
<option value="{{ language.code }}"{% if language.code == LANGUAGE_CODE %} selected="selected"{% endif %}>
|
||||
{{ language.name_local }} ({{ language.code }})
|
||||
{{ language.name_local|capfirst }} ({{ language.code }})
|
||||
</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
{% extends 'public/base.html' %}
|
||||
|
||||
{% load i18n %}
|
||||
|
||||
{% block content %}
|
||||
<div class="col-md-4 col-md-offset-4">
|
||||
{% if messages %}
|
||||
@@ -6,6 +9,7 @@
|
||||
<div class="alert alert-{{ message.level_tag}}">{{ message }}</div>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
<div class="panel panel-default panel-transparent">
|
||||
<div class="panel-body">
|
||||
<div class="col-md-12">
|
||||
@@ -13,10 +17,25 @@
|
||||
{% endblock %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% include 'public/lang_select.html' %}
|
||||
|
||||
<p class="text-center" style="margin-top: 2rem;">
|
||||
{% translate "For information on SSO, ESI and security read the CCP Dev Blog" %}<br>
|
||||
<a href="https://www.eveonline.com/article/introducing-esi" target="_blank" rel="noopener noreferrer">
|
||||
{% translate "Introducing ESI - A New API For Eve Online" %}
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<p class="text-center">
|
||||
<a href="https://community.eveonline.com/support/third-party-applications/" target="_blank" rel="noopener noreferrer">
|
||||
{% translate "Manage ESI Applications" %}
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block extra_include %}
|
||||
{% include 'bundles/bootstrap-js.html' %}
|
||||
{% endblock %}
|
||||
|
||||
@@ -116,10 +116,17 @@ class TestAuthenticate(TestCase):
|
||||
user = StateBackend().authenticate(token=t)
|
||||
self.assertEqual(user, self.user)
|
||||
|
||||
""" Alt Login disabled
|
||||
def test_authenticate_alt_character(self):
|
||||
t = Token(character_id=self.alt_character.character_id, character_owner_hash='2')
|
||||
user = StateBackend().authenticate(token=t)
|
||||
self.assertEqual(user, self.user)
|
||||
"""
|
||||
|
||||
def test_authenticate_alt_character_fail(self):
|
||||
t = Token(character_id=self.alt_character.character_id, character_owner_hash='2')
|
||||
user = StateBackend().authenticate(token=t)
|
||||
self.assertEqual(user, None)
|
||||
|
||||
def test_authenticate_unclaimed_character(self):
|
||||
t = Token(character_id=self.unclaimed_character.character_id, character_name=self.unclaimed_character.character_name, character_owner_hash='3')
|
||||
@@ -128,6 +135,7 @@ class TestAuthenticate(TestCase):
|
||||
self.assertEqual(user.username, 'Unclaimed_Character')
|
||||
self.assertEqual(user.profile.main_character, self.unclaimed_character)
|
||||
|
||||
""" Alt Login disabled
|
||||
def test_authenticate_character_record(self):
|
||||
t = Token(character_id=self.unclaimed_character.character_id, character_name=self.unclaimed_character.character_name, character_owner_hash='4')
|
||||
OwnershipRecord.objects.create(user=self.old_user, character=self.unclaimed_character, owner_hash='4')
|
||||
@@ -135,6 +143,15 @@ class TestAuthenticate(TestCase):
|
||||
self.assertEqual(user, self.old_user)
|
||||
self.assertTrue(CharacterOwnership.objects.filter(owner_hash='4', user=self.old_user).exists())
|
||||
self.assertTrue(user.profile.main_character)
|
||||
"""
|
||||
|
||||
def test_authenticate_character_record_fails(self):
|
||||
t = Token(character_id=self.unclaimed_character.character_id, character_name=self.unclaimed_character.character_name, character_owner_hash='4')
|
||||
OwnershipRecord.objects.create(user=self.old_user, character=self.unclaimed_character, owner_hash='4')
|
||||
user = StateBackend().authenticate(token=t)
|
||||
self.assertEqual(user, self.old_user)
|
||||
self.assertTrue(CharacterOwnership.objects.filter(owner_hash='4', user=self.old_user).exists())
|
||||
self.assertTrue(user.profile.main_character)
|
||||
|
||||
def test_iterate_username(self):
|
||||
t = Token(character_id=self.unclaimed_character.character_id,
|
||||
|
||||
@@ -22,5 +22,20 @@ urlpatterns = [
|
||||
views.add_character,
|
||||
name='add_character'
|
||||
),
|
||||
path(
|
||||
'account/tokens/manage/',
|
||||
views.token_management,
|
||||
name='token_management'
|
||||
),
|
||||
path(
|
||||
'account/tokens/delete/<int:token_id>',
|
||||
views.token_delete,
|
||||
name='token_delete'
|
||||
),
|
||||
path(
|
||||
'account/tokens/refresh/<int:token_id>',
|
||||
views.token_refresh,
|
||||
name='token_refresh'
|
||||
),
|
||||
path('dashboard/', views.dashboard, name='dashboard'),
|
||||
]
|
||||
|
||||
@@ -61,6 +61,44 @@ def dashboard(request):
|
||||
}
|
||||
return render(request, 'authentication/dashboard.html', context)
|
||||
|
||||
@login_required
|
||||
def token_management(request):
|
||||
tokens = request.user.token_set.all()
|
||||
|
||||
context = {
|
||||
'tokens': tokens
|
||||
}
|
||||
return render(request, 'authentication/tokens.html', context)
|
||||
|
||||
@login_required
|
||||
def token_delete(request, token_id=None):
|
||||
try:
|
||||
token = Token.objects.get(id=token_id)
|
||||
if request.user == token.user:
|
||||
token.delete()
|
||||
messages.success(request, "Token Deleted.")
|
||||
else:
|
||||
messages.error(request, "This token does not belong to you.")
|
||||
except Token.DoesNotExist:
|
||||
messages.warning(request, "Token does not exist")
|
||||
return redirect('authentication:token_management')
|
||||
|
||||
@login_required
|
||||
def token_refresh(request, token_id=None):
|
||||
try:
|
||||
token = Token.objects.get(id=token_id)
|
||||
if request.user == token.user:
|
||||
try:
|
||||
token.refresh()
|
||||
messages.success(request, "Token refreshed.")
|
||||
except Exception as e:
|
||||
messages.warning(request, f"Failed to refresh token. {e}")
|
||||
else:
|
||||
messages.error(request, "This token does not belong to you.")
|
||||
except Token.DoesNotExist:
|
||||
messages.warning(request, "Token does not exist")
|
||||
return redirect('authentication:token_management')
|
||||
|
||||
|
||||
@login_required
|
||||
@token_required(scopes=settings.LOGIN_TOKEN_SCOPES)
|
||||
|
||||
@@ -5,5 +5,6 @@ from .views import NightModeRedirectView
|
||||
def auth_settings(request):
|
||||
return {
|
||||
'SITE_NAME': settings.SITE_NAME,
|
||||
'SITE_URL': settings.SITE_URL,
|
||||
'NIGHT_MODE': NightModeRedirectView.night_mode_state(request),
|
||||
}
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
# Generated by Django 4.0.7 on 2022-08-14 16:23
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('eveonline', '0016_character_names_are_not_unique'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='eveallianceinfo',
|
||||
name='alliance_name',
|
||||
field=models.CharField(max_length=254, db_index=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='evecorporationinfo',
|
||||
name='corporation_name',
|
||||
field=models.CharField(max_length=254, db_index=True),
|
||||
),
|
||||
]
|
||||
@@ -71,7 +71,7 @@ class EveAllianceInfo(models.Model):
|
||||
"""An alliance in Eve Online."""
|
||||
|
||||
alliance_id = models.PositiveIntegerField(unique=True)
|
||||
alliance_name = models.CharField(max_length=254, unique=True)
|
||||
alliance_name = models.CharField(max_length=254, db_index=True)
|
||||
alliance_ticker = models.CharField(max_length=254)
|
||||
executor_corp_id = models.PositiveIntegerField()
|
||||
|
||||
@@ -139,7 +139,7 @@ class EveCorporationInfo(models.Model):
|
||||
"""A corporation in Eve Online."""
|
||||
|
||||
corporation_id = models.PositiveIntegerField(unique=True)
|
||||
corporation_name = models.CharField(max_length=254, unique=True)
|
||||
corporation_name = models.CharField(max_length=254, db_index=True)
|
||||
corporation_ticker = models.CharField(max_length=254)
|
||||
member_count = models.IntegerField()
|
||||
ceo_id = models.PositiveIntegerField(blank=True, null=True, default=None)
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
<td class="text-center">{{ fat.user }}</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>
|
||||
<td class="text-center">{% blocktranslate %}Docked in {% endblocktranslate %}{{ fat.system }}</td>
|
||||
{% else %}
|
||||
<td class="text-center">{{ fat.system }}</td>
|
||||
{% endif %}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
{% block content %}
|
||||
<div class="col-lg-12">
|
||||
<h1 class="page-header text-center">{% blocktrans %}Participation data statistics for {{ month }}, {{ year }}{% endblocktrans %}
|
||||
<h1 class="page-header text-center">{% blocktranslate %}Participation data statistics for {{ month }}, {{ year }}{% endblocktranslate %}
|
||||
{% 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">{% translate "Previous month" %}</a>
|
||||
@@ -14,11 +14,11 @@
|
||||
{% endif %}
|
||||
</h1>
|
||||
<h2>
|
||||
{% blocktrans count links=n_fats trimmed %}
|
||||
{% blocktranslate count links=n_fats trimmed %}
|
||||
{{ user }} has collected one link this month.
|
||||
{% plural %}
|
||||
{{ user }} has collected {{ links }} links this month.
|
||||
{% endblocktrans %}
|
||||
{% endblocktranslate %}
|
||||
</h2>
|
||||
<table class="table table-responsive">
|
||||
<tr>
|
||||
@@ -34,11 +34,11 @@
|
||||
</table>
|
||||
{% if created_fats %}
|
||||
<h2>
|
||||
{% blocktrans count links=n_created_fats trimmed %}
|
||||
{% blocktranslate count links=n_created_fats trimmed %}
|
||||
{{ user }} has created one link this month.
|
||||
{% plural %}
|
||||
{{ user }} has created {{ links }} links this month.
|
||||
{% endblocktrans %}
|
||||
{% endblocktranslate %}
|
||||
</h2>
|
||||
{% if created_fats %}
|
||||
<table class="table">
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
{% block content %}
|
||||
<div class="col-lg-12">
|
||||
<h1 class="page-header text-center">{% blocktrans %}Participation data statistics for {{ year }}{% endblocktrans %}
|
||||
<h1 class="page-header text-center">{% blocktranslate %}Participation data statistics for {{ year }}{% endblocktranslate %}
|
||||
<div class="text-right">
|
||||
<a href="{% url 'fatlink:personal_statistics_year' previous_year %}" class="btn btn-info">{% translate "Previous year" %}</a>
|
||||
{% if next_year %}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
{% block content %}
|
||||
<div class="col-lg-12">
|
||||
<h1 class="page-header text-center">{% blocktrans %}Participation data statistics for {{ month }}, {{ year }}{% endblocktrans %}
|
||||
<h1 class="page-header text-center">{% blocktranslate %}Participation data statistics for {{ month }}, {{ year }}{% endblocktranslate %}
|
||||
<div class="text-right">
|
||||
<a href="{% url 'fatlink:statistics_corp_month' corpid previous_month|date:"Y" previous_month|date:"m" %}" class="btn btn-info">{% translate "Previous month" %}</a>
|
||||
{% if next_month %}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
{% block content %}
|
||||
<div class="col-lg-12">
|
||||
<h1 class="page-header text-center">{% blocktrans %}Participation data statistics for {{ month }}, {{ year }}{% endblocktrans %}
|
||||
<h1 class="page-header text-center">{% blocktranslate %}Participation data statistics for {{ month }}, {{ year }}{% endblocktranslate %}
|
||||
<div class="text-right">
|
||||
<a href="{% url 'fatlink:statistics_month' previous_month|date:"Y" previous_month|date:"m" %}" class="btn btn-info">{% translate "Previous month" %}</a>
|
||||
{% if next_month %}
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
<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>
|
||||
<td class="text-center">{% blocktranslate %}Docked in {% endblocktranslate %}{{ fat.system }}</td>
|
||||
{% else %}
|
||||
<td class="text-center">{{ fat.system }}</td>
|
||||
{% endif %}
|
||||
|
||||
@@ -248,59 +248,82 @@ 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'])
|
||||
scopes=[
|
||||
'esi-location.read_location.v1',
|
||||
'esi-location.read_ship_type.v1',
|
||||
'esi-universe.read_structures.v1',
|
||||
'esi-location.read_online.v1',
|
||||
]
|
||||
)
|
||||
def click_fatlink_view(request, token, fat_hash=None):
|
||||
fatlink = get_object_or_404(Fatlink, hash=fat_hash)
|
||||
c = token.get_esi_client(spec_file=SWAGGER_SPEC_PATH)
|
||||
character = EveCharacter.objects.get_character_by_id(token.character_id)
|
||||
character_online = c.Location.get_characters_character_id_online(
|
||||
character_id=token.character_id
|
||||
).result()
|
||||
|
||||
if (timezone.now() - fatlink.fatdatetime) < datetime.timedelta(seconds=(fatlink.duration * 60)):
|
||||
if character_online["online"] is True:
|
||||
fatlink = get_object_or_404(Fatlink, hash=fat_hash)
|
||||
|
||||
character = EveCharacter.objects.get_character_by_id(token.character_id)
|
||||
if (timezone.now() - fatlink.fatdatetime) < datetime.timedelta(seconds=(fatlink.duration * 60)):
|
||||
if character:
|
||||
# get data
|
||||
location = c.Location.get_characters_character_id_location(character_id=token.character_id).result()
|
||||
ship = c.Location.get_characters_character_id_ship(character_id=token.character_id).result()
|
||||
location['solar_system_name'] = \
|
||||
c.Universe.get_universe_systems_system_id(system_id=location['solar_system_id']).result()['name']
|
||||
|
||||
if character:
|
||||
# get data
|
||||
c = token.get_esi_client(spec_file=SWAGGER_SPEC_PATH)
|
||||
location = c.Location.get_characters_character_id_location(character_id=token.character_id).result()
|
||||
ship = c.Location.get_characters_character_id_ship(character_id=token.character_id).result()
|
||||
location['solar_system_name'] = \
|
||||
c.Universe.get_universe_systems_system_id(system_id=location['solar_system_id']).result()['name']
|
||||
if location['station_id']:
|
||||
location['station_name'] = \
|
||||
c.Universe.get_universe_stations_station_id(station_id=location['station_id']).result()['name']
|
||||
elif location['structure_id']:
|
||||
location['station_name'] = \
|
||||
c.Universe.get_universe_structures_structure_id(structure_id=location['structure_id']).result()[
|
||||
'name']
|
||||
if location['station_id']:
|
||||
location['station_name'] = \
|
||||
c.Universe.get_universe_stations_station_id(station_id=location['station_id']).result()['name']
|
||||
elif location['structure_id']:
|
||||
location['station_name'] = \
|
||||
c.Universe.get_universe_structures_structure_id(structure_id=location['structure_id']).result()[
|
||||
'name']
|
||||
else:
|
||||
location['station_name'] = "No Station"
|
||||
|
||||
ship['ship_type_name'] = provider.get_itemtype(ship['ship_type_id']).name
|
||||
|
||||
fat = Fat()
|
||||
fat.system = location['solar_system_name']
|
||||
fat.station = location['station_name']
|
||||
fat.shiptype = ship['ship_type_name']
|
||||
fat.fatlink = fatlink
|
||||
fat.character = character
|
||||
fat.user = request.user
|
||||
|
||||
try:
|
||||
fat.full_clean()
|
||||
fat.save()
|
||||
messages.success(request, _('Fleet participation registered.'))
|
||||
except ValidationError as e:
|
||||
err_messages = []
|
||||
|
||||
for errorname, message in e.message_dict.items():
|
||||
err_messages.append(message[0])
|
||||
|
||||
messages.error(request, ' '.join(err_messages))
|
||||
else:
|
||||
location['station_name'] = "No Station"
|
||||
ship['ship_type_name'] = provider.get_itemtype(ship['ship_type_id']).name
|
||||
context = {
|
||||
'character_id': token.character_id,
|
||||
'character_name': token.character_name,
|
||||
'character_portrait_url': EveCharacter.generic_portrait_url(
|
||||
token.character_id, 128
|
||||
),
|
||||
}
|
||||
|
||||
fat = Fat()
|
||||
fat.system = location['solar_system_name']
|
||||
fat.station = location['station_name']
|
||||
fat.shiptype = ship['ship_type_name']
|
||||
fat.fatlink = fatlink
|
||||
fat.character = character
|
||||
fat.user = request.user
|
||||
try:
|
||||
fat.full_clean()
|
||||
fat.save()
|
||||
messages.success(request, _('Fleet participation registered.'))
|
||||
except ValidationError as e:
|
||||
err_messages = []
|
||||
for errorname, message in e.message_dict.items():
|
||||
err_messages.append(message[0])
|
||||
messages.error(request, ' '.join(err_messages))
|
||||
return render(request, 'fleetactivitytracking/characternotexisting.html', context=context)
|
||||
else:
|
||||
context = {
|
||||
'character_id': token.character_id,
|
||||
'character_name': token.character_name,
|
||||
'character_portrait_url': EveCharacter.generic_portrait_url(
|
||||
token.character_id, 128
|
||||
),
|
||||
}
|
||||
return render(request, 'fleetactivitytracking/characternotexisting.html', context=context)
|
||||
messages.error(request, _('FAT link has expired.'))
|
||||
else:
|
||||
messages.error(request, _('FAT link has expired.'))
|
||||
messages.warning(
|
||||
request,
|
||||
_(
|
||||
f"Cannot register the fleet participation for {character.character_name}. The character needs to be online."
|
||||
),
|
||||
)
|
||||
|
||||
return redirect('fatlink:view')
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
{% extends "allianceauth/base.html" %}
|
||||
{% load static %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block page_title %}{{ group }} {% translate "Audit Log" %}{% endblock page_title %}
|
||||
|
||||
@@ -60,7 +60,7 @@
|
||||
<i class="glyphicon glyphicon-list-alt"></i>
|
||||
</a>
|
||||
|
||||
<a id="clipboard-copy" data-clipboard-text="{{ request.scheme }}://{{request.get_host}}{% url 'groupmanagement:request_add' group.id %}" class="btn btn-warning" title="{% translate "Copy Direct Join Link" %}">
|
||||
<a id="clipboard-copy" data-clipboard-text="{{ SITE_URL }}{% url 'groupmanagement:request_add' group.id %}" class="btn btn-warning" title="{% translate "Copy Direct Join Link" %}">
|
||||
<i class="glyphicon glyphicon-copy"></i>
|
||||
</a>
|
||||
</td>
|
||||
|
||||
@@ -5,7 +5,7 @@ app_name = "groupmanagement"
|
||||
|
||||
urlpatterns = [
|
||||
# groups
|
||||
path("groups", views.groups_view, name="groups"),
|
||||
path("groups/", views.groups_view, name="groups"),
|
||||
path("group/request/join/<int:group_id>/", views.group_request_add, name="request_add"),
|
||||
path(
|
||||
"group/request/leave/<int:group_id>/", views.group_request_leave, name="request_leave"
|
||||
|
||||
Binary file not shown.
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@@ -34,7 +34,7 @@ class OpTimer(models.Model):
|
||||
fc = models.CharField(max_length=254, default="")
|
||||
post_time = models.DateTimeField(default=timezone.now)
|
||||
eve_character = models.ForeignKey(EveCharacter, null=True,
|
||||
on_delete=models.SET_NULL)
|
||||
on_delete=models.SET_NULL)
|
||||
description = models.TextField(blank=True, default="")
|
||||
type = models.ForeignKey(OpTimerType, null=True, on_delete=models.SET_NULL)
|
||||
|
||||
|
||||
@@ -8,10 +8,10 @@
|
||||
<h1 class="page-header">{% translate "Permissions Overview" %}</h1>
|
||||
<p>
|
||||
{% if request.GET.all != 'yes' %}
|
||||
{% blocktrans %}Showing only applied permissions{% endblocktrans %}
|
||||
{% blocktranslate %}Showing only applied permissions{% endblocktranslate %}
|
||||
<a href="{% url 'permissions_tool:overview' %}?all=yes" class="btn btn-primary">{% translate "Show All" %}</a>
|
||||
{% else %}
|
||||
{% blocktrans %}Showing all permissions{% endblocktrans %}
|
||||
{% blocktranslate %}Showing all permissions{% endblocktranslate %}
|
||||
<a href="{% url 'permissions_tool:overview' %}?all=no" class="btn btn-primary">{% translate "Show Applied" %}</a>
|
||||
{% endif %}
|
||||
</p>
|
||||
|
||||
@@ -84,17 +84,16 @@ LOCALE_PATHS = (
|
||||
os.path.join(BASE_DIR, 'locale/'),
|
||||
)
|
||||
|
||||
ugettext = lambda s: s
|
||||
LANGUAGES = (
|
||||
('en', ugettext('English')),
|
||||
('de', ugettext('German')),
|
||||
('es', ugettext('Spanish')),
|
||||
('zh-hans', ugettext('Chinese Simplified')),
|
||||
('ru', ugettext('Russian')),
|
||||
('ko', ugettext('Korean')),
|
||||
('fr', ugettext('French')),
|
||||
('ja', ugettext('Japanese')),
|
||||
('it', ugettext('Italian')),
|
||||
("en", "English"),
|
||||
("de", "German"),
|
||||
("es", "Spanish"),
|
||||
("zh-hans", "Chinese Simplified"),
|
||||
("ru", "Russian"),
|
||||
("ko", "Korean"),
|
||||
("fr", "French"),
|
||||
("ja", "Japanese"),
|
||||
("it", "Italian"),
|
||||
)
|
||||
|
||||
TEMPLATES = [
|
||||
|
||||
@@ -13,6 +13,13 @@ STATIC_ROOT = "/var/www/{{ project_name }}/static/"
|
||||
# in page titles and the site header.
|
||||
SITE_NAME = '{{ project_name }}'
|
||||
|
||||
# This is your websites URL, set it accordingly
|
||||
# Make sure this URL is WITHOUT a trailing slash
|
||||
SITE_URL = "https://example.com"
|
||||
|
||||
# Django security
|
||||
CSRF_TRUSTED_ORIGINS = [SITE_URL]
|
||||
|
||||
# Change this to enable/disable debug mode, which displays
|
||||
# useful error messages but can leak sensitive data.
|
||||
DEBUG = False
|
||||
@@ -39,15 +46,16 @@ DATABASES['default'] = {
|
||||
|
||||
# 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
|
||||
# to https://example.com/sso/callback substituting your domain for example.com in
|
||||
# CCP's developer portal
|
||||
# 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 = ''
|
||||
ESI_SSO_CALLBACK_URL = f"{SITE_URL}/sso/callback"
|
||||
ESI_USER_CONTACT_EMAIL = '' # A server maintainer that CCP can contact in case of issues.
|
||||
|
||||
# By default emails are validated before new users can log in.
|
||||
# By default, emails are validated before new users can log in.
|
||||
# It's recommended to use a free service like SparkPost or Elastic Email to send email.
|
||||
# https://www.sparkpost.com/docs/integrations/django/
|
||||
# https://elasticemail.com/resources/settings/smtp-api/
|
||||
|
||||
@@ -38,6 +38,12 @@ class SmfService(ServicesHook):
|
||||
if SmfTasks.has_account(user):
|
||||
SmfTasks.update_groups.delay(user.pk)
|
||||
|
||||
def sync_nickname(self, user):
|
||||
logger.debug(f"Updating {self.name} displayed name for {user}")
|
||||
|
||||
if SmfTasks.has_account(user):
|
||||
SmfTasks.update_display_name.apply_async(args=[user.pk], countdown=5) # cooldown on this task to ensure DB clean when syncing
|
||||
|
||||
def update_all_groups(self):
|
||||
logger.debug('Update all %s groups called' % self.name)
|
||||
SmfTasks.update_all_groups.delay()
|
||||
|
||||
@@ -5,11 +5,14 @@ from datetime import datetime
|
||||
import hashlib
|
||||
import logging
|
||||
import re
|
||||
from typing import Tuple
|
||||
|
||||
from packaging import version
|
||||
|
||||
from django.db import connections
|
||||
from django.conf import settings
|
||||
from django.contrib.auth.models import User
|
||||
|
||||
from allianceauth.eveonline.models import EveCharacter
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -37,6 +40,10 @@ class SmfManager:
|
||||
|
||||
SQL_DEL_USER = r"DELETE FROM %smembers where member_name = %%s" % TABLE_PREFIX
|
||||
|
||||
SQL_UPD_USER = r"UPDATE %smembers SET email_address = %%s, passwd = %%s, real_name = %%s WHERE member_name = %%s" % TABLE_PREFIX
|
||||
|
||||
SQL_UPD_DISPLAY_NAME = r"UPDATE %smembers SET real_name = %%s WHERE member_name = %%s" % TABLE_PREFIX
|
||||
|
||||
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 %smembers WHERE member_name = %%s" % TABLE_PREFIX
|
||||
@@ -174,50 +181,75 @@ class SmfManager:
|
||||
return out
|
||||
|
||||
@classmethod
|
||||
def add_user(cls, username, email_address, groups, characterid):
|
||||
def add_user(cls, username, email_address, groups, main_character: EveCharacter) -> Tuple:
|
||||
"""
|
||||
Add a user to SMF
|
||||
:param username:
|
||||
:param email_address:
|
||||
:param groups:
|
||||
:param main_character:
|
||||
:return:
|
||||
"""
|
||||
|
||||
main_character_id = main_character.character_id
|
||||
main_character_name = main_character.character_name
|
||||
|
||||
logger.debug(
|
||||
f"Adding smf user with member_name {username}, "
|
||||
f"email_address {email_address}, "
|
||||
f"characterid {characterid}"
|
||||
f"Adding smf user with member_name: {username}, "
|
||||
f"email_address: {email_address}, "
|
||||
f"characterid: {main_character_id}, "
|
||||
f"main character: {main_character_name}"
|
||||
)
|
||||
|
||||
cursor = connections['smf'].cursor()
|
||||
username_clean = cls.santatize_username(username)
|
||||
passwd = cls.generate_random_pass()
|
||||
pwhash = cls.gen_hash(username_clean, passwd)
|
||||
logger.debug(f"Proceeding to add smf user {username} and pwhash starting with {pwhash[0:5]}")
|
||||
register_date = cls.get_current_utc_date()
|
||||
|
||||
logger.debug(f"Proceeding to add smf user {username} and pwhash starting with {pwhash[0:5]}")
|
||||
|
||||
# check if the username was simply revoked
|
||||
if cls.check_user(username) is True:
|
||||
logger.warning(f"Unable to add smf user with username {username} - already exists. Updating user instead.")
|
||||
cls.__update_user_info(username_clean, email_address, pwhash)
|
||||
logger.warning(
|
||||
f"Unable to add smf user with username {username} - "
|
||||
f"already exists. Updating user instead."
|
||||
)
|
||||
|
||||
cls.__update_user_info(
|
||||
username_clean, email_address, pwhash, main_character_name
|
||||
)
|
||||
else:
|
||||
try:
|
||||
smf_version = cls._get_current_smf_version()
|
||||
sql_add_user_arguments = [
|
||||
username_clean,
|
||||
pwhash,
|
||||
email_address,
|
||||
register_date,
|
||||
main_character_name,
|
||||
]
|
||||
|
||||
if version.parse(smf_version) < version.parse("2.1"):
|
||||
logger.debug("SMF compatibility: < 2.1")
|
||||
|
||||
cursor.execute(
|
||||
cls.SQL_ADD_USER_SMF_20,
|
||||
[username_clean, pwhash, email_address, register_date, username_clean]
|
||||
)
|
||||
cursor.execute(cls.SQL_ADD_USER_SMF_20, sql_add_user_arguments)
|
||||
else:
|
||||
logger.debug("SMF compatibility: >= 2.1")
|
||||
|
||||
cursor.execute(
|
||||
cls.SQL_ADD_USER_SMF_21,
|
||||
[username_clean, pwhash, email_address, register_date, username_clean]
|
||||
)
|
||||
cls.add_avatar(username_clean, characterid)
|
||||
cursor.execute(cls.SQL_ADD_USER_SMF_21, sql_add_user_arguments)
|
||||
|
||||
cls.add_avatar(username_clean, main_character_id)
|
||||
logger.info(f"Added smf member_name {username_clean}")
|
||||
cls.update_groups(username_clean, groups)
|
||||
except Exception as e:
|
||||
logger.warning(f"Unable to add smf user {username_clean}: {e}")
|
||||
pass
|
||||
|
||||
return username_clean, passwd
|
||||
|
||||
@classmethod
|
||||
def __update_user_info(cls, username, email_address, passwd):
|
||||
def __update_user_info(cls, username, email_address, passwd, main_character_name):
|
||||
logger.debug(
|
||||
f"Updating smf user {username} info: "
|
||||
f"username {email_address} "
|
||||
@@ -225,7 +257,9 @@ class SmfManager:
|
||||
)
|
||||
cursor = connections['smf'].cursor()
|
||||
try:
|
||||
cursor.execute(cls.SQL_DIS_USER, [email_address, passwd, username])
|
||||
cursor.execute(
|
||||
cls.SQL_UPD_USER, [email_address, passwd, main_character_name, username]
|
||||
)
|
||||
logger.info(f"Updated smf user {username} info")
|
||||
except Exception as e:
|
||||
logger.exception(f"Unable to update smf user {username} info. ({e})")
|
||||
@@ -243,6 +277,27 @@ class SmfManager:
|
||||
logger.error(f"Unable to delete smf user {username} - user not found on smf.")
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
def update_display_name(cls, user: User):
|
||||
logger.debug(f"Updating SMF displayed name for user {user}")
|
||||
cursor = connections['smf'].cursor()
|
||||
smf_username = user.smf.username
|
||||
|
||||
try:
|
||||
display_name = user.profile.main_character.character_name
|
||||
except Exception as exc:
|
||||
logger.exception(
|
||||
f"Unable to find a main character name for {user}, skipping... ({exc})"
|
||||
)
|
||||
display_name = smf_username
|
||||
|
||||
if cls.check_user(smf_username):
|
||||
cursor.execute(cls.SQL_UPD_DISPLAY_NAME, [display_name, smf_username])
|
||||
logger.info(f"Updated displayed name for smf user {smf_username}")
|
||||
return True
|
||||
logger.error(f"Unable to update smf user {smf_username} - user not found on smf.")
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
def update_groups(cls, username, groups):
|
||||
userid = cls.get_user_id(username)
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
from django.db import migrations
|
||||
from ..manager import SmfManager
|
||||
|
||||
def on_migrate(apps, schema_editor):
|
||||
SmfUser = apps.get_model("smf", "SmfUser")
|
||||
db_alias = schema_editor.connection.alias
|
||||
all_smf_users = SmfUser.objects.using(db_alias).all()
|
||||
|
||||
for smf_user in all_smf_users:
|
||||
try:
|
||||
auth_user = smf_user.user
|
||||
except:
|
||||
pass
|
||||
else:
|
||||
SmfManager.update_display_name(auth_user)
|
||||
|
||||
def on_migrate_zero(apps, schema_editor):
|
||||
pass
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('smf', '0002_service_permissions'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RunPython(on_migrate, on_migrate_zero),
|
||||
]
|
||||
@@ -57,6 +57,40 @@ class SmfTasks:
|
||||
else:
|
||||
logger.debug("User does not have an smf account")
|
||||
|
||||
@staticmethod
|
||||
@shared_task(bind=True, name="smf.update_display_name", base=QueueOnce)
|
||||
def update_display_name(self, pk):
|
||||
user = User.objects.get(pk=pk)
|
||||
logger.debug(f"Updating SMF displayed name user {user}")
|
||||
|
||||
if SmfTasks.has_account(user):
|
||||
try:
|
||||
if not SmfManager.update_display_name(user):
|
||||
raise Exception("SMF Displayed Name Sync failed")
|
||||
logger.debug(f"Updated user {user} SMF displayed name.")
|
||||
return True
|
||||
except SmfUser.DoesNotExist:
|
||||
logger.info(
|
||||
f"SMF displayed name sync failed for {user}, "
|
||||
"user does not have a SMF account"
|
||||
)
|
||||
except:
|
||||
logger.exception(
|
||||
f"SMF displayed name sync failed for {user}, retrying in 10 mins"
|
||||
)
|
||||
raise self.retry(countdown=60 * 10)
|
||||
else:
|
||||
logger.debug(f"User {user} does not have a SMF account, skipping")
|
||||
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
@shared_task(name="smf.update_all_display_names")
|
||||
def update_all_display_names():
|
||||
logger.debug("Updating ALL SMF display names")
|
||||
for smf_user in SmfUser.objects.exclude(username__exact=''):
|
||||
SmfTasks.update_display_name.delay(smf_user)
|
||||
|
||||
@staticmethod
|
||||
@shared_task(name="smf.update_all_groups")
|
||||
def update_all_groups():
|
||||
|
||||
@@ -19,26 +19,51 @@ ACCESS_PERM = 'smf.access_smf'
|
||||
@login_required
|
||||
@permission_required(ACCESS_PERM)
|
||||
def activate_smf(request):
|
||||
logger.debug("activate_smf called by user %s" % request.user)
|
||||
logger.debug(f"activate_smf called by user {request.user}")
|
||||
# Valid now we get the main characters
|
||||
character = request.user.profile.main_character
|
||||
logger.debug(f"Adding smf user for user {request.user} with main character {character}")
|
||||
result = SmfManager.add_user(SmfTasks.get_username(request.user), request.user.email, ['Member'], character.character_id)
|
||||
main_character = request.user.profile.main_character
|
||||
|
||||
logger.debug(
|
||||
f"Adding smf user for user {request.user} with main character {main_character}"
|
||||
)
|
||||
|
||||
result = SmfManager.add_user(
|
||||
SmfTasks.get_username(request.user),
|
||||
request.user.email,
|
||||
['Member'],
|
||||
main_character,
|
||||
)
|
||||
|
||||
# if empty we failed
|
||||
if result[0] != "":
|
||||
SmfUser.objects.update_or_create(user=request.user, defaults={'username': result[0]})
|
||||
logger.debug("Updated authserviceinfo for user %s with smf credentials. Updating groups." % request.user)
|
||||
SmfUser.objects.update_or_create(
|
||||
user=request.user, defaults={'username': result[0]}
|
||||
)
|
||||
|
||||
logger.debug(
|
||||
f"Updated authserviceinfo for user {request.user} "
|
||||
f"with smf credentials. Updating groups."
|
||||
)
|
||||
|
||||
SmfTasks.update_groups.delay(request.user.pk)
|
||||
logger.info("Successfully activated smf for user %s" % request.user)
|
||||
|
||||
logger.info(f"Successfully activated smf for user {request.user}")
|
||||
|
||||
messages.success(request, _('Activated SMF account.'))
|
||||
credentials = {
|
||||
'username': result[0],
|
||||
'password': result[1],
|
||||
}
|
||||
return render(request, 'services/service_credentials.html', context={'credentials': credentials, 'service': 'SMF'})
|
||||
else:
|
||||
logger.error("Unsuccessful attempt to activate smf for user %s" % request.user)
|
||||
messages.error(request, _('An error occurred while processing your SMF account.'))
|
||||
|
||||
return render(
|
||||
request,
|
||||
'services/service_credentials.html',
|
||||
context={'credentials': credentials, 'service': 'SMF'},
|
||||
)
|
||||
|
||||
logger.error(f"Unsuccessful attempt to activate smf for user {request.user}")
|
||||
messages.error(request, _('An error occurred while processing your SMF account.'))
|
||||
|
||||
return redirect("services:services")
|
||||
|
||||
|
||||
|
||||
@@ -2,5 +2,10 @@
|
||||
CSS for allianceauth admin site
|
||||
*/
|
||||
|
||||
.img-circle { border-radius: 50%; }
|
||||
.column-user_profile_pic { width: 50px; }
|
||||
.img-circle {
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.column-user_profile_pic {
|
||||
width: 50px;
|
||||
}
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
|
||||
|
||||
{% block page_title %}
|
||||
{% blocktrans with service_name=view.service_name|title %}Delete {{ service_name }} Account?{% endblocktrans %}
|
||||
{% blocktranslate with service_name=view.service_name|title %}Delete {{ service_name }} Account?{% endblocktranslate %}
|
||||
{% endblock page_title %}
|
||||
|
||||
{% block content %}
|
||||
<div class="col-lg-12">
|
||||
<h1 class="page-header text-center">
|
||||
{% blocktrans with service_name=view.service_name|title %}Delete {{ service_name }} Account?{% endblocktrans %}
|
||||
{% blocktranslate with service_name=view.service_name|title %}Delete {{ service_name }} Account?{% endblocktranslate %}
|
||||
</h1>
|
||||
<div class="container-fluid">
|
||||
<div class="col-md-2 col-md-offset-5">
|
||||
@@ -17,9 +17,9 @@
|
||||
<form action="" method="post">
|
||||
{% csrf_token %}
|
||||
<p>
|
||||
{% blocktrans trimmed with service_name=view.service_name|title %}
|
||||
{% blocktranslate trimmed with service_name=view.service_name|title %}
|
||||
Are you sure you want to delete your {{ service_name }} account {{ object }}?
|
||||
{% endblocktrans %}
|
||||
{% endblocktranslate %}
|
||||
</p>
|
||||
<input class="btn btn-danger btn-block" type="submit" value="Confirm">
|
||||
</form>
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
{% extends "allianceauth/base.html" %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block page_title %}{% blocktrans with service_name=view.service_name|title %}{{ service_name }} Credentials{% endblocktrans %}{% endblock page_title %}
|
||||
{% block page_title %}{% blocktranslate with service_name=view.service_name|title %}{{ service_name }} Credentials{% endblocktranslate %}{% endblock page_title %}
|
||||
|
||||
{% block content %}
|
||||
<div class="col-lg-12">
|
||||
<h1 class="page-header text-center">{% blocktrans with service_name=view.service_name|title %}{{ service_name }} Credentials{% endblocktrans %}</h1>
|
||||
<h1 class="page-header text-center">{% blocktranslate with service_name=view.service_name|title %}{{ service_name }} Credentials{% endblocktranslate %}</h1>
|
||||
<div class="container-fluid">
|
||||
<div class="col-lg-4 col-lg-offset-4">
|
||||
<form class="form-signin">
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
{% load bootstrap %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block page_title %}{% blocktrans with service_name=view.service_name|title %}{{ service_name }} Password Change{% endblocktrans %}{% endblock page_title %}
|
||||
{% block page_title %}{% blocktranslate with service_name=view.service_name|title %}{{ service_name }} Password Change{% endblocktranslate %}{% endblock page_title %}
|
||||
|
||||
{% block content %}
|
||||
<div class="col-lg-12">
|
||||
<h1 class="page-header text-center">{% blocktrans with service_name=view.service_name|title %}Set {{service_name}} Password{% endblocktrans %}</h1>
|
||||
<h1 class="page-header text-center">{% blocktranslate with service_name=view.service_name|title %}Set {{service_name}} Password{% endblocktranslate %}</h1>
|
||||
<div class="container-fluid">
|
||||
<div class="col-md-4 col-md-offset-4">
|
||||
<div class="row">
|
||||
|
||||
@@ -23,9 +23,10 @@
|
||||
<button class="btn btn-lg btn-primary btn-block" type="submit">{% translate "Create SRP Fleet" %}</button>
|
||||
</form>
|
||||
{% else %}
|
||||
<div class="alert alert-info" role="alert">{% blocktrans %}Give this link to the line members{% endblocktrans %}.</div>
|
||||
<div class="alert alert-info" role="alert">{% blocktranslate %}Give this link to the line members{% endblocktranslate %}.</div>
|
||||
<div class="alert alert-info" role="alert">
|
||||
{{ request.scheme }}://{{ request.get_host }}{% url 'srp:request' completed_srp_code %}</div>
|
||||
{{ SITE_URL }}{% url 'srp:request' completed_srp_code %}
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<a href="{% url 'srp:management' %}" class="btn btn-primary btn-lg">{% translate "Continue" %}</a>
|
||||
</div>
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
{% extends "allianceauth/base.html" %}
|
||||
{% load static %}
|
||||
{% load i18n %}
|
||||
|
||||
{% load humanize %}
|
||||
@@ -7,7 +6,7 @@
|
||||
{% block extra_css %}
|
||||
{% include 'bundles/datatables-css.html' %}
|
||||
{% include 'bundles/x-editable.css.html' %}
|
||||
<link href="{% static 'allianceauth/css/checkbox.css' %}" rel="stylesheet">
|
||||
{% include 'bundles/checkbox-css.html' %}
|
||||
<style>
|
||||
.copy-text-fa-icon:hover {
|
||||
cursor: pointer;
|
||||
@@ -93,9 +92,9 @@
|
||||
<th class="text-center">{% translate "Ship Type" %}</th>
|
||||
<th class="text-center">{% translate "Killboard Loss Amt" %}</th>
|
||||
<th class="text-center">{% translate "SRP ISK Cost" %}
|
||||
<i class="glyphicon glyphicon-question-sign" rel="tooltip" title="{% blocktrans trimmed %}Click value to edit
|
||||
<i class="glyphicon glyphicon-question-sign" rel="tooltip" title="{% blocktranslate trimmed %}Click value to edit
|
||||
Enter to save & next
|
||||
ESC to cancel{% endblocktrans %}" id="blah"></i></th>
|
||||
ESC to cancel{% endblocktranslate %}" id="blah"></i></th>
|
||||
<th class="text-center">{% translate "Post Time" %}</th>
|
||||
<th class="text-center">{% translate "Status" %}</th>
|
||||
{% if perms.auth.srp_management %}
|
||||
|
||||
@@ -11,7 +11,7 @@ urlpatterns = [
|
||||
path('<int:fleet_id>/view/', views.srp_fleet_view, name='fleet'),
|
||||
path('add/', views.srp_fleet_add_view, name='add'),
|
||||
path('<int:fleet_id>/edit/', views.srp_fleet_edit_view, name='edit'),
|
||||
path('<str:fleet_srp>/request', views.srp_request_view, name='request'),
|
||||
path('<str:fleet_srp>/request/', views.srp_request_view, name='request'),
|
||||
|
||||
# SRP URLS
|
||||
path('<int:fleet_id>/remove/', views.srp_fleet_remove, name='remove'),
|
||||
@@ -27,6 +27,6 @@ urlpatterns = [
|
||||
name='request_approve'),
|
||||
path('request/reject/', views.srp_request_reject,
|
||||
name='request_reject'),
|
||||
path('request/<int:fleet_srp_request_id>/update', views.srp_request_update_amount,
|
||||
path('request/<int:fleet_srp_request_id>/update/', views.srp_request_update_amount,
|
||||
name="request_update_amount"),
|
||||
]
|
||||
|
||||
@@ -2,17 +2,9 @@ body {
|
||||
margin-bottom: 32px;
|
||||
}
|
||||
|
||||
.gray-icon-color .fa {
|
||||
color: #505050;
|
||||
}
|
||||
|
||||
.notification-bell-color {
|
||||
color: #a88f1e;
|
||||
}
|
||||
|
||||
.navbar-brand {
|
||||
height: 58px;
|
||||
padding: 19px 19px;
|
||||
padding: 19px;
|
||||
}
|
||||
|
||||
.auth-navbar-top {
|
||||
@@ -48,36 +40,36 @@ ul.list-group.list-group-horizontal > li.list-group-item {
|
||||
}
|
||||
|
||||
@media all {
|
||||
/* style nav tabs in dark mode*/
|
||||
/* style nav tabs in dark mode */
|
||||
.template-dark-mode .nav-tabs > li.active > a {
|
||||
background-color: rgb(70, 69, 69) !important;
|
||||
color: rgb(255, 255, 255) !important;
|
||||
background-color: rgb(70 69 69) !important;
|
||||
color: rgb(255 255 255) !important;
|
||||
}
|
||||
|
||||
.panel-tabs-aa {
|
||||
border-top: none;
|
||||
border-top-left-radius: 0%;
|
||||
border-top-right-radius: 0%;
|
||||
border-top-left-radius: 0;
|
||||
border-top-right-radius: 0;
|
||||
}
|
||||
|
||||
/* style group headers within a table */
|
||||
.template-light-mode .tr-group {
|
||||
background-color: #e6e6e6 !important;
|
||||
background-color: rgb(230 230 230) !important;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.template-dark-mode .tr-group {
|
||||
background-color: rgb(105, 105, 105) !important;
|
||||
background-color: rgb(105 105 105) !important;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* default style for tables */
|
||||
.template-light-mode .table-aa > thead > tr > th {
|
||||
border-bottom: 1px solid #f2f2f2;
|
||||
border-bottom: 1px solid rgb(242 242 242);
|
||||
}
|
||||
|
||||
.template-dark-mode .table-aa > thead > tr > th {
|
||||
border-bottom: 1px solid rgb(70, 69, 69);
|
||||
border-bottom: 1px solid rgb(70 69 69);
|
||||
}
|
||||
|
||||
.table-aa > thead > tr > th {
|
||||
@@ -85,11 +77,11 @@ ul.list-group.list-group-horizontal > li.list-group-item {
|
||||
}
|
||||
|
||||
.template-light-mode .table-aa > tbody > tr > td {
|
||||
border-bottom: 1px solid #f2f2f2;
|
||||
border-bottom: 1px solid rgb(242 242 242);
|
||||
}
|
||||
|
||||
.template-dark-mode .table-aa > tbody > tr > td {
|
||||
border-bottom: 1px solid rgb(70, 69, 69);
|
||||
border-bottom: 1px solid rgb(70 69 69);
|
||||
}
|
||||
|
||||
.table-aa > tbody > tr > td {
|
||||
@@ -100,9 +92,9 @@ ul.list-group.list-group-horizontal > li.list-group-item {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.task-status-progress-bar {
|
||||
font-size: 15px!important;
|
||||
line-height: normal!important;
|
||||
.progress .progress-bar {
|
||||
font-size: 13px;
|
||||
line-height: 21px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -110,11 +102,11 @@ ul.list-group.list-group-horizontal > li.list-group-item {
|
||||
------------------------------------------------------------------------------------- */
|
||||
@media all {
|
||||
.template-light-mode .nav-pills > li > a.active {
|
||||
background-color: rgb(236, 240, 241);
|
||||
background-color: rgb(236 240 241);
|
||||
}
|
||||
|
||||
.template-dark-mode .nav-pills > li > a.active {
|
||||
background-color: rgb(48, 48, 48);
|
||||
background-color: rgb(48 48 48);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -136,45 +128,41 @@ ul.list-group.list-group-horizontal > li.list-group-item {
|
||||
|
||||
.dropdown-menu > li > a {
|
||||
clear: both;
|
||||
color: rgb(123, 138, 139);
|
||||
color: rgb(123 138 139);
|
||||
display: block;
|
||||
font-weight: 400;
|
||||
line-height: 1.42857143;
|
||||
line-height: 1.42857;
|
||||
padding: 3px 20px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.top-user-menu {
|
||||
color: rgb(255, 255, 255);
|
||||
color: rgb(255 255 255);
|
||||
}
|
||||
|
||||
.top-menu-bar-language-select form {
|
||||
border-bottom: 1px solid transparent;
|
||||
border-top: 1px solid transparent;
|
||||
-webkit-box-shadow: inset 0 1px 0 rgb(255 255 255), 0 1px 0 rgb(255 255 255);
|
||||
box-shadow: inset 0 1px 0 rgb(255 255 255), 0 1px 0 rgb(255 255 255);
|
||||
margin-bottom: 7.5px;
|
||||
margin-left: 5px;
|
||||
margin-right: 5px;
|
||||
margin-top: 7.5px;
|
||||
margin: 7.5px 5px;
|
||||
padding: 10px 15px;
|
||||
}
|
||||
}
|
||||
|
||||
@media all and (max-width: 768px) {
|
||||
.navbar-nav .open .dropdown-menu .dropdown-header, .navbar-nav .open .dropdown-menu > li > a {
|
||||
.navbar-nav .open .dropdown-menu .dropdown-header,
|
||||
.navbar-nav .open .dropdown-menu > li > a {
|
||||
padding: 5px 15px 5px 25px;
|
||||
}
|
||||
}
|
||||
|
||||
@media all and (min-width: 768px) {
|
||||
.top-user-menu {
|
||||
color: rgb(123, 138, 139);
|
||||
color: rgb(123 138 139);
|
||||
}
|
||||
|
||||
.top-menu-bar-language-select form {
|
||||
border: 0;
|
||||
-webkit-box-shadow: none;
|
||||
box-shadow: none;
|
||||
margin-left: 0;
|
||||
margin-right: 0;
|
||||
@@ -188,7 +176,7 @@ ul.list-group.list-group-horizontal > li.list-group-item {
|
||||
------------------------------------------------------------------------------------- */
|
||||
@media all {
|
||||
.nav-item-eve-time .eve-time-wrapper {
|
||||
color: rgb(255, 255, 255);
|
||||
color: rgb(255 255 255);
|
||||
display: block;
|
||||
line-height: 21px;
|
||||
padding: 10px 15px;
|
||||
@@ -203,26 +191,17 @@ ul.list-group.list-group-horizontal > li.list-group-item {
|
||||
}
|
||||
}
|
||||
|
||||
/* Small devices (tablets, 768px and up) */
|
||||
/* Small devices (tablets, 768px and up)
|
||||
------------------------------------------------------------------------------------- */
|
||||
@media (min-width: 768px) {
|
||||
/* class for vertically aligning columns in a bootstrap row */
|
||||
.row.vertical-flexbox-row2 {
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.row.vertical-flexbox-row2 > [class*='col-'] {
|
||||
.row.vertical-flexbox-row2 > [class*="col-"] {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
|
||||
/* Extra Small devices (Phones, <768px) */
|
||||
@media (max-width: 767px) {
|
||||
.button-wrapper .btn {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
.checkbox label:after,
|
||||
.radio label:after {
|
||||
content: '';
|
||||
display: table;
|
||||
.checkbox label::after,
|
||||
.radio label::after {
|
||||
clear: both;
|
||||
content: "";
|
||||
display: table;
|
||||
}
|
||||
|
||||
.checkbox .cr,
|
||||
.radio .cr {
|
||||
position: relative;
|
||||
border: 1px solid rgb(169 169 169);
|
||||
border-radius: 0.25em;
|
||||
display: inline-block;
|
||||
border: 1px solid #a9a9a9;
|
||||
border-radius: .25em;
|
||||
width: 1.3em;
|
||||
height: 1.3em;
|
||||
float: left;
|
||||
margin-right: .5em;
|
||||
height: 1.3em;
|
||||
margin-right: 0.5em;
|
||||
position: relative;
|
||||
width: 1.3em;
|
||||
}
|
||||
|
||||
.radio .cr {
|
||||
@@ -23,11 +23,11 @@
|
||||
|
||||
.checkbox .cr .cr-icon,
|
||||
.radio .cr .cr-icon {
|
||||
position: absolute;
|
||||
font-size: .8em;
|
||||
line-height: 0;
|
||||
top: 50%;
|
||||
font-size: 0.8em;
|
||||
left: 20%;
|
||||
line-height: 0;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
}
|
||||
|
||||
.radio .cr .cr-icon {
|
||||
@@ -41,18 +41,18 @@
|
||||
|
||||
.checkbox label input[type="checkbox"] + .cr > .cr-icon,
|
||||
.radio label input[type="radio"] + .cr > .cr-icon {
|
||||
transform: scale(3) rotateZ(-20deg);
|
||||
opacity: 0;
|
||||
transition: all .3s ease-in;
|
||||
transform: scale(3) rotateZ(-20deg);
|
||||
transition: all 0.3s ease-in;
|
||||
}
|
||||
|
||||
.checkbox label input[type="checkbox"]:checked + .cr > .cr-icon,
|
||||
.radio label input[type="radio"]:checked + .cr > .cr-icon {
|
||||
transform: scale(1) rotateZ(0deg);
|
||||
opacity: 1;
|
||||
transform: scale(1) rotateZ(0deg);
|
||||
}
|
||||
|
||||
.checkbox label input[type="checkbox"]:disabled + .cr,
|
||||
.radio label input[type="radio"]:disabled + .cr {
|
||||
opacity: .5;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
aria-valuenow="{% decimal_widthratio tasks_count tasks_total 100 %}"
|
||||
aria-valuemin="0"
|
||||
aria-valuemax="100"
|
||||
style="width: {% decimal_widthratio tasks_count tasks_total 100 %}%;">
|
||||
<p style="margin-top:5px;">{% widthratio tasks_count tasks_total 100 %}%</p>
|
||||
style="width: {% decimal_widthratio tasks_count tasks_total 100 %}%;"
|
||||
>
|
||||
<span>{% widthratio tasks_count tasks_total 100 %}%</span>
|
||||
</div>
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
{% load static %}
|
||||
{% load i18n %}
|
||||
{% load navactive %}
|
||||
{% load auth_notifications %}
|
||||
@@ -16,8 +15,7 @@
|
||||
|
||||
{% include 'bundles/bootstrap-css.html' %}
|
||||
{% include 'bundles/fontawesome.html' %}
|
||||
|
||||
<link href="{% static 'allianceauth/css/auth-base.css' %}" rel="stylesheet">
|
||||
{% include 'bundles/auth-base-css.html' %}
|
||||
|
||||
{% block extra_css %}{% endblock extra_css %}
|
||||
</head>
|
||||
|
||||
@@ -53,6 +53,14 @@
|
||||
<!-- logout / login -->
|
||||
<li role="separator" class="divider"></li>
|
||||
{% if user.is_authenticated %}
|
||||
<li>
|
||||
<a href="{% url 'authentication:token_management' %}">
|
||||
<i class="fas fa-user-lock"></i>
|
||||
{% translate "Token Management" %}
|
||||
</a>
|
||||
</li>
|
||||
<li role="separator" class="divider"></li>
|
||||
|
||||
<li><a href="{% url 'logout' %}">{% translate "Logout" %}</a></li>
|
||||
{% else %}
|
||||
<li><a href="{% url 'authentication:login' %}">{% translate "Login" %}</a></li>
|
||||
|
||||
3
allianceauth/templates/bundles/auth-base-css.html
Normal file
3
allianceauth/templates/bundles/auth-base-css.html
Normal file
@@ -0,0 +1,3 @@
|
||||
{% load static %}
|
||||
|
||||
<link href="{% static 'allianceauth/css/auth-base.css' %}" rel="stylesheet">
|
||||
3
allianceauth/templates/bundles/checkbox-css.html
Normal file
3
allianceauth/templates/bundles/checkbox-css.html
Normal file
@@ -0,0 +1,3 @@
|
||||
{% load static %}
|
||||
|
||||
<link href="{% static 'allianceauth/css/checkbox.css' %}" rel="stylesheet">
|
||||
@@ -16,7 +16,7 @@
|
||||
<div class="row">
|
||||
<form action="" method="post">
|
||||
{% csrf_token %}
|
||||
<p>{% blocktrans %}Are you sure you want to delete timer "{{ object }}"?{% endblocktrans %}</p>
|
||||
<p>{% blocktranslate %}Are you sure you want to delete timer "{{ object }}"?{% endblocktranslate %}</p>
|
||||
<input class="btn btn-danger btn-block" type="submit" value="Confirm">
|
||||
</form>
|
||||
</div>
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
{% extends "allianceauth/base.html" %}
|
||||
{% load static %}
|
||||
{% load i18n %}
|
||||
{% get_current_language as LANGUAGE_CODE %}
|
||||
{% load evelinks %}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
PROTOCOL=https://
|
||||
AUTH_SUBDOMAIN=%AUTH_SUBDOMAIN%
|
||||
DOMAIN=%DOMAIN%
|
||||
AA_DOCKER_TAG=registry.gitlab.com/allianceauth/allianceauth/auth:v3.0.0
|
||||
AA_DOCKER_TAG=registry.gitlab.com/allianceauth/allianceauth/auth:3.3.0
|
||||
|
||||
# Nginx Proxy Manager
|
||||
PROXY_HTTP_PORT=80
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
FROM python:3.9-slim
|
||||
ARG AUTH_VERSION=v3.0.0
|
||||
ARG AUTH_VERSION=v3.3.0
|
||||
ARG AUTH_PACKAGE=allianceauth==${AUTH_VERSION}
|
||||
ENV VIRTUAL_ENV=/opt/venv
|
||||
ENV AUTH_USER=allianceauth
|
||||
|
||||
@@ -3,14 +3,20 @@ from .base import *
|
||||
|
||||
SECRET_KEY = os.environ.get("AA_SECRET_KEY")
|
||||
SITE_NAME = os.environ.get("AA_SITENAME")
|
||||
SITE_URL = (
|
||||
f"{os.environ.get('PROTOCOL')}"
|
||||
f"{os.environ.get('AUTH_SUBDOMAIN')}."
|
||||
f"{os.environ.get('DOMAIN')}"
|
||||
)
|
||||
CSRF_TRUSTED_ORIGINS = [SITE_URL]
|
||||
DEBUG = os.environ.get("AA_DEBUG", False)
|
||||
DATABASES['default'] = {
|
||||
'ENGINE': 'django.db.backends.mysql',
|
||||
'NAME': os.environ.get("AA_DB_NAME"),
|
||||
'USER': os.environ.get("AA_DB_USER"),
|
||||
'PASSWORD': os.environ.get("AA_DB_PASSWORD"),
|
||||
'HOST': os.environ.get("AA_DB_HOST"),
|
||||
'PORT': os.environ.get("AA_DB_PORT", "3306"),
|
||||
DATABASES["default"] = {
|
||||
"ENGINE": "django.db.backends.mysql",
|
||||
"NAME": os.environ.get("AA_DB_NAME"),
|
||||
"USER": os.environ.get("AA_DB_USER"),
|
||||
"PASSWORD": os.environ.get("AA_DB_PASSWORD"),
|
||||
"HOST": os.environ.get("AA_DB_HOST"),
|
||||
"PORT": os.environ.get("AA_DB_PORT", "3306"),
|
||||
}
|
||||
|
||||
# Register an application at https://developers.eveonline.com for Authentication
|
||||
@@ -21,10 +27,10 @@ DATABASES['default'] = {
|
||||
|
||||
ESI_SSO_CLIENT_ID = os.environ.get("ESI_SSO_CLIENT_ID")
|
||||
ESI_SSO_CLIENT_SECRET = os.environ.get("ESI_SSO_CLIENT_SECRET")
|
||||
ESI_SSO_CALLBACK_URL = (f"{os.environ.get('PROTOCOL')}"
|
||||
f"{os.environ.get('AUTH_SUBDOMAIN')}."
|
||||
f"{os.environ.get('DOMAIN')}/sso/callback")
|
||||
ESI_USER_CONTACT_EMAIL = os.environ.get("ESI_USER_CONTACT_EMAIL") # A server maintainer that CCP can contact in case of issues.
|
||||
ESI_SSO_CALLBACK_URL = f"{SITE_URL}/sso/callback"
|
||||
ESI_USER_CONTACT_EMAIL = os.environ.get(
|
||||
"ESI_USER_CONTACT_EMAIL"
|
||||
) # A server maintainer that CCP can contact in case of issues.
|
||||
|
||||
# By default emails are validated before new users can log in.
|
||||
# It's recommended to use a free service like SparkPost or Elastic Email to send email.
|
||||
@@ -40,40 +46,36 @@ EMAIL_HOST_PASSWORD = os.environ.get("AA_EMAIL_HOST_PASSWORD", "")
|
||||
EMAIL_USE_TLS = os.environ.get("AA_EMAIL_USE_TLS", True)
|
||||
DEFAULT_FROM_EMAIL = os.environ.get("AA_DEFAULT_FROM_EMAIL", "")
|
||||
|
||||
ROOT_URLCONF = 'myauth.urls'
|
||||
WSGI_APPLICATION = 'myauth.wsgi.application'
|
||||
ROOT_URLCONF = "myauth.urls"
|
||||
WSGI_APPLICATION = "myauth.wsgi.application"
|
||||
STATIC_ROOT = "/var/www/myauth/static/"
|
||||
BROKER_URL = F"redis://{os.environ.get('AA_REDIS', 'redis:6379')}/0"
|
||||
CELERY_RESULT_BACKEND = F"redis://{os.environ.get('AA_REDIS', 'redis:6379')}/0"
|
||||
BROKER_URL = f"redis://{os.environ.get('AA_REDIS', 'redis:6379')}/0"
|
||||
CACHES = {
|
||||
"default": {
|
||||
"BACKEND": "redis_cache.RedisCache",
|
||||
"LOCATION": os.environ.get('AA_REDIS', 'redis:6379'),
|
||||
"OPTIONS": {
|
||||
"DB": 1,
|
||||
}
|
||||
"BACKEND": "django_redis.cache.RedisCache",
|
||||
"LOCATION": f"redis://{os.environ.get('AA_REDIS', 'redis:6379')}/1", # change the 1 here to change the database used
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# Add any additional apps to this list.
|
||||
INSTALLED_APPS += [
|
||||
# https://allianceauth.readthedocs.io/en/latest/features/apps/index.html
|
||||
# 'allianceauth.corputils',
|
||||
# 'allianceauth.fleetactivitytracking',
|
||||
# 'allianceauth.optimer',
|
||||
# 'allianceauth.permissions_tool',
|
||||
# 'allianceauth.srp',
|
||||
# 'allianceauth.timerboard',
|
||||
|
||||
# https://allianceauth.readthedocs.io/en/latest/features/services/index.html
|
||||
# 'allianceauth.services.modules.discord',
|
||||
# 'allianceauth.services.modules.discourse',
|
||||
# 'allianceauth.services.modules.ips4',
|
||||
# 'allianceauth.services.modules.openfire',
|
||||
# 'allianceauth.services.modules.phpbb3',
|
||||
# 'allianceauth.services.modules.smf',
|
||||
# 'allianceauth.services.modules.teamspeak3',
|
||||
# 'allianceauth.services.modules.xenforo',
|
||||
# https://allianceauth.readthedocs.io/en/latest/features/apps/index.html
|
||||
# 'allianceauth.corputils',
|
||||
# 'allianceauth.fleetactivitytracking',
|
||||
# 'allianceauth.optimer',
|
||||
# 'allianceauth.permissions_tool',
|
||||
# 'allianceauth.srp',
|
||||
# 'allianceauth.timerboard',
|
||||
# https://allianceauth.readthedocs.io/en/latest/features/services/index.html
|
||||
# 'allianceauth.services.modules.discord',
|
||||
# 'allianceauth.services.modules.discourse',
|
||||
# 'allianceauth.services.modules.ips4',
|
||||
# 'allianceauth.services.modules.openfire',
|
||||
# 'allianceauth.services.modules.phpbb3',
|
||||
# 'allianceauth.services.modules.smf',
|
||||
# 'allianceauth.services.modules.teamspeak3',
|
||||
# 'allianceauth.services.modules.xenforo',
|
||||
]
|
||||
|
||||
#######################################
|
||||
|
||||
@@ -284,7 +284,7 @@ python manage.py migrate
|
||||
We also need to create a superuser for our AA installation:
|
||||
|
||||
```bash
|
||||
python /home/allianceserver/myauth/manage.py createsuperuser
|
||||
python manage.py createsuperuser
|
||||
```
|
||||
|
||||
## Running Alliance Auth
|
||||
@@ -319,7 +319,7 @@ In addition you can start a celery worker instance for myauth. For development p
|
||||
This can be done from the command line with the following command in the myauth folder (where manage.py is located):
|
||||
|
||||
```bash
|
||||
celery -E -A myauth worker -l info -P solo
|
||||
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.
|
||||
|
||||
@@ -17,8 +17,11 @@ Make the following changes in your auth project's settings file (`local.py`):
|
||||
|
||||
```python
|
||||
# Discord Configuration
|
||||
# Be sure to set the callback URLto https://example.com/discord/callback/
|
||||
# substituting your domain for example.com in Discord's developer portal
|
||||
# (Be sure to add the trailing slash)
|
||||
DISCORD_GUILD_ID = ''
|
||||
DISCORD_CALLBACK_URL = ''
|
||||
DISCORD_CALLBACK_URL = f"{SITE_URL}/discord/callback/"
|
||||
DISCORD_APP_ID = ''
|
||||
DISCORD_APP_SECRET = ''
|
||||
DISCORD_BOT_TOKEN = ''
|
||||
@@ -62,9 +65,9 @@ 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:
|
||||
|
||||
- From the App Details panel, `DISCORD_APP_ID` is the Client/Application ID
|
||||
- From the App Details panel, `DISCORD_APP_SECRET` is the Secret
|
||||
- From the App Bot Users panel, `DISCORD_BOT_TOKEN` is the Token
|
||||
- From the General Information panel, `DISCORD_APP_ID` is the Client/Application ID
|
||||
- From the OAuth2 > General panel, `DISCORD_APP_SECRET` is the Client Secret
|
||||
- From the Bot panel, `DISCORD_BOT_TOKEN` is the Token
|
||||
|
||||
### Preparing Auth
|
||||
|
||||
|
||||
@@ -344,8 +344,6 @@ For **scopes** your SSO app needs to have at least `publicData`. Additional scop
|
||||
|
||||
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`
|
||||
|
||||
In `local.py` you will need to set `ESI_USER_CONTACT_EMAIL` to an email address to ensure that CCP has reliable contact information for you.
|
||||
|
||||
### Alliance Auth Project
|
||||
|
||||
Update Pip before installing python packages:
|
||||
@@ -384,7 +382,14 @@ The following command bootstraps a Django project which will run your **Alliance
|
||||
allianceauth start myauth
|
||||
```
|
||||
|
||||
The settings file needs configuring. Edit the template at `myauth/myauth/settings/local.py`. Be sure to configure the EVE SSO as defined earlier in **Eve Online Settings** and valid Email settings.
|
||||
The settings file needs configuring, edit the template at `myauth/myauth/settings/local.py`.
|
||||
|
||||
**Be sure to configure:**
|
||||
* Your site URL as `SITE_URL`
|
||||
* The Database account setup earlier in **Database Setup**
|
||||
* `ESI_SSO_CLIENT_ID`, `ESI_SSO_CLIENT_SECRET` from the EVE Online Developers Portal earlier in **Eve Online Settings**
|
||||
* `ESI_USER_CONTACT_EMAIL` to an email address to ensure that CCP has reliable contact information for you
|
||||
* Valid Email server settings.
|
||||
|
||||
Django needs to install models to the database before it can start.
|
||||
|
||||
|
||||
@@ -13,4 +13,5 @@ In addition to main guide for installation Alliance Auth you also find guides fo
|
||||
apache
|
||||
gunicorn
|
||||
upgrade_python
|
||||
switch_to_non_root
|
||||
```
|
||||
|
||||
68
docs/installation/switch_to_non_root.md
Normal file
68
docs/installation/switch_to_non_root.md
Normal file
@@ -0,0 +1,68 @@
|
||||
# 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.
|
||||
|
||||
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.
|
||||
|
||||
The migration itself is rather straightforward. The main idea is to change ownership for all relevant directories and files to `allianceserver`.
|
||||
|
||||
First, log in as your sudo user and run the following commands in order:
|
||||
|
||||
```shell
|
||||
# Set the right owner
|
||||
sudo chown -R allianceserver: /home/allianceserver
|
||||
sudo chown -R allianceserver: /var/www/myauth
|
||||
|
||||
# Remove static files, they will be re-added later
|
||||
sudo rm -rf /var/www/mayauth/static/*
|
||||
|
||||
# Fix directory permissions
|
||||
sudo chmod -R 755 /var/www/myauth
|
||||
```
|
||||
|
||||
That's it. Your AA installation is now configured to be maintained with the `allianceserver` user.
|
||||
|
||||
## How to do maintenance with a non-root user
|
||||
|
||||
Here is how you can maintain your AA installation in the future:
|
||||
|
||||
First, log in with your sudo user.
|
||||
|
||||
Then, switch to the `allianceserver` user:
|
||||
|
||||
```shell
|
||||
sudo su allianceserver
|
||||
```
|
||||
|
||||
Go to your home folder and activate your venv:
|
||||
|
||||
```shell
|
||||
cd ~
|
||||
source venv/auth/bin/activate
|
||||
```
|
||||
|
||||
Finally, switch to the main AA folder, from where you can run most commands directly:
|
||||
|
||||
```shell
|
||||
cd myauth
|
||||
```
|
||||
|
||||
Now it's time to re-add the static files with the right permissions. To do so simply
|
||||
run:
|
||||
|
||||
```shell
|
||||
python manage.py collectstatic
|
||||
```
|
||||
|
||||
When you want to restart myauth, you need to switch back to your sudo user, because `allianceserver` does not have sudo privileges:
|
||||
|
||||
```shell
|
||||
exit
|
||||
sudo supervisorctl restart myauth:
|
||||
```
|
||||
|
||||
Alternatively, you can open another terminal with your sudo user for restarting myauth. That has the added advantage that you can now continue working with both your allianceauth user and your sudo user for restarts at the same time.
|
||||
@@ -37,7 +37,7 @@ install_requires =
|
||||
beautifulsoup4
|
||||
celery>=5.2.0,<6.0.0
|
||||
celery-once>=3.0.1
|
||||
django>=4.0.6,<5.0.0
|
||||
django>=4.0.6,<4.1.0
|
||||
django-bootstrap-form
|
||||
django-celery-beat>=2.3.0
|
||||
django-esi>=4.0.1
|
||||
|
||||
@@ -10,40 +10,43 @@ from allianceauth.project_template.project_name.settings.base import *
|
||||
CELERY_ALWAYS_EAGER = True # Forces celery to run locally for testing
|
||||
|
||||
INSTALLED_APPS += [
|
||||
'allianceauth.eveonline.autogroups',
|
||||
'allianceauth.hrapplications',
|
||||
'allianceauth.timerboard',
|
||||
'allianceauth.srp',
|
||||
'allianceauth.optimer',
|
||||
'allianceauth.corputils',
|
||||
'allianceauth.fleetactivitytracking',
|
||||
'allianceauth.permissions_tool',
|
||||
'allianceauth.services.modules.mumble',
|
||||
'allianceauth.services.modules.discord',
|
||||
'allianceauth.services.modules.discourse',
|
||||
'allianceauth.services.modules.ips4',
|
||||
'allianceauth.services.modules.openfire',
|
||||
'allianceauth.services.modules.smf',
|
||||
'allianceauth.services.modules.phpbb3',
|
||||
'allianceauth.services.modules.xenforo',
|
||||
'allianceauth.services.modules.teamspeak3',
|
||||
"allianceauth.eveonline.autogroups",
|
||||
"allianceauth.hrapplications",
|
||||
"allianceauth.timerboard",
|
||||
"allianceauth.srp",
|
||||
"allianceauth.optimer",
|
||||
"allianceauth.corputils",
|
||||
"allianceauth.fleetactivitytracking",
|
||||
"allianceauth.permissions_tool",
|
||||
"allianceauth.services.modules.mumble",
|
||||
"allianceauth.services.modules.discord",
|
||||
"allianceauth.services.modules.discourse",
|
||||
"allianceauth.services.modules.ips4",
|
||||
"allianceauth.services.modules.openfire",
|
||||
"allianceauth.services.modules.smf",
|
||||
"allianceauth.services.modules.phpbb3",
|
||||
"allianceauth.services.modules.xenforo",
|
||||
"allianceauth.services.modules.teamspeak3",
|
||||
]
|
||||
|
||||
ROOT_URLCONF = 'tests.urls'
|
||||
ROOT_URLCONF = "tests.urls"
|
||||
|
||||
SITE_URL = "https://example.com"
|
||||
CSRF_TRUSTED_ORIGINS = [SITE_URL]
|
||||
|
||||
CACHES = {
|
||||
"default": {
|
||||
"BACKEND": "django_redis.cache.RedisCache",
|
||||
"LOCATION": "redis://127.0.0.1:6379/1"
|
||||
"LOCATION": "redis://127.0.0.1:6379/1",
|
||||
}
|
||||
}
|
||||
|
||||
########################
|
||||
# XenForo Configuration
|
||||
########################
|
||||
XENFORO_ENDPOINT = 'example.com/api.php'
|
||||
XENFORO_ENDPOINT = "example.com/api.php"
|
||||
XENFORO_DEFAULT_GROUP = 0
|
||||
XENFORO_APIKEY = 'yourapikey'
|
||||
XENFORO_APIKEY = "yourapikey"
|
||||
#####################
|
||||
|
||||
######################
|
||||
@@ -79,7 +82,7 @@ MUMBLE_SERVER_ID = 1
|
||||
######################################
|
||||
# PHPBB3 Configuration
|
||||
######################################
|
||||
PHPBB3_URL = ''
|
||||
PHPBB3_URL = ""
|
||||
|
||||
######################################
|
||||
# Teamspeak3 Configuration
|
||||
@@ -92,12 +95,12 @@ PHPBB3_URL = ''
|
||||
# TEAMSPEAK3_AUTHED_GROUP_ID - Default authed group id
|
||||
# TEAMSPEAK3_PUBLIC_URL - teamspeak3 public url used for link creation
|
||||
######################################
|
||||
TEAMSPEAK3_SERVER_IP = '127.0.0.1'
|
||||
TEAMSPEAK3_SERVER_IP = "127.0.0.1"
|
||||
TEAMSPEAK3_SERVER_PORT = 10011
|
||||
TEAMSPEAK3_SERVERQUERY_USER = 'serveradmin'
|
||||
TEAMSPEAK3_SERVERQUERY_PASSWORD = 'passwordhere'
|
||||
TEAMSPEAK3_SERVERQUERY_USER = "serveradmin"
|
||||
TEAMSPEAK3_SERVERQUERY_PASSWORD = "passwordhere"
|
||||
TEAMSPEAK3_VIRTUAL_SERVER = 1
|
||||
TEAMSPEAK3_PUBLIC_URL = 'example.com'
|
||||
TEAMSPEAK3_PUBLIC_URL = "example.com"
|
||||
|
||||
######################################
|
||||
# Discord Configuration
|
||||
@@ -110,13 +113,13 @@ TEAMSPEAK3_PUBLIC_URL = 'example.com'
|
||||
# DISCORD_CALLBACK_URL - oauth callback url
|
||||
# DISCORD_SYNC_NAMES - enable to force discord nicknames to be set to eve char name (bot needs Manage Nicknames permission)
|
||||
######################################
|
||||
DISCORD_GUILD_ID = '0118999'
|
||||
DISCORD_BOT_TOKEN = 'bottoken'
|
||||
DISCORD_INVITE_CODE = 'invitecode'
|
||||
DISCORD_APP_ID = 'appid'
|
||||
DISCORD_APP_SECRET = 'secret'
|
||||
DISCORD_CALLBACK_URL = 'http://example.com/discord/callback'
|
||||
DISCORD_SYNC_NAMES = 'True' == 'False'
|
||||
DISCORD_GUILD_ID = "0118999"
|
||||
DISCORD_BOT_TOKEN = "bottoken"
|
||||
DISCORD_INVITE_CODE = "invitecode"
|
||||
DISCORD_APP_ID = "appid"
|
||||
DISCORD_APP_SECRET = "secret"
|
||||
DISCORD_CALLBACK_URL = "http://example.com/discord/callback"
|
||||
DISCORD_SYNC_NAMES = "True" == "False"
|
||||
|
||||
######################################
|
||||
# Discourse Configuration
|
||||
@@ -126,10 +129,10 @@ DISCORD_SYNC_NAMES = 'True' == 'False'
|
||||
# DISCOURSE_API_KEY - API Key
|
||||
# DISCOURSE_SSO_SECRET - SSO secret key
|
||||
######################################
|
||||
DISCOURSE_URL = 'https://example.com'
|
||||
DISCOURSE_API_USERNAME = ''
|
||||
DISCOURSE_API_KEY = ''
|
||||
DISCOURSE_SSO_SECRET = 'd836444a9e4084d5b224a60c208dce14'
|
||||
DISCOURSE_URL = "https://example.com"
|
||||
DISCOURSE_API_USERNAME = ""
|
||||
DISCOURSE_API_KEY = ""
|
||||
DISCOURSE_SSO_SECRET = "d836444a9e4084d5b224a60c208dce14"
|
||||
# Example secret from https://meta.discourse.org/t/official-single-sign-on-for-discourse/13045
|
||||
|
||||
#####################################
|
||||
@@ -138,16 +141,16 @@ DISCOURSE_SSO_SECRET = 'd836444a9e4084d5b224a60c208dce14'
|
||||
# IPS4_URL - base url of the IPS4 install (no trailing slash)
|
||||
# IPS4_API_KEY - API key provided by IPS4
|
||||
#####################################
|
||||
IPS4_URL = 'http://example.com/ips4'
|
||||
IPS4_API_KEY = ''
|
||||
IPS4_URL = "http://example.com/ips4"
|
||||
IPS4_API_KEY = ""
|
||||
|
||||
######################################
|
||||
# SMF Configuration
|
||||
######################################
|
||||
SMF_URL = ''
|
||||
SMF_URL = ""
|
||||
|
||||
PASSWORD_HASHERS = [
|
||||
'django.contrib.auth.hashers.MD5PasswordHasher',
|
||||
"django.contrib.auth.hashers.MD5PasswordHasher",
|
||||
]
|
||||
|
||||
LOGGING = None # Comment out to enable logging for debugging
|
||||
|
||||
@@ -10,17 +10,20 @@ from allianceauth.project_template.project_name.settings.base import *
|
||||
CELERY_ALWAYS_EAGER = True # Forces celery to run locally for testing
|
||||
|
||||
|
||||
ROOT_URLCONF = 'tests.urls'
|
||||
ROOT_URLCONF = "tests.urls"
|
||||
|
||||
SITE_URL = "https://example.com"
|
||||
CSRF_TRUSTED_ORIGINS = [SITE_URL]
|
||||
|
||||
CACHES = {
|
||||
"default": {
|
||||
"BACKEND": "django_redis.cache.RedisCache",
|
||||
"LOCATION": "redis://127.0.0.1:6379/1"
|
||||
"LOCATION": "redis://127.0.0.1:6379/1",
|
||||
}
|
||||
}
|
||||
|
||||
PASSWORD_HASHERS = [
|
||||
'django.contrib.auth.hashers.MD5PasswordHasher',
|
||||
"django.contrib.auth.hashers.MD5PasswordHasher",
|
||||
]
|
||||
|
||||
LOGGING = None # Comment out to enable logging for debugging
|
||||
|
||||
Reference in New Issue
Block a user