Merge branch 'aa-framework-part-2' into 'v4.x'

Alliance Auth Framework (Part 2)

See merge request allianceauth/allianceauth!1558
This commit is contained in:
Ariel Rin
2023-12-25 09:46:57 +00:00
52 changed files with 614 additions and 179 deletions

View File

@@ -14,15 +14,13 @@ Needs to be called with a context containing three objects:
{% block page_title %}Evelinks Examples{% endblock page_title %}
{% block content %}
<div>
{% include "framework/header/page-header.html" with title="Evelinks templatetags examples" %}
<div class="col-lg-12">
<h1 class="page-header text-center mb-3">Evelinks templatetags examples</h1>
<div class="col-lg-12 container">
<h2>profile URLs</h2>
<div class="rows">
<div class="col-md-4">
<h3>evewho</h3>
<p><a href="{{ my_character|evewho_character_url }}">character from character object</a></p>
@@ -57,7 +55,6 @@ Needs to be called with a context containing three objects:
<h2>image URLs</h2>
<div class="rows">
<div class="col-md-4">
<p>character from ID: <img src="{{ my_character.character_id|character_portrait_url:128 }}"></p>
<p>character from character object: <img src="{{ my_character|character_portrait_url:128 }}"></p>
@@ -77,5 +74,4 @@ Needs to be called with a context containing three objects:
</div>
</div>
</div>
{% endblock content %}

View File

@@ -0,0 +1,26 @@
"""
Migration to AA Framework API method
"""
from django.conf import settings
from django.db import migrations, models
import allianceauth.framework.api.user
class Migration(migrations.Migration):
dependencies = [
("fleetactivitytracking", "0006_auto_20180803_0430"),
]
operations = [
migrations.AlterField(
model_name="fatlink",
name="creator",
field=models.ForeignKey(
on_delete=models.SET(allianceauth.framework.api.user.get_sentinel_user),
to=settings.AUTH_USER_MODEL
),
),
]

View File

@@ -3,10 +3,7 @@ from django.db import models
from django.utils import timezone
from allianceauth.eveonline.models import EveCharacter
def get_sentinel_user():
return User.objects.get_or_create(username='deleted')[0]
from allianceauth.framework.api.user import get_sentinel_user
class Fatlink(models.Model):

View File

@@ -12,9 +12,8 @@
{% block content %}
<div>
<h1 class="page-header text-center mb-3">
{% translate "Character not found!" %}
</h1>
{% translate "Character not found!" as page_header %}
{% include "framework/header/page-header.html" with title=page_header %}
<div class="col-lg-12 container">
<div class="row">

View File

@@ -13,9 +13,8 @@
{% block content %}
<div>
<h1 class="page-header text-center mb-3">
{% translate "Create Fatlink" %}
</h1>
{% translate "Create Fatlink" as page_header %}
{% include "framework/header/page-header.html" with title=page_header %}
<div>
{% if badrequest %}

View File

@@ -14,16 +14,16 @@
<div>
<h1 class="page-header text-center mb-3">
{% translate "Edit fatlink" %} "{{ fatlink }}"
<div class="text-end">
<form>
<button type="submit" onclick="return confirm('{% translate "Are you sure?" %}')" class="btn btn-danger" name="deletefat" value="True">
{% translate "Delete fat" %}
</button>
</form>
</div>
</h1>
<div class="text-end mb-3">
<form>
<button type="submit" onclick="return confirm('{% translate "Are you sure?" %}')" class="btn btn-danger" name="deletefat" value="True">
{% translate "Delete fat" %}
</button>
</form>
</div>
<div class="card card-default">
<div class="card-header">
<div class="card-title mb-0">{% translate "Registered characters" %}</div>

View File

@@ -14,20 +14,20 @@
<div>
<h1 class="page-header text-center mb-3">
{% blocktranslate %}Participation data statistics for {{ month }}, {{ year }}{% endblocktranslate %}
{% if char_id %}
<div class="text-end">
<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>
<a href="{% url 'fatlink:user_statistics_month' char_id next_month|date:'Y' next_month|date:'m' %}" class="btn btn-info">
{% translate "Next month" %}
</a>
</div>
{% endif %}
</h1>
<div class="card card-default mb-4">
{% if char_id %}
<div class="text-end mb-3">
<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>
<a href="{% url 'fatlink:user_statistics_month' char_id next_month|date:'Y' next_month|date:'m' %}" class="btn btn-info">
{% translate "Next month" %}
</a>
</div>
{% endif %}
<div class="card card-default mb-3">
<div class="card-header">
<div class="card-title mb-0">
{% blocktranslate count links=n_fats trimmed %}

View File

@@ -14,16 +14,16 @@
<div>
<h1 class="page-header text-center mb-3">
{% blocktranslate %}Participation data statistics for {{ year }}{% endblocktranslate %}
<div class="text-end">
<a href="{% url "fatlink:personal_statistics_year" previous_year %}" class="btn btn-info"><i class="fa-solid fa-chevron-left"></i> {% translate "Previous year" %}</a>
{% if next_year %}
<a href="{% url "fatlink:personal_statistics_year" next_year %}" class="btn btn-info">{% translate "Next year" %} <i class="fa-solid fa-chevron-right"></i></a>
{% endif %}
</div>
</h1>
<div class="text-end mb-3">
<a href="{% url "fatlink:personal_statistics_year" previous_year %}" class="btn btn-info"><i class="fa-solid fa-chevron-left"></i> {% translate "Previous year" %}</a>
{% if next_year %}
<a href="{% url "fatlink:personal_statistics_year" next_year %}" class="btn btn-info">{% translate "Next year" %} <i class="fa-solid fa-chevron-right"></i></a>
{% endif %}
</div>
<div class="col-lg-2 offset-lg-5">
<table class="table table-responsive">
<tr>

View File

@@ -11,19 +11,19 @@
{% endblock header_nav_brand %}
{% block content %}
<div class="col-lg-12">
<div>
<h1 class="page-header text-center mb-3">
{% blocktranslate %}Participation data statistics for {{ month }}, {{ year }}{% endblocktranslate %}
<div class="text-end">
<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 %}
<a href="{% url "fatlink:statistics_corp_month" corpid next_month|date:"Y" next_month|date:"m" %}" class="btn btn-info">{% translate "Next month" %}</a>
{% endif %}
</div>
</h1>
<div class="text-end mb-3">
<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 %}
<a href="{% url "fatlink:statistics_corp_month" corpid next_month|date:"Y" next_month|date:"m" %}" class="btn btn-info">{% translate "Next month" %}</a>
{% endif %}
</div>
{% if fatStats %}
<div class="table-responsive">
<table class="table table-striped">

View File

@@ -14,16 +14,16 @@
<div>
<h1 class="page-header text-center mb-3">
{% blocktranslate %}Participation data statistics for {{ month }}, {{ year }}{% endblocktranslate %}
<div class="text-end">
<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 %}
<a href="{% url 'fatlink:statistics_month' next_month|date:"Y" next_month|date:"m" %}" class="btn btn-info">{% translate "Next month" %}</a>
{% endif %}
</div>
</h1>
<div class="text-end mb-3">
<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 %}
<a href="{% url 'fatlink:statistics_month' next_month|date:"Y" next_month|date:"m" %}" class="btn btn-info">{% translate "Next month" %}</a>
{% endif %}
</div>
{% if fatStats %}
<div class="table-responsive">
<table class="table table-striped">

View File

@@ -11,10 +11,9 @@
{% endblock header_nav_brand %}
{% block content %}
<div class="col-lg-12">
<h1 class="page-header text-center mb-3">
{% translate "Participation data" %}
</h1>
<div>
{% translate "Participation data" as page_header %}
{% include "framework/header/page-header.html" with title=page_header %}
<div class="table-responsive">
<table class="table table-striped">

View File

@@ -0,0 +1,3 @@
"""
Alliance Auth Framework
"""

View File

@@ -0,0 +1,64 @@
"""
Alliance Auth User API
"""
from typing import Optional
from django.contrib.auth.models import User
from allianceauth.eveonline.models import EveCharacter
def get_sentinel_user() -> User:
"""
Get the sentinel user or create one
:return:
"""
return User.objects.get_or_create(username="deleted")[0]
def get_main_character_from_user(user: User) -> Optional[EveCharacter]:
"""
Get the main character from a user
:param user:
:type user:
:return:
:rtype:
"""
if user is None:
return None
try:
main_character = user.profile.main_character
except AttributeError:
return None
return main_character
def get_main_character_name_from_user(user: User) -> str:
"""
Get the main character name from a user
:param user:
:type user:
:return:
:rtype:
"""
if user is None:
sentinel_user = get_sentinel_user()
return sentinel_user.username
main_character = get_main_character_from_user(user=user)
try:
username = main_character.character_name
except AttributeError:
return str(user)
return username

View File

@@ -0,0 +1,14 @@
"""
Framework App Config
"""
from django.apps import AppConfig
class FrameworkConfig(AppConfig):
"""
Framework App Config
"""
name = "allianceauth.framework"
label = "framework"

View File

@@ -0,0 +1,13 @@
{#Usage:#}
{# {% include "framework/header/page-header.html" with title="Foobar" subtitle="Barfoo" %}#}
{% if title %}
<h1 class="page-header text-center mb-3">
{{ title }}
{% if subtitle %}
<br>
<small>{{ subtitle }}</small>
{% endif %}
</h1>
{% endif %}

View File

@@ -0,0 +1,3 @@
"""
Initializing our tests
"""

View File

@@ -0,0 +1,179 @@
"""
Test sentinel user
"""
import re
# Django
from django.contrib.auth.models import User
from django.test import TestCase
# Alliance Auth
from allianceauth.framework.api.user import (
get_sentinel_user,
get_main_character_from_user,
get_main_character_name_from_user
)
from allianceauth.tests.auth_utils import AuthUtils
class TestSentinelUser(TestCase):
"""
Tests for the sentinel user
"""
def test_should_create_user_when_it_does_not_exist(self) -> None:
"""
Test should create a sentinel user when it doesn't exist
:return:
:rtype:
"""
# when
user = get_sentinel_user()
# then
self.assertEqual(first=user.username, second="deleted")
def test_should_return_user_when_it_does(self) -> None:
"""
Test should return sentinel user when it exists
:return:
:rtype:
"""
# given
User.objects.create_user(username="deleted")
# when
user = get_sentinel_user()
# then
self.assertEqual(first=user.username, second="deleted")
class TestGetMainForUser(TestCase):
"""
Tests for get_main_character_from_user
"""
@classmethod
def setUpClass(cls) -> None:
"""
Set up groups and users
"""
super().setUpClass()
cls.character_name = "William T. Riker"
cls.character_name_2 = "Christopher Pike"
cls.username = re.sub(pattern=r"[^\w\d@\.\+-]", repl="_", string=cls.character_name)
cls.username_2 = re.sub(
pattern=r"[^\w\d@\.\+-]", repl="_", string=cls.character_name_2
)
cls.user = AuthUtils.create_user(username=cls.username)
cls.user_without_main = AuthUtils.create_user(
username=cls.username_2, disconnect_signals=True
)
cls.character = AuthUtils.add_main_character_2(
user=cls.user, name=cls.character_name, character_id=1001
)
def test_get_main_character_from_user_should_return_character_name(self):
"""
Test should return the main character name for a regular user
:return:
:rtype:
"""
character = get_main_character_from_user(user=self.user)
self.assertEqual(first=character, second=self.character)
def test_get_main_character_from_user_should_return_none_for_no_main_character(self):
"""
Test should return None for User without a main character
:return:
:rtype:
"""
character = get_main_character_from_user(user=self.user_without_main)
self.assertIsNone(obj=character)
def test_get_main_character_from_user_should_none(self):
"""
Test should return None when user is None
:return:
:rtype:
"""
user = None
character = get_main_character_from_user(user=user)
self.assertIsNone(obj=character)
def test_get_main_character_name_from_user_should_return_character_name(self):
"""
Test should return the main character name for a regular user
:return:
:rtype:
"""
character_name = get_main_character_name_from_user(user=self.user)
self.assertEqual(first=character_name, second=self.character_name)
def test_get_main_character_name_from_user_should_return_user_name(self):
"""
Test should return just the username for a user without a main character
:return:
:rtype:
"""
character_name = get_main_character_name_from_user(user=self.user_without_main)
self.assertEqual(first=character_name, second=self.username_2)
def test_get_main_character_name_from_user_should_return_sentinel_user(self):
"""
Test should return "deleted" as username (Sentinel User)
:return:
:rtype:
"""
user = get_sentinel_user()
character_name = get_main_character_name_from_user(user=user)
self.assertEqual(first=character_name, second="deleted")
def test_get_main_character_name_from_user_should_return_sentinel_user_for_none(self):
"""
Test should return "deleted" (Sentinel User) if user is None
:return:
:rtype:
"""
user = None
character_name = get_main_character_name_from_user(user=user)
self.assertEqual(first=character_name, second="deleted")

View File

@@ -12,9 +12,8 @@
{% block content %}
<div>
<h1 class="page-header text-center mb-3">
{% translate "Choose a Corp" %}
</h1>
{% translate "Choose a Corp" as page_header %}
{% include "framework/header/page-header.html" with title=page_header %}
{% if choices %}
<div class="card card-primary">

View File

@@ -13,17 +13,18 @@
{% block content %}
<div>
<h1 class="page-header text-center mb-3">{% translate "Personal Applications" %}
<div class="text-end">
{% if create %}
<a href="{% url 'hrapplications:create_view' %}">
<button type="button" class="btn btn-success">{% translate "Create Application" %}</button>
</a>
{% else %}
<button type="button" class="btn btn-success" disabled>{% translate "Create Application" %}</button>
{% endif %}
</div>
</h1>
{% translate "Personal Applications" as page_header %}
{% include "framework/header/page-header.html" with title=page_header %}
<div class="text-end mb-3">
{% if create %}
<a href="{% url 'hrapplications:create_view' %}">
<button type="button" class="btn btn-success">{% translate "Create Application" %}</button>
</a>
{% else %}
<button type="button" class="btn btn-success" disabled>{% translate "Create Application" %}</button>
{% endif %}
</div>
{% if personal_apps %}
<div class="card card-default mb-3">
@@ -68,16 +69,17 @@
{% endif %}
{% if perms.auth.human_resources %}
<h1 class="page-header text-center mb-3">{% translate "Application Management" %}
<div class="text-end">
<!-- Button trigger modal -->
<button type="button" class="btn btn-primary btn-sm" data-bs-toggle="modal" data-bs-target="#modal-hr-search">
{% translate "Search Applications" %}
</button>
</div>
</h1>
{% translate "Application Management" as page_header %}
{% include "framework/header/page-header.html" with title=page_header %}
<div class="card card-default mt-4">
<div class="text-end mb-3">
<!-- Button trigger modal -->
<button type="button" class="btn btn-primary btn-sm" data-bs-toggle="modal" data-bs-target="#modal-hr-search">
{% translate "Search Applications" %}
</button>
</div>
<div class="card card-default">
<div class="card-body clearfix">
<ul class="nav nav-tabs" id="application-list" role="tablist">
<li class="nav-item" role="presentation">

View File

@@ -14,9 +14,8 @@
{% block content %}
<div>
{% if perms.auth.human_resources %}
<h1 class="page-header text-center mb-3">
{% translate "Application Search Results" %}
</h1>
{% translate "Application Search Results" as page_header %}
{% include "framework/header/page-header.html" with title=page_header %}
<div class="text-end mb-3">
<!-- Button trigger modal -->

View File

@@ -13,7 +13,8 @@
{% block content %}
<div>
<h1 class="page-header text-center mb-3">{% translate "View Application" %}</h1>
{% translate "View Application" as page_header %}
{% include "framework/header/page-header.html" with title=page_header %}
<div>
{% if app.approved %}

View File

@@ -18,9 +18,8 @@
{% block content %}
<div>
<h1 class="page-header text-center mb-3">
{% translate "Create Fleet Operation" %}
</h1>
{% translate "Create Fleet Operation" as page_header %}
{% include "framework/header/page-header.html" with title=page_header %}
<div class="card card-primary border-0">
<div class="card-header">

View File

@@ -18,9 +18,8 @@
{% block content %}
<div>
<h1 class="page-header text-center mb-3">
{% translate "Update Fleet Operation" %}
</h1>
{% translate "Update Fleet Operation" as page_header %}
{% include "framework/header/page-header.html" with title=page_header %}
<div class="card card-primary border-0">
<div class="card-header">

View File

@@ -25,6 +25,7 @@ INSTALLED_APPS = [
'django_bootstrap5', # https://github.com/zostera/django-bootstrap5
'sortedm2m',
'esi',
'allianceauth.framework',
'allianceauth.authentication',
'allianceauth.services',
'allianceauth.eveonline',

View File

@@ -7,9 +7,8 @@
{% block content %}
<div class="col-lg-12">
<h1 class="page-header text-center mb-3">
{% translate "Verify TeamSpeak3 Identity" %}
</h1>
{% translate "Verify TeamSpeak3 Identity" as page_header %}
{% include "framework/header/page-header.html" with title=page_header %}
<div class="row justify-content-center">
<div class="col-md-4">

View File

@@ -11,7 +11,7 @@
{% endblock header_nav_brand %}
{% block content %}
<div class="col-lg-12">
<div>
<h1 class="page-header text-center mb-3">
{% blocktranslate with service_name=view.service_name|title %}{{ service_name }} Credentials{% endblocktranslate %}
</h1>

View File

@@ -17,9 +17,8 @@
{% block content %}
<div>
<h1 class="page-header text-center mb-3">
{% translate "Create SRP Fleet" %}
</h1>
{% translate "Create SRP Fleet" as page_header %}
{% include "framework/header/page-header.html" with title=page_header %}
<div class="card card-primary border-0">
<div class="card-header">

View File

@@ -13,23 +13,22 @@
{% block content %}
<div>
<h1 class="page-header text-center mb-3">
{% translate "SRP Fleet Data" %}
{% translate "SRP Fleet Data" as page_header %}
{% include "framework/header/page-header.html" with title=page_header %}
<div class="text-end">
{% if perms.auth.srp_management %}
{% if fleet_status == "Completed" %}
<a href="{% url 'srp:mark_uncompleted' fleet_id %}" class="btn btn-warning">
{% translate "Mark Incomplete" %}
</a>
{% else %}
<a href="{% url 'srp:mark_completed' fleet_id %}" class="btn btn-success">
{% translate "Mark Completed" %}
</a>
{% endif %}
<div class="text-end mb-3">
{% if perms.auth.srp_management %}
{% if fleet_status == "Completed" %}
<a href="{% url 'srp:mark_uncompleted' fleet_id %}" class="btn btn-warning">
{% translate "Mark Incomplete" %}
</a>
{% else %}
<a href="{% url 'srp:mark_completed' fleet_id %}" class="btn btn-success">
{% translate "Mark Completed" %}
</a>
{% endif %}
</div>
</h1>
{% endif %}
</div>
{% if srpfleetrequests %}
<form method="POST">

View File

@@ -13,9 +13,8 @@
{% block content %}
<div>
<h1 class="page-header text-center mb-3">
{% translate "Create SRP Request" %}
</h1>
{% translate "Create SRP Request" as page_header %}
{% include "framework/header/page-header.html" with title=page_header %}
<div class="card card-primary border-0">
<div class="card-header">

View File

@@ -13,9 +13,8 @@
{% block content %}
<div>
<h1 class="page-header text-center mb-3">
{% translate "Update AAR Link" %}
</h1>
{% translate "Update AAR Link" as page_header %}
{% include "framework/header/page-header.html" with title=page_header %}
<div class="card card-primary border-0">
<div class="card-header">

View File

@@ -5,8 +5,8 @@
{% endblock page_title %}
{% block content %}
<div class="col-lg-12">
<h1 class="page-header text-center mb-3">{{ error_title }}</h1>
<div>
{% include "framework/header/page-header.html" with title=error_title %}
<div class="text-center">
<svg

View File

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

View File

@@ -15,9 +15,10 @@
<h1 class="page-header text-center mb-3">
{% block page_header %}
{% endblock page_header %}
{% include "timerboard/index_button.html" %}
</h1>
{% include "timerboard/index_button.html" %}
<div class="card card-primary border-0">
<div class="card-header">
<div class="card-title mb-0">

View File

@@ -1,5 +1,5 @@
{% load i18n %}
<div class="text-end">
<div class="text-end mb-3">
<a href="{% url 'timerboard:view' %}" class="btn btn-secondary">{% translate "Back" %}</a>
</div>

View File

@@ -12,13 +12,13 @@
{% block content %}
<div>
<h1 class="page-header text-center mb-3">
{% translate "Delete Timer" %}
{% include "timerboard/index_button.html" %}
</h1>
{% translate "Delete Timer" as page_header %}
{% include "framework/header/page-header.html" with title=page_header %}
{% include "timerboard/index_button.html" %}
<div class="row justify-content-center">
<div class="col-md-2">
<div class="col-md-4">
<div class="row">
<form action="" method="post">
{% csrf_token %}