Compare commits

...

45 Commits

Author SHA1 Message Date
Ariel Rin
da102618a0 Version Bump 3.2.0 2022-09-14 23:26:02 +10:00
Ariel Rin
51ee281b14 Update from Transifex 2022-09-14 23:20:08 +10:00
Ariel Rin
7fbf96623b Update from Transifex 2022-09-12 11:41:08 +10:00
Ariel Rin
273bda173e Merge branch '1088-qol-improve-name-handling-for-smf' into 'master'
Displayed names for SMF

Closes #1088

See merge request allianceauth/allianceauth!1459
2022-09-11 13:53:25 +00:00
Ariel Rin
7bd5838ea1 Merge branch 'master' into 'master'
minor fixes to dev environment setup

See merge request allianceauth/allianceauth!1458
2022-09-11 13:51:42 +00:00
Ariel Rin
b232d9ab17 Merge branch 'use-SITE_URL-in-templates' into 'master'
[ADDED] `SITE_URL` usage in templates

See merge request allianceauth/allianceauth!1456
2022-09-11 13:51:21 +00:00
Ariel Rin
a11b870664 Merge branch 'switch-to-non-root' into 'master'
Add docs for switching to a non-root installation

See merge request allianceauth/allianceauth!1463
2022-09-11 13:48:44 +00:00
Erik Kalkoken
a27aae5d1c Add docs for switching to a non-root installation 2022-09-11 13:48:43 +00:00
Ariel Rin
117ef63d90 Merge branch 'trailing-slash-it' into 'master'
[ADDED] Missing trailing slashes to URLs

See merge request allianceauth/allianceauth!1457
2022-09-11 13:45:50 +00:00
Ariel Rin
1bde3d5672 Merge branch 'esi-related-links-on-login' into 'master'
[ADDED] ESI related links in login box

See merge request allianceauth/allianceauth!1455
2022-09-11 13:44:55 +00:00
Ariel Rin
d2355b1ec8 Merge branch 'none-is-not-an-alliance' into 'master'
[CHANGE] None is not an alliance name, so don't show `None`

See merge request allianceauth/allianceauth!1460
2022-09-11 13:44:34 +00:00
Ariel Rin
191d474a8e Merge branch 'task-queue-top-margin-fix' into 'master'
[FIX] Top margin on celery task percentage bar

See merge request allianceauth/allianceauth!1461
2022-09-11 13:44:11 +00:00
Peter Pfeufer
ec9a9733be [FIX] Top margin on celery task percentage bar 2022-09-11 13:44:11 +00:00
Ariel Rin
cf7a8cedf1 Merge branch 'dont-fight-against-bootstrap' into 'master'
[FIX] Use proper markup instead of fighting against Bootstrap

See merge request allianceauth/allianceauth!1462
2022-09-11 13:43:38 +00:00
Peter Pfeufer
18cbb994d5 [FIX] Use proper markup instead of fighting against Bootstrap 2022-09-08 11:22:40 +02:00
Peter Pfeufer
663388a0c2 [CHANGE] None is not an alliance name, so don't show None 2022-09-08 00:19:41 +02:00
Peter Pfeufer
7a943591ec [ADDED] Migration to update existing user's displayed names 2022-09-07 23:01:38 +02:00
Peter Pfeufer
cd189927fe [ADDED] Update displayed name when main is changed 2022-09-07 23:01:07 +02:00
Peter Pfeufer
8772349309 [ADDED] Main character name as displayed name on SMF service activation 2022-09-07 21:14:18 +02:00
Arc Tiru
cf20100cb5 minor fixes to dev environment setup 2022-09-07 11:00:38 -07:00
Peter Pfeufer
9b9c2ddc04 [ADDED] SITE_URLto test settings 2022-09-07 15:31:22 +02:00
Peter Pfeufer
34839e8344 [ADDED] Trailing slahes to URLs
URLs in AA usually use a trailing slash, so this was added to the ones that were missing it.
2022-09-07 15:18:06 +02:00
Peter Pfeufer
89ef4f4cbc [ADDED] SITE_URL usage in templates
Instead of {{ request.scheme }}://{{request.get_host}}`
2022-09-07 15:04:25 +02:00
Peter Pfeufer
2cc7f46aae [ADDED] ESI related links in login box 2022-09-07 14:45:04 +02:00
Ariel Rin
8d255fb720 Merge branch '834-check-if-character-is-online' into 'master'
[FIX] Check if character is online before accepting FAT click

Closes #834

See merge request allianceauth/allianceauth!1451
2022-09-07 06:29:19 +00:00
Ariel Rin
67cf68ad87 Merge branch 'no_unique_names' into 'master'
Corp and Alliance names are not unique

Closes #1317

See merge request allianceauth/allianceauth!1452
2022-09-07 06:28:01 +00:00
colcrunch
db1971d4c2 Corp and Alliance names are not unique 2022-09-07 06:28:01 +00:00
Ariel Rin
63c1521cba Merge branch 'add-missing-doctype' into 'master'
[FIX] Missing DOCTYPE and padding

See merge request allianceauth/allianceauth!1449
2022-09-07 06:25:45 +00:00
Ariel Rin
ba7ef11505 Merge branch 'fix-deprecated-translation-tags' into 'master'
[FIX] Deprecated `{% blocktrans %}` tags to `{% blocktranslate %}`

See merge request allianceauth/allianceauth!1454
2022-09-07 06:22:55 +00:00
Ariel Rin
d2e494b9be Merge branch 'modernize-css' into 'master'
CSS modernized

See merge request allianceauth/allianceauth!1448
2022-09-07 06:21:15 +00:00
Ariel Rin
98bab0b180 Merge branch 'bundle-all-the-things' into 'master'
Bundle the remaining static files

See merge request allianceauth/allianceauth!1447
2022-09-07 06:20:41 +00:00
Ariel Rin
c4efb2a11f Merge branch 'aa3-docker-fixes' into 'master'
[CHANGE] Docker updates for AA3

Closes #1352

See merge request allianceauth/allianceauth!1453
2022-09-07 06:19:47 +00:00
Ariel Rin
94e4895f29 Merge branch 'clarify-url-format' into 'master'
[MISC] Clarify URL format

See merge request allianceauth/allianceauth!1450
2022-09-07 06:18:43 +00:00
Peter Pfeufer
70eb1b5b50 [CHANGE] Deprecated {% blocktrans %} tags to {% blocktranslate %} 2022-09-06 23:48:36 +02:00
Peter Pfeufer
e247a94db3 [CHANGE] Updates for AA3
- SITE_URL introduced
- Redis cache fixed (#1352)
- Using the same type of quotes, not wildly mixing them
2022-09-06 22:50:49 +02:00
Peter Pfeufer
714431c932 [FIX] Check if character is online before accepting FAT click
Fixes #834
2022-08-07 12:08:57 +02:00
Peter Pfeufer
b026277ab0 [MISC] Clarify URL format
Seems his is causing confusion, so add a note that the URL should be without a trailing slash
2022-08-07 02:01:26 +02:00
Peter Pfeufer
11855f0b54 [FIX] Missing DOCTYPE and padding 2022-08-05 19:51:50 +02:00
Ariel Rin
635fbfe2c8 Version Bump v3.1.1 2022-08-05 21:35:51 +10:00
Ariel Rin
b10233daf0 Merge branch 'transifex' of https://gitlab.com/allianceauth/allianceauth 2022-08-05 21:23:58 +10:00
Ariel Rin
1aa3187491 Cap Django to 4.0.x 2022-08-05 21:23:40 +10:00
Ariel Rin
59f17a88f0 Update from Transifex 2022-08-05 21:20:32 +10:00
Peter Pfeufer
75db3195d4 CSS modernized 2022-08-02 23:56:47 +02:00
Peter Pfeufer
afe3fea757 Bundle the remaining static files
They are used in some template overrides. To prevent missing JS or CSS in the future in those template overrides, it's a good idea to provide HTML templates for these static files.
2022-08-01 14:15:55 +02:00
Ariel Rin
74651dd30a Update from Transifex 2022-07-30 18:21:20 +10:00
66 changed files with 5959 additions and 5374 deletions

View File

@@ -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.1.0'
__version__ = '3.2.0'
__title__ = 'Alliance Auth'
__url__ = 'https://gitlab.com/allianceauth/allianceauth'
NAME = f'{__title__} v{__version__}'

View File

@@ -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;
}

View File

@@ -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>

View File

@@ -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 {

View File

@@ -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 %}

View File

@@ -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),
}

View File

@@ -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),
),
]

View File

@@ -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)

View File

@@ -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 %}

View File

@@ -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">

View File

@@ -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 %}

View File

@@ -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 %}

View File

@@ -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 %}

View File

@@ -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 %}

View File

@@ -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')

View File

@@ -1,5 +1,4 @@
{% extends "allianceauth/base.html" %}
{% load static %}
{% load i18n %}
{% block page_title %}{{ group }} {% translate "Audit Log" %}{% endblock page_title %}

View File

@@ -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>

View File

@@ -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"

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -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>

View File

@@ -14,6 +14,7 @@ STATIC_ROOT = "/var/www/{{ project_name }}/static/"
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

View File

@@ -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()

View File

@@ -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)

View File

@@ -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),
]

View File

@@ -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():

View File

@@ -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")

View File

@@ -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;
}

View File

@@ -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>

View File

@@ -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">

View File

@@ -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">

View File

@@ -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>

View File

@@ -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 %}

View File

@@ -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"),
]

View File

@@ -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;
}
}

View File

@@ -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;
}

View File

@@ -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>

View File

@@ -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>

View File

@@ -0,0 +1,3 @@
{% load static %}
<link href="{% static 'allianceauth/css/auth-base.css' %}" rel="stylesheet">

View File

@@ -0,0 +1,3 @@
{% load static %}
<link href="{% static 'allianceauth/css/checkbox.css' %}" rel="stylesheet">

View File

@@ -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>

View File

@@ -1,5 +1,4 @@
{% extends "allianceauth/base.html" %}
{% load static %}
{% load i18n %}
{% get_current_language as LANGUAGE_CODE %}
{% load evelinks %}

View File

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

View File

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

View File

@@ -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,8 @@ 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 +44,37 @@ 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"
CELERY_RESULT_BACKEND = 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',
]
#######################################

View File

@@ -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.

View File

@@ -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
```

View File

@@ -0,0 +1,55 @@
# 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
sudo chown -R allianceserver: /home/allianceserver
sudo chown -R allianceserver: /var/www/myauth
sudo chmod -r 655 /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
```
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.

View File

@@ -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

View File

@@ -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

View File

@@ -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