Merge branch 'aa-framework-part-2' into 'v4.x'
Alliance Auth Framework (Part 2) See merge request allianceauth/allianceauth!1558
@ -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 %}
|
||||
|
@ -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
|
||||
),
|
||||
),
|
||||
]
|
@ -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):
|
||||
|
@ -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">
|
||||
|
@ -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 %}
|
||||
|
@ -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>
|
||||
|
@ -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 %}
|
||||
|
@ -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>
|
||||
|
@ -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">
|
||||
|
@ -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">
|
||||
|
@ -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">
|
||||
|
3
allianceauth/framework/__init__.py
Normal file
@ -0,0 +1,3 @@
|
||||
"""
|
||||
Alliance Auth Framework
|
||||
"""
|
64
allianceauth/framework/api/user.py
Normal 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
|
14
allianceauth/framework/apps.py
Normal file
@ -0,0 +1,14 @@
|
||||
"""
|
||||
Framework App Config
|
||||
"""
|
||||
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class FrameworkConfig(AppConfig):
|
||||
"""
|
||||
Framework App Config
|
||||
"""
|
||||
|
||||
name = "allianceauth.framework"
|
||||
label = "framework"
|
@ -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 %}
|
3
allianceauth/framework/tests/__init__.py
Normal file
@ -0,0 +1,3 @@
|
||||
"""
|
||||
Initializing our tests
|
||||
"""
|
179
allianceauth/framework/tests/test_api_user.py
Normal 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")
|
@ -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">
|
||||
|
@ -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">
|
||||
|
@ -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 -->
|
||||
|
@ -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 %}
|
||||
|
@ -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">
|
||||
|
@ -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">
|
||||
|
@ -25,6 +25,7 @@ INSTALLED_APPS = [
|
||||
'django_bootstrap5', # https://github.com/zostera/django-bootstrap5
|
||||
'sortedm2m',
|
||||
'esi',
|
||||
'allianceauth.framework',
|
||||
'allianceauth.authentication',
|
||||
'allianceauth.services',
|
||||
'allianceauth.eveonline',
|
||||
|
@ -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">
|
||||
|
@ -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>
|
||||
|
@ -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">
|
||||
|
@ -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">
|
||||
|
@ -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">
|
||||
|
@ -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">
|
||||
|
@ -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
|
||||
|
@ -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">
|
||||
|
@ -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">
|
||||
|
@ -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>
|
||||
|
@ -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 %}
|
||||
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
BIN
docs/_static/images/development/aa-framework/css/cursor-default.png
vendored
Normal file
After Width: | Height: | Size: 4.1 KiB |
BIN
docs/_static/images/development/aa-framework/css/cursor-help.png
vendored
Normal file
After Width: | Height: | Size: 4.4 KiB |
BIN
docs/_static/images/development/aa-framework/css/cursor-move.png
vendored
Normal file
After Width: | Height: | Size: 4.3 KiB |
BIN
docs/_static/images/development/aa-framework/css/cursor-not-allowed.png
vendored
Normal file
After Width: | Height: | Size: 6.1 KiB |
BIN
docs/_static/images/development/aa-framework/css/cursor-pointer.png
vendored
Normal file
After Width: | Height: | Size: 4.3 KiB |
BIN
docs/_static/images/development/aa-framework/css/cursor-text.png
vendored
Normal file
After Width: | Height: | Size: 3.7 KiB |
BIN
docs/_static/images/development/aa-framework/css/cursor-wait.png
vendored
Normal file
After Width: | Height: | Size: 4.4 KiB |
BIN
docs/_static/images/development/aa-framework/css/cursor-zoom-in.png
vendored
Normal file
After Width: | Height: | Size: 4.6 KiB |
BIN
docs/_static/images/development/aa-framework/css/cursor-zoom-out.png
vendored
Normal file
After Width: | Height: | Size: 4.5 KiB |
12
docs/development/custom/aa-framework.md
Normal file
@ -0,0 +1,12 @@
|
||||
# AA Framework
|
||||
|
||||
To establish a unified style language throughout Alliance Auth and Community Apps,
|
||||
Alliance Auth is providing its own CSS framework with a couple of CSS classes.
|
||||
|
||||
:::{toctree}
|
||||
:maxdepth: 1
|
||||
|
||||
framework/api
|
||||
framework/css
|
||||
framework/templates
|
||||
:::
|
@ -1,42 +0,0 @@
|
||||
# CSS Framework
|
||||
|
||||
To establish a unified style language throughout Alliance Auth and Community Apps,
|
||||
Alliance Auth is providing its own CSS framework with a couple of CSS classes.
|
||||
|
||||
## Callout-Boxes
|
||||
|
||||
These are similar to the Bootstrap alert/notification boxes, but not as "loud".
|
||||
|
||||
Callout-boxes need a base-class (`.aa-callout`) and a modifier-class (e.g.:
|
||||
`.aa-callout-info` for an info-box). Modifier classes are available for the usual
|
||||
Bootstrap alert levels "Success", "Info", "Warning" and "Danger".
|
||||
|
||||

|
||||
|
||||
### HTML
|
||||
|
||||
```html
|
||||
<div class="aa-callout aa-callout-success">
|
||||
<p>
|
||||
This is a success callout-box.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="aa-callout aa-callout-info">
|
||||
<p>
|
||||
This is an info callout-box.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="aa-callout aa-callout-warning">
|
||||
<p>
|
||||
This is a warning callout-box.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="aa-callout aa-callout-danger">
|
||||
<p>
|
||||
This is a danger callout-box.
|
||||
</p>
|
||||
</div>
|
||||
```
|
58
docs/development/custom/framework/api.md
Normal file
@ -0,0 +1,58 @@
|
||||
# Alliance Auth Helper-Functions API
|
||||
|
||||
## User API
|
||||
|
||||
### get_main_character_from_user
|
||||
|
||||
This is to get the main character object (`EveCharacter`) of a user.
|
||||
|
||||
Given we have a `User` object called `my_user` and we want to get the main character:
|
||||
|
||||
```python
|
||||
# Alliance Auth
|
||||
from allianceauth.framework.api.user import get_main_character_from_user
|
||||
|
||||
main_character = get_main_character_from_user(user=my_user)
|
||||
```
|
||||
|
||||
Now, `main_character` is an `EveCharacter` object, or `None` if the user has no main
|
||||
character or the user is `None`.
|
||||
|
||||
### get_main_character_name_from_user
|
||||
|
||||
This is to get the name of the main character of a user.
|
||||
|
||||
Given we have a `User` object called `my_user` and we want to get the main character name:
|
||||
|
||||
```python
|
||||
# Alliance Auth
|
||||
from allianceauth.framework.api.user import get_main_character_name_from_user
|
||||
|
||||
main_character = get_main_character_name_from_user(user=my_user)
|
||||
```
|
||||
|
||||
Now, `main_character` is a `string` containing the user's main character name.
|
||||
If the user has no main character, the username will be returned. If the user is `None`,
|
||||
the sentinel username (see [get_sentinel_user](#get-sentinel-user)) will be returned.
|
||||
|
||||
### get_sentinel_user
|
||||
|
||||
This function is useful in models when using `User` model-objects as foreign keys.
|
||||
Django needs to know what should happen to those relations when the user is being
|
||||
deleted. To keep the data, you can have Django map this to the sentinel user.
|
||||
|
||||
Import:
|
||||
|
||||
```python
|
||||
# Alliance Auth
|
||||
from allianceauth.framework.api.user import get_sentinel_user
|
||||
```
|
||||
|
||||
And later in your model:
|
||||
|
||||
```python
|
||||
creator = models.ForeignKey(
|
||||
to=User,
|
||||
on_delete=models.SET(get_sentinel_user),
|
||||
)
|
||||
```
|
73
docs/development/custom/framework/css.md
Normal file
@ -0,0 +1,73 @@
|
||||
# CSS Framework
|
||||
|
||||
To establish a unified style language throughout Alliance Auth and Community Apps,
|
||||
Alliance Auth is providing its own CSS framework with a couple of CSS classes.
|
||||
|
||||
## Cursors
|
||||
|
||||
Our CSS framework provides different classes to manipulate the cursor, which are
|
||||
missing in Bootstrap.
|
||||
|
||||
```{eval-rst}
|
||||
+----------------------+--------------------------------------------------------+--------------------------------------------------------------------------------+
|
||||
| CSS Class | Effect | Example |
|
||||
+======================+========================================================+================================================================================+
|
||||
| `cursor-default` | System default curser | .. image:: /_static/images/development/aa-framework/css/cursor-default.png |
|
||||
+----------------------+--------------------------------------------------------+--------------------------------------------------------------------------------+
|
||||
| `cursor-pointer` | Pointer, like it looks like for links and form buttons | .. image:: /_static/images/development/aa-framework/css/cursor-pointer.png |
|
||||
+----------------------+--------------------------------------------------------+--------------------------------------------------------------------------------+
|
||||
| `cursor-wait` | Wait animation | .. image:: /_static/images/development/aa-framework/css/cursor-wait.png |
|
||||
+----------------------+--------------------------------------------------------+--------------------------------------------------------------------------------+
|
||||
| `cursor-text` | Text selection cursor | .. image:: /_static/images/development/aa-framework/css/cursor-text.png |
|
||||
+----------------------+--------------------------------------------------------+--------------------------------------------------------------------------------+
|
||||
| `cursor-move` | 4-arrow-shaped cursor | .. image:: /_static/images/development/aa-framework/css/cursor-move.png |
|
||||
+----------------------+--------------------------------------------------------+--------------------------------------------------------------------------------+
|
||||
| `cursor-help` | Cursor with a little question mark | .. image:: /_static/images/development/aa-framework/css/cursor-help.png |
|
||||
+----------------------+--------------------------------------------------------+--------------------------------------------------------------------------------+
|
||||
| `cursor-not-allowed` | Not Allowed sign | .. image:: /_static/images/development/aa-framework/css/cursor-not-allowed.png |
|
||||
+----------------------+--------------------------------------------------------+--------------------------------------------------------------------------------+
|
||||
| `cursor-inherit` | Inherited from its parent element | |
|
||||
+----------------------+--------------------------------------------------------+--------------------------------------------------------------------------------+
|
||||
| `cursor-zoom-in` | Zoom in symbol | .. image:: /_static/images/development/aa-framework/css/cursor-zoom-in.png |
|
||||
+----------------------+--------------------------------------------------------+--------------------------------------------------------------------------------+
|
||||
| `cursor-zoom-out` | Zoom out symbol | .. image:: /_static/images/development/aa-framework/css/cursor-zoom-out.png |
|
||||
+----------------------+--------------------------------------------------------+--------------------------------------------------------------------------------+
|
||||
```
|
||||
|
||||
## Callout-Boxes
|
||||
|
||||
These are similar to the Bootstrap alert/notification boxes, but not as "loud".
|
||||
|
||||
Callout-boxes need a base-class (`.aa-callout`) and a modifier-class (e.g.:
|
||||
`.aa-callout-info` for an info-box). Modifier classes are available for the usual
|
||||
Bootstrap alert levels "Success", "Info", "Warning" and "Danger".
|
||||
|
||||

|
||||
|
||||
### HTML
|
||||
|
||||
```html
|
||||
<div class="aa-callout aa-callout-success">
|
||||
<p>
|
||||
This is a success callout-box.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="aa-callout aa-callout-info">
|
||||
<p>
|
||||
This is an info callout-box.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="aa-callout aa-callout-warning">
|
||||
<p>
|
||||
This is a warning callout-box.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="aa-callout aa-callout-danger">
|
||||
<p>
|
||||
This is a danger callout-box.
|
||||
</p>
|
||||
</div>
|
||||
```
|
46
docs/development/custom/framework/templates.md
Normal file
@ -0,0 +1,46 @@
|
||||
# Templates
|
||||
|
||||
## Bundles
|
||||
|
||||
As bundles, we see templates that load essential CSS and JavaScript and are used
|
||||
throughout Alliance Auth. These bundles can also be used in your own apps, so you don't
|
||||
have to load specific CSS or JavaScript yourself.
|
||||
|
||||
These bundles include DataTables CSS and JS, jQuery Datepicker CSS and JS, jQueryUI CSS and JS, and more.
|
||||
|
||||
A full list of bundles we provide can be found here: https://gitlab.com/allianceauth/allianceauth/-/tree/master/allianceauth/templates/bundles
|
||||
|
||||
To use a bundle, you can use the following code in your template (Example for jQueryUI):
|
||||
|
||||
```django
|
||||
{% block extra_css %}
|
||||
{% include "bundles/jquery-ui-css.html" %}
|
||||
{% endblock %}
|
||||
|
||||
{% block extra_javascript %}
|
||||
{% include "bundles/jquery-ui-js.html" %}
|
||||
{% endblock %}
|
||||
```
|
||||
|
||||
## Template Partials
|
||||
|
||||
To ensure a unified style language throughout Alliance Auth and Community Apps,
|
||||
we also provide a couple of template partials. This collection is bound to grow over
|
||||
time, so best have an eye on this page.
|
||||
|
||||
### Page Header
|
||||
|
||||
On some pages you want to have a page header. To make this easier, we provide a template partial for this.
|
||||
|
||||
To use it, you can use the following code in your template:
|
||||
|
||||
```django
|
||||
{% block content %}
|
||||
<div>
|
||||
{% translate "My Page Header" as page_header %}
|
||||
{% include "framework/header/page-header.html" with title=page_header %}
|
||||
|
||||
<p>My page content</p>
|
||||
</div>
|
||||
{% endblock %}
|
||||
```
|
@ -9,5 +9,5 @@ integrating-services
|
||||
menu-hooks
|
||||
url-hooks
|
||||
logging
|
||||
css-framework
|
||||
aa-framework
|
||||
:::
|
||||
|