Compare commits
45 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5250432ce3 | ||
|
|
53d6e973eb | ||
|
|
c9bdd62d53 | ||
|
|
7eb98af528 | ||
|
|
385e3e21b3 | ||
|
|
127ec63d76 | ||
|
|
4988b5f260 | ||
|
|
f28a50f92c | ||
|
|
e8efe8e609 | ||
|
|
d7e7457bc5 | ||
|
|
daff927811 | ||
|
|
8861ec0a61 | ||
|
|
bd4321f61a | ||
|
|
d831482fe0 | ||
|
|
73f262ce4b | ||
|
|
f63434adc3 | ||
|
|
32e0621b0a | ||
|
|
78e05b84e9 | ||
|
|
76ebd21163 | ||
|
|
38aaf545c6 | ||
|
|
527d7ef671 | ||
|
|
e54b80e061 | ||
|
|
27f95a8b2c | ||
|
|
a1e8903128 | ||
|
|
b00ac2aef4 | ||
|
|
8865d15ed9 | ||
|
|
fc3d4b7f33 | ||
|
|
934cc44540 | ||
|
|
106de3dd4c | ||
|
|
9b55cfcbe3 | ||
|
|
8137f1023a | ||
|
|
d670e33b6f | ||
|
|
3d3bb8fc94 | ||
|
|
9c880eae8a | ||
|
|
54a71630f1 | ||
|
|
923a8453cc | ||
|
|
00447ca819 | ||
|
|
ad4ee9d822 | ||
|
|
40e9dbfda2 | ||
|
|
b9da6911e6 | ||
|
|
81f9211098 | ||
|
|
8290081365 | ||
|
|
81af610c11 | ||
|
|
cfa2cf58f3 | ||
|
|
01c17d28f6 |
3
.gitignore
vendored
@@ -69,3 +69,6 @@ celerybeat-schedule
|
|||||||
|
|
||||||
#gitlab configs
|
#gitlab configs
|
||||||
.gitlab/
|
.gitlab/
|
||||||
|
|
||||||
|
#transifex
|
||||||
|
.tx/
|
||||||
|
|||||||
@@ -6,25 +6,45 @@ before_script:
|
|||||||
- python -V
|
- python -V
|
||||||
- pip install wheel tox
|
- pip install wheel tox
|
||||||
|
|
||||||
test-3.5:
|
test-3.5-core:
|
||||||
image: python:3.5-buster
|
image: python:3.5-buster
|
||||||
script:
|
script:
|
||||||
- tox -e py35
|
- tox -e py35-core
|
||||||
|
|
||||||
test-3.6:
|
test-3.6-core:
|
||||||
image: python:3.6-buster
|
image: python:3.6-buster
|
||||||
script:
|
script:
|
||||||
- tox -e py36
|
- tox -e py36-core
|
||||||
|
|
||||||
test-3.7:
|
test-3.7-core:
|
||||||
image: python:3.7-buster
|
image: python:3.7-buster
|
||||||
script:
|
script:
|
||||||
- tox -e py37
|
- tox -e py37-core
|
||||||
|
|
||||||
test-3.8:
|
test-3.8-core:
|
||||||
image: python:3.8-buster
|
image: python:3.8-buster
|
||||||
script:
|
script:
|
||||||
- tox -e py38
|
- tox -e py38-core
|
||||||
|
|
||||||
|
test-3.5-all:
|
||||||
|
image: python:3.5-buster
|
||||||
|
script:
|
||||||
|
- tox -e py35-all
|
||||||
|
|
||||||
|
test-3.6-all:
|
||||||
|
image: python:3.6-buster
|
||||||
|
script:
|
||||||
|
- tox -e py36-all
|
||||||
|
|
||||||
|
test-3.7-all:
|
||||||
|
image: python:3.7-buster
|
||||||
|
script:
|
||||||
|
- tox -e py37-all
|
||||||
|
|
||||||
|
test-3.8-all:
|
||||||
|
image: python:3.8-buster
|
||||||
|
script:
|
||||||
|
- tox -e py38-all
|
||||||
|
|
||||||
deploy_production:
|
deploy_production:
|
||||||
stage: deploy
|
stage: deploy
|
||||||
|
|||||||
18
README.md
@@ -11,32 +11,34 @@
|
|||||||
|
|
||||||
An auth system for EVE Online to help in-game organizations manage online service access.
|
An auth system for EVE Online to help in-game organizations manage online service access.
|
||||||
|
|
||||||
## Contens
|
## Content
|
||||||
|
|
||||||
- [Overview](#overview)
|
- [Overview](#overview)
|
||||||
- [Documentation](http://allianceauth.rtfd.io)
|
- [Documentation](http://allianceauth.rtfd.io)
|
||||||
- [Support](#support)
|
- [Support](#support)
|
||||||
- [Release Notes](https://gitlab.com/allianceauth/allianceauth/-/releases)
|
- [Release Notes](https://gitlab.com/allianceauth/allianceauth/-/releases)
|
||||||
- [Devloper Team](#developer-team)
|
- [Developer Team](#developer-team)
|
||||||
- [Contributing](#contributing)
|
- [Contributing](#contributing)
|
||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
|
|
||||||
Alliance Auth (AA) is a web application that helps Eve Online organizations efficiently manage access to their applications and services.
|
Alliance Auth (AA) is a web site that helps Eve Online organizations efficiently manage access to applications and services.
|
||||||
|
|
||||||
Main features:
|
Main features:
|
||||||
|
|
||||||
- Automatically grants or revokes user access to external applications / services (e.g. Discord, Mumble) and web apps (e.g. SRP requests) based on the user's current membership to [in-game organizations](https://allianceauth.readthedocs.io/en/latest/features/states/) and [groups](https://allianceauth.readthedocs.io/en/latest/features/groups/)
|
- Automatically grants or revokes user access to external services (e.g. Discord, Mumble) and web apps (e.g. SRP requests) based on the user's current membership to [in-game organizations](https://allianceauth.readthedocs.io/en/latest/features/core/states/) and [groups](https://allianceauth.readthedocs.io/en/latest/features/core/groups/)
|
||||||
|
|
||||||
- Provides a central web site where users can directly access web apps (e.g. SRP requests, Fleet Schedule) and manage their access to external services and groups.
|
- Provides a central web site where users can directly access web apps (e.g. SRP requests, Fleet Schedule) and manage their access to external services and groups.
|
||||||
|
|
||||||
- Includes a set of connectors (called ["services"](https://allianceauth.readthedocs.io/en/latest/installation/services/)) for integrating access management with many popular external applications / services like Discord, Mumble, Teamspeak 3, SMF and others
|
- Includes a set of connectors (called ["services"](https://allianceauth.readthedocs.io/en/latest/features/services/)) for integrating access management with many popular external applications / services like Discord, Mumble, Teamspeak 3, SMF and others
|
||||||
|
|
||||||
- Includes a set of web apps called ["plug-in apps"](https://allianceauth.readthedocs.io/en/latest/features/) which add many useful functions: fleet schedule, timer board, SRP request management, fleet activity tracker and character application management
|
- Includes a set of web [apps](https://allianceauth.readthedocs.io/en/latest/features/apps/) which add many useful functions, e.g.: fleet schedule, timer board, SRP request management, fleet activity tracker
|
||||||
|
|
||||||
- Can be easily extended with new services and plugin-apps. Many additional services and plugin-apps are provided by the community and can be found here: [Community Creations](https://gitlab.com/allianceauth/community-creations)
|
- Can be easily extended with additional services and apps. Many are provided by the community and can be found here: [Community Creations](https://gitlab.com/allianceauth/community-creations)
|
||||||
|
|
||||||
For further details about AA - including an installation guide and a full list of included services and plugin apps - please see the [offical documentation](http://allianceauth.rtfd.io).
|
- Chinese :cn:, English :us:, German :de: and Spanish :es: localization
|
||||||
|
|
||||||
|
For further details about AA - including an installation guide and a full list of included services and plugin apps - please see the [official documentation](http://allianceauth.rtfd.io).
|
||||||
|
|
||||||
## Screenshot
|
## Screenshot
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# This will make sure the app is always imported when
|
# This will make sure the app is always imported when
|
||||||
# Django starts so that shared_task will use this app.
|
# Django starts so that shared_task will use this app.
|
||||||
|
|
||||||
__version__ = '2.6.0'
|
__version__ = '2.6.3'
|
||||||
NAME = 'Alliance Auth v%s' % __version__
|
NAME = 'Alliance Auth v%s' % __version__
|
||||||
default_app_config = 'allianceauth.apps.AllianceAuthConfig'
|
default_app_config = 'allianceauth.apps.AllianceAuthConfig'
|
||||||
|
|||||||
@@ -18,14 +18,14 @@ from django.utils.text import slugify
|
|||||||
from allianceauth.authentication.models import State, get_guest_state,\
|
from allianceauth.authentication.models import State, get_guest_state,\
|
||||||
CharacterOwnership, UserProfile, OwnershipRecord
|
CharacterOwnership, UserProfile, OwnershipRecord
|
||||||
from allianceauth.hooks import get_hooks
|
from allianceauth.hooks import get_hooks
|
||||||
from allianceauth.eveonline.models import EveCharacter, EveCorporationInfo
|
from allianceauth.eveonline.models import EveCharacter, EveCorporationInfo,\
|
||||||
|
EveAllianceInfo
|
||||||
from allianceauth.eveonline.tasks import update_character
|
from allianceauth.eveonline.tasks import update_character
|
||||||
from .app_settings import AUTHENTICATION_ADMIN_USERS_MAX_GROUPS, \
|
from .app_settings import AUTHENTICATION_ADMIN_USERS_MAX_GROUPS, \
|
||||||
AUTHENTICATION_ADMIN_USERS_MAX_CHARS
|
AUTHENTICATION_ADMIN_USERS_MAX_CHARS
|
||||||
|
|
||||||
if 'allianceauth.eveonline.autogroups' in settings.INSTALLED_APPS:
|
if 'allianceauth.eveonline.autogroups' in settings.INSTALLED_APPS:
|
||||||
_has_auto_groups = True
|
_has_auto_groups = True
|
||||||
from allianceauth.eveonline.autogroups.models import *
|
|
||||||
else:
|
else:
|
||||||
_has_auto_groups = False
|
_has_auto_groups = False
|
||||||
|
|
||||||
@@ -241,6 +241,22 @@ class MainAllianceFilter(admin.SimpleListFilter):
|
|||||||
self.value())
|
self.value())
|
||||||
|
|
||||||
|
|
||||||
|
def update_main_character_model(modeladmin, request, queryset):
|
||||||
|
tasks_count = 0
|
||||||
|
for obj in queryset:
|
||||||
|
if obj.profile.main_character:
|
||||||
|
update_character.delay(obj.profile.main_character.character_id)
|
||||||
|
tasks_count += 1
|
||||||
|
|
||||||
|
modeladmin.message_user(
|
||||||
|
request,
|
||||||
|
'Update from ESI started for {} characters'.format(tasks_count)
|
||||||
|
)
|
||||||
|
|
||||||
|
update_main_character_model.short_description = \
|
||||||
|
'Update main character model from ESI'
|
||||||
|
|
||||||
|
|
||||||
class UserAdmin(BaseUserAdmin):
|
class UserAdmin(BaseUserAdmin):
|
||||||
"""Extending Django's UserAdmin model
|
"""Extending Django's UserAdmin model
|
||||||
|
|
||||||
@@ -272,28 +288,13 @@ class UserAdmin(BaseUserAdmin):
|
|||||||
else:
|
else:
|
||||||
return queryset.filter(groups__pk=self.value())
|
return queryset.filter(groups__pk=self.value())
|
||||||
|
|
||||||
def update_main_character_model(self, request, queryset):
|
|
||||||
tasks_count = 0
|
|
||||||
for obj in queryset:
|
|
||||||
if obj.profile.main_character:
|
|
||||||
update_character.delay(obj.profile.main_character.character_id)
|
|
||||||
tasks_count += 1
|
|
||||||
|
|
||||||
self.message_user(
|
|
||||||
request,
|
|
||||||
'Update from ESI started for {} characters'.format(tasks_count)
|
|
||||||
)
|
|
||||||
|
|
||||||
update_main_character_model.short_description = \
|
|
||||||
'Update main character model from ESI'
|
|
||||||
|
|
||||||
def get_actions(self, request):
|
def get_actions(self, request):
|
||||||
actions = super(BaseUserAdmin, self).get_actions(request)
|
actions = super(BaseUserAdmin, self).get_actions(request)
|
||||||
|
|
||||||
actions[self.update_main_character_model.__name__] = (
|
actions[update_main_character_model.__name__] = (
|
||||||
self.update_main_character_model,
|
update_main_character_model,
|
||||||
self.update_main_character_model.__name__,
|
update_main_character_model.__name__,
|
||||||
self.update_main_character_model.short_description
|
update_main_character_model.short_description
|
||||||
)
|
)
|
||||||
|
|
||||||
for hook in get_hooks('services_hook'):
|
for hook in get_hooks('services_hook'):
|
||||||
@@ -505,7 +506,7 @@ class BaseOwnershipAdmin(admin.ModelAdmin):
|
|||||||
'character',
|
'character',
|
||||||
)
|
)
|
||||||
search_fields = (
|
search_fields = (
|
||||||
'user__user',
|
'user__username',
|
||||||
'character__character_name',
|
'character__character_name',
|
||||||
'character__corporation_name',
|
'character__corporation_name',
|
||||||
'character__alliance_name'
|
'character__alliance_name'
|
||||||
|
|||||||
@@ -94,12 +94,12 @@
|
|||||||
<div class="col-sm-6 text-center">
|
<div class="col-sm-6 text-center">
|
||||||
<div class="panel panel-success" style="height:100%">
|
<div class="panel panel-success" style="height:100%">
|
||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
<h3 class="panel-title">{% trans "Groups" %}</h3>
|
<h3 class="panel-title">{% trans "Group Memberships" %}</h3>
|
||||||
</div>
|
</div>
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
<div style="height: 240px;overflow:-moz-scrollbars-vertical;overflow-y:auto;">
|
<div style="height: 240px;overflow:-moz-scrollbars-vertical;overflow-y:auto;">
|
||||||
<table class="table table-aa">
|
<table class="table table-aa">
|
||||||
{% for group in user.groups.all %}
|
{% for group in groups %}
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{ group.name }}</td>
|
<td>{{ group.name }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
@@ -128,16 +128,14 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{% for ownership in request.user.character_ownerships.all %}
|
{% for char in characters %}
|
||||||
{% with ownership.character as char %}
|
<tr>
|
||||||
<tr>
|
<td class="text-center"><img class="ra-avatar img-circle" src="{{ char.portrait_url_32 }}">
|
||||||
<td class="text-center"><img class="ra-avatar img-circle" src="{{ char.portrait_url_32 }}">
|
</td>
|
||||||
</td>
|
<td class="text-center">{{ char.character_name }}</td>
|
||||||
<td class="text-center">{{ char.character_name }}</td>
|
<td class="text-center">{{ char.corporation_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 }}</td>
|
</tr>
|
||||||
</tr>
|
|
||||||
{% endwith %}
|
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
{% load i18n %}{% autoescape off %}
|
{% load i18n %}{% autoescape off %}
|
||||||
{% blocktrans %}You're receiving this email because you requested a password reset for your
|
{% blocktrans trimmed %}You're receiving this email because you requested a password reset for your
|
||||||
user account.{% endblocktrans %}
|
user account.{% endblocktrans %}
|
||||||
|
|
||||||
{% trans "Please go to the following page and choose a new password:" %}
|
{% trans "Please go to the following page and choose a new password:" %}
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
from django.urls import reverse
|
||||||
|
|
||||||
|
|
||||||
|
def get_admin_change_view_url(obj: object) -> str:
|
||||||
|
"""returns URL to admin change view for given object"""
|
||||||
|
return reverse(
|
||||||
|
'admin:{}_{}_change'.format(
|
||||||
|
obj._meta.app_label, type(obj).__name__.lower()
|
||||||
|
),
|
||||||
|
args=(obj.pk,)
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_admin_search_url(ModelClass: type) -> str:
|
||||||
|
"""returns URL to search URL for model of given object"""
|
||||||
|
return '{}{}/'.format(
|
||||||
|
reverse('admin:app_list', args=(ModelClass._meta.app_label,)),
|
||||||
|
ModelClass.__name__.lower()
|
||||||
|
)
|
||||||
@@ -1,187 +1,314 @@
|
|||||||
|
from urllib.parse import quote
|
||||||
from unittest.mock import patch
|
from unittest.mock import patch
|
||||||
|
|
||||||
from django.test import TestCase, RequestFactory
|
from django.conf import settings
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from django.contrib.admin.sites import AdminSite
|
from django.contrib.admin.sites import AdminSite
|
||||||
from django.contrib.auth.models import User as BaseUser, Group
|
from django.contrib.auth.models import User as BaseUser, Group
|
||||||
|
from django.test import TestCase, RequestFactory, Client
|
||||||
|
|
||||||
from allianceauth.authentication.models import CharacterOwnership, State
|
from allianceauth.authentication.models import (
|
||||||
from allianceauth.eveonline.autogroups.models import AutogroupsConfig
|
CharacterOwnership, State, OwnershipRecord
|
||||||
|
)
|
||||||
from allianceauth.eveonline.models import (
|
from allianceauth.eveonline.models import (
|
||||||
EveCharacter, EveCorporationInfo, EveAllianceInfo
|
EveCharacter, EveCorporationInfo, EveAllianceInfo
|
||||||
)
|
)
|
||||||
|
from allianceauth.tests.auth_utils import AuthUtils
|
||||||
|
|
||||||
from ..admin import (
|
from ..admin import (
|
||||||
BaseUserAdmin,
|
BaseUserAdmin,
|
||||||
|
CharacterOwnershipAdmin,
|
||||||
|
PermissionAdmin,
|
||||||
|
StateAdmin,
|
||||||
MainCorporationsFilter,
|
MainCorporationsFilter,
|
||||||
MainAllianceFilter,
|
MainAllianceFilter,
|
||||||
|
OwnershipRecordAdmin,
|
||||||
User,
|
User,
|
||||||
UserAdmin,
|
UserAdmin,
|
||||||
user_main_organization,
|
user_main_organization,
|
||||||
user_profile_pic,
|
user_profile_pic,
|
||||||
user_username,
|
user_username,
|
||||||
|
update_main_character_model
|
||||||
)
|
)
|
||||||
|
from . import get_admin_change_view_url, get_admin_search_url
|
||||||
|
|
||||||
|
if 'allianceauth.eveonline.autogroups' in settings.INSTALLED_APPS:
|
||||||
|
_has_auto_groups = True
|
||||||
|
from allianceauth.eveonline.autogroups.models import AutogroupsConfig
|
||||||
|
else:
|
||||||
|
_has_auto_groups = False
|
||||||
|
|
||||||
MODULE_PATH = 'allianceauth.authentication.admin'
|
MODULE_PATH = 'allianceauth.authentication.admin'
|
||||||
|
|
||||||
|
|
||||||
class MockRequest(object):
|
class MockRequest(object):
|
||||||
|
|
||||||
def __init__(self, user=None):
|
def __init__(self, user=None):
|
||||||
self.user = user
|
self.user = user
|
||||||
|
|
||||||
|
|
||||||
|
def create_test_data():
|
||||||
|
# groups
|
||||||
|
group_1 = Group.objects.create(
|
||||||
|
name='Group 1'
|
||||||
|
)
|
||||||
|
group_2 = Group.objects.create(
|
||||||
|
name='Group 2'
|
||||||
|
)
|
||||||
|
|
||||||
|
# user 1 - corp and alliance, normal user
|
||||||
|
character_1 = EveCharacter.objects.create(
|
||||||
|
character_id='1001',
|
||||||
|
character_name='Bruce Wayne',
|
||||||
|
corporation_id='2001',
|
||||||
|
corporation_name='Wayne Technologies',
|
||||||
|
corporation_ticker='WT',
|
||||||
|
alliance_id='3001',
|
||||||
|
alliance_name='Wayne Enterprises',
|
||||||
|
alliance_ticker='WE',
|
||||||
|
)
|
||||||
|
character_1a = EveCharacter.objects.create(
|
||||||
|
character_id='1002',
|
||||||
|
character_name='Batman',
|
||||||
|
corporation_id='2001',
|
||||||
|
corporation_name='Wayne Technologies',
|
||||||
|
corporation_ticker='WT',
|
||||||
|
alliance_id='3001',
|
||||||
|
alliance_name='Wayne Enterprises',
|
||||||
|
alliance_ticker='WE',
|
||||||
|
)
|
||||||
|
alliance = EveAllianceInfo.objects.create(
|
||||||
|
alliance_id='3001',
|
||||||
|
alliance_name='Wayne Enterprises',
|
||||||
|
alliance_ticker='WE',
|
||||||
|
executor_corp_id='2001'
|
||||||
|
)
|
||||||
|
EveCorporationInfo.objects.create(
|
||||||
|
corporation_id='2001',
|
||||||
|
corporation_name='Wayne Technologies',
|
||||||
|
corporation_ticker='WT',
|
||||||
|
member_count=42,
|
||||||
|
alliance=alliance
|
||||||
|
)
|
||||||
|
user_1 = User.objects.create_user(
|
||||||
|
character_1.character_name.replace(' ', '_'),
|
||||||
|
'abc@example.com',
|
||||||
|
'password'
|
||||||
|
)
|
||||||
|
CharacterOwnership.objects.create(
|
||||||
|
character=character_1,
|
||||||
|
owner_hash='x1' + character_1.character_name,
|
||||||
|
user=user_1
|
||||||
|
)
|
||||||
|
CharacterOwnership.objects.create(
|
||||||
|
character=character_1a,
|
||||||
|
owner_hash='x1' + character_1a.character_name,
|
||||||
|
user=user_1
|
||||||
|
)
|
||||||
|
user_1.profile.main_character = character_1
|
||||||
|
user_1.profile.save()
|
||||||
|
user_1.groups.add(group_1)
|
||||||
|
|
||||||
|
# user 2 - corp only, staff
|
||||||
|
character_2 = EveCharacter.objects.create(
|
||||||
|
character_id=1003,
|
||||||
|
character_name='Clark Kent',
|
||||||
|
corporation_id=2002,
|
||||||
|
corporation_name='Daily Planet',
|
||||||
|
corporation_ticker='DP',
|
||||||
|
alliance_id=None
|
||||||
|
)
|
||||||
|
EveCorporationInfo.objects.create(
|
||||||
|
corporation_id=2002,
|
||||||
|
corporation_name='Daily Plane',
|
||||||
|
corporation_ticker='DP',
|
||||||
|
member_count=99,
|
||||||
|
alliance=None
|
||||||
|
)
|
||||||
|
user_2 = User.objects.create_user(
|
||||||
|
character_2.character_name.replace(' ', '_'),
|
||||||
|
'abc@example.com',
|
||||||
|
'password'
|
||||||
|
)
|
||||||
|
CharacterOwnership.objects.create(
|
||||||
|
character=character_2,
|
||||||
|
owner_hash='x1' + character_2.character_name,
|
||||||
|
user=user_2
|
||||||
|
)
|
||||||
|
user_2.profile.main_character = character_2
|
||||||
|
user_2.profile.save()
|
||||||
|
user_2.groups.add(group_2)
|
||||||
|
user_2.is_staff = True
|
||||||
|
user_2.save()
|
||||||
|
|
||||||
|
# user 3 - no main, no group, superuser
|
||||||
|
character_3 = EveCharacter.objects.create(
|
||||||
|
character_id=1101,
|
||||||
|
character_name='Lex Luthor',
|
||||||
|
corporation_id=2101,
|
||||||
|
corporation_name='Lex Corp',
|
||||||
|
corporation_ticker='LC',
|
||||||
|
alliance_id=None
|
||||||
|
)
|
||||||
|
EveCorporationInfo.objects.create(
|
||||||
|
corporation_id=2101,
|
||||||
|
corporation_name='Lex Corp',
|
||||||
|
corporation_ticker='LC',
|
||||||
|
member_count=666,
|
||||||
|
alliance=None
|
||||||
|
)
|
||||||
|
EveAllianceInfo.objects.create(
|
||||||
|
alliance_id='3101',
|
||||||
|
alliance_name='Lex World Domination',
|
||||||
|
alliance_ticker='LWD',
|
||||||
|
executor_corp_id=''
|
||||||
|
)
|
||||||
|
user_3 = User.objects.create_user(
|
||||||
|
character_3.character_name.replace(' ', '_'),
|
||||||
|
'abc@example.com',
|
||||||
|
'password'
|
||||||
|
)
|
||||||
|
CharacterOwnership.objects.create(
|
||||||
|
character=character_3,
|
||||||
|
owner_hash='x1' + character_3.character_name,
|
||||||
|
user=user_3
|
||||||
|
)
|
||||||
|
user_3.is_superuser = True
|
||||||
|
user_3.save()
|
||||||
|
return user_1, user_2, user_3, group_1, group_2
|
||||||
|
|
||||||
|
|
||||||
|
def make_generic_search_request(ModelClass: type, search_term: str):
|
||||||
|
User.objects.create_superuser(
|
||||||
|
username='superuser', password='secret', email='admin@example.com'
|
||||||
|
)
|
||||||
|
c = Client()
|
||||||
|
c.login(username='superuser', password='secret')
|
||||||
|
return c.get(
|
||||||
|
'%s?q=%s' % (get_admin_search_url(ModelClass), quote(search_term))
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class TestCharacterOwnershipAdmin(TestCase):
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setUpClass(cls):
|
||||||
|
super().setUpClass()
|
||||||
|
cls.user_1, _, _, _, _ = create_test_data()
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.modeladmin = CharacterOwnershipAdmin(
|
||||||
|
model=User, admin_site=AdminSite()
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_change_view_loads_normally(self):
|
||||||
|
User.objects.create_superuser(
|
||||||
|
username='superuser', password='secret', email='admin@example.com'
|
||||||
|
)
|
||||||
|
c = Client()
|
||||||
|
c.login(username='superuser', password='secret')
|
||||||
|
ownership = self.user_1.character_ownerships.first()
|
||||||
|
response = c.get(get_admin_change_view_url(ownership))
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
|
def test_search_works(self):
|
||||||
|
obj = CharacterOwnership.objects\
|
||||||
|
.filter(user=self.user_1)\
|
||||||
|
.first()
|
||||||
|
response = make_generic_search_request(type(obj), obj.user.username)
|
||||||
|
expected = 200
|
||||||
|
self.assertEqual(response.status_code, expected)
|
||||||
|
|
||||||
|
|
||||||
|
class TestOwnershipRecordAdmin(TestCase):
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setUpClass(cls):
|
||||||
|
super().setUpClass()
|
||||||
|
cls.user_1, _, _, _, _ = create_test_data()
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.modeladmin = OwnershipRecordAdmin(
|
||||||
|
model=User, admin_site=AdminSite()
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_change_view_loads_normally(self):
|
||||||
|
User.objects.create_superuser(
|
||||||
|
username='superuser', password='secret', email='admin@example.com'
|
||||||
|
)
|
||||||
|
c = Client()
|
||||||
|
c.login(username='superuser', password='secret')
|
||||||
|
ownership_record = OwnershipRecord.objects\
|
||||||
|
.filter(user=self.user_1)\
|
||||||
|
.first()
|
||||||
|
response = c.get(get_admin_change_view_url(ownership_record))
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
|
def test_search_works(self):
|
||||||
|
obj = OwnershipRecord.objects.first()
|
||||||
|
response = make_generic_search_request(type(obj), obj.user.username)
|
||||||
|
expected = 200
|
||||||
|
self.assertEqual(response.status_code, expected)
|
||||||
|
|
||||||
|
|
||||||
|
class TestStateAdmin(TestCase):
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setUpClass(cls):
|
||||||
|
super().setUpClass()
|
||||||
|
create_test_data()
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.modeladmin = StateAdmin(
|
||||||
|
model=User, admin_site=AdminSite()
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_change_view_loads_normally(self):
|
||||||
|
User.objects.create_superuser(
|
||||||
|
username='superuser', password='secret', email='admin@example.com'
|
||||||
|
)
|
||||||
|
c = Client()
|
||||||
|
c.login(username='superuser', password='secret')
|
||||||
|
|
||||||
|
guest_state = AuthUtils.get_guest_state()
|
||||||
|
response = c.get(get_admin_change_view_url(guest_state))
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
|
member_state = AuthUtils.get_member_state()
|
||||||
|
response = c.get(get_admin_change_view_url(member_state))
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
|
def test_search_works(self):
|
||||||
|
obj = State.objects.first()
|
||||||
|
response = make_generic_search_request(type(obj), obj.name)
|
||||||
|
expected = 200
|
||||||
|
self.assertEqual(response.status_code, expected)
|
||||||
|
|
||||||
class TestUserAdmin(TestCase):
|
class TestUserAdmin(TestCase):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpClass(cls):
|
def setUpClass(cls):
|
||||||
super().setUpClass()
|
super().setUpClass()
|
||||||
|
cls.user_1, cls.user_2, cls.user_3, cls.group_1, cls.group_2 = \
|
||||||
# groups
|
create_test_data()
|
||||||
cls.group_1 = Group.objects.create(
|
|
||||||
name='Group 1'
|
|
||||||
)
|
|
||||||
cls.group_2 = Group.objects.create(
|
|
||||||
name='Group 2'
|
|
||||||
)
|
|
||||||
|
|
||||||
# user 1 - corp and alliance, normal user
|
|
||||||
cls.character_1 = EveCharacter.objects.create(
|
|
||||||
character_id='1001',
|
|
||||||
character_name='Bruce Wayne',
|
|
||||||
corporation_id='2001',
|
|
||||||
corporation_name='Wayne Technologies',
|
|
||||||
corporation_ticker='WT',
|
|
||||||
alliance_id='3001',
|
|
||||||
alliance_name='Wayne Enterprises',
|
|
||||||
alliance_ticker='WE',
|
|
||||||
)
|
|
||||||
cls.character_1a = EveCharacter.objects.create(
|
|
||||||
character_id='1002',
|
|
||||||
character_name='Batman',
|
|
||||||
corporation_id='2001',
|
|
||||||
corporation_name='Wayne Technologies',
|
|
||||||
corporation_ticker='WT',
|
|
||||||
alliance_id='3001',
|
|
||||||
alliance_name='Wayne Enterprises',
|
|
||||||
alliance_ticker='WE',
|
|
||||||
)
|
|
||||||
alliance = EveAllianceInfo.objects.create(
|
|
||||||
alliance_id='3001',
|
|
||||||
alliance_name='Wayne Enterprises',
|
|
||||||
alliance_ticker='WE',
|
|
||||||
executor_corp_id='2001'
|
|
||||||
)
|
|
||||||
EveCorporationInfo.objects.create(
|
|
||||||
corporation_id='2001',
|
|
||||||
corporation_name='Wayne Technologies',
|
|
||||||
corporation_ticker='WT',
|
|
||||||
member_count=42,
|
|
||||||
alliance=alliance
|
|
||||||
)
|
|
||||||
cls.user_1 = User.objects.create_user(
|
|
||||||
cls.character_1.character_name.replace(' ', '_'),
|
|
||||||
'abc@example.com',
|
|
||||||
'password'
|
|
||||||
)
|
|
||||||
CharacterOwnership.objects.create(
|
|
||||||
character=cls.character_1,
|
|
||||||
owner_hash='x1' + cls.character_1.character_name,
|
|
||||||
user=cls.user_1
|
|
||||||
)
|
|
||||||
CharacterOwnership.objects.create(
|
|
||||||
character=cls.character_1a,
|
|
||||||
owner_hash='x1' + cls.character_1a.character_name,
|
|
||||||
user=cls.user_1
|
|
||||||
)
|
|
||||||
cls.user_1.profile.main_character = cls.character_1
|
|
||||||
cls.user_1.profile.save()
|
|
||||||
cls.user_1.groups.add(cls.group_1)
|
|
||||||
|
|
||||||
# user 2 - corp only, staff
|
|
||||||
cls.character_2 = EveCharacter.objects.create(
|
|
||||||
character_id=1003,
|
|
||||||
character_name='Clark Kent',
|
|
||||||
corporation_id=2002,
|
|
||||||
corporation_name='Daily Planet',
|
|
||||||
corporation_ticker='DP',
|
|
||||||
alliance_id=None
|
|
||||||
)
|
|
||||||
EveCorporationInfo.objects.create(
|
|
||||||
corporation_id=2002,
|
|
||||||
corporation_name='Daily Plane',
|
|
||||||
corporation_ticker='DP',
|
|
||||||
member_count=99,
|
|
||||||
alliance=None
|
|
||||||
)
|
|
||||||
cls.user_2 = User.objects.create_user(
|
|
||||||
cls.character_2.character_name.replace(' ', '_'),
|
|
||||||
'abc@example.com',
|
|
||||||
'password'
|
|
||||||
)
|
|
||||||
CharacterOwnership.objects.create(
|
|
||||||
character=cls.character_2,
|
|
||||||
owner_hash='x1' + cls.character_2.character_name,
|
|
||||||
user=cls.user_2
|
|
||||||
)
|
|
||||||
cls.user_2.profile.main_character = cls.character_2
|
|
||||||
cls.user_2.profile.save()
|
|
||||||
cls.user_2.groups.add(cls.group_2)
|
|
||||||
cls.user_2.is_staff = True
|
|
||||||
cls.user_2.save()
|
|
||||||
|
|
||||||
# user 3 - no main, no group, superuser
|
|
||||||
cls.character_3 = EveCharacter.objects.create(
|
|
||||||
character_id=1101,
|
|
||||||
character_name='Lex Luthor',
|
|
||||||
corporation_id=2101,
|
|
||||||
corporation_name='Lex Corp',
|
|
||||||
corporation_ticker='LC',
|
|
||||||
alliance_id=None
|
|
||||||
)
|
|
||||||
EveCorporationInfo.objects.create(
|
|
||||||
corporation_id=2101,
|
|
||||||
corporation_name='Lex Corp',
|
|
||||||
corporation_ticker='LC',
|
|
||||||
member_count=666,
|
|
||||||
alliance=None
|
|
||||||
)
|
|
||||||
EveAllianceInfo.objects.create(
|
|
||||||
alliance_id='3101',
|
|
||||||
alliance_name='Lex World Domination',
|
|
||||||
alliance_ticker='LWD',
|
|
||||||
executor_corp_id=''
|
|
||||||
)
|
|
||||||
cls.user_3 = User.objects.create_user(
|
|
||||||
cls.character_3.character_name.replace(' ', '_'),
|
|
||||||
'abc@example.com',
|
|
||||||
'password'
|
|
||||||
)
|
|
||||||
CharacterOwnership.objects.create(
|
|
||||||
character=cls.character_3,
|
|
||||||
owner_hash='x1' + cls.character_3.character_name,
|
|
||||||
user=cls.user_3
|
|
||||||
)
|
|
||||||
cls.user_3.is_superuser = True
|
|
||||||
cls.user_3.save()
|
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.factory = RequestFactory()
|
self.factory = RequestFactory()
|
||||||
self.modeladmin = UserAdmin(
|
self.modeladmin = UserAdmin(
|
||||||
model=User, admin_site=AdminSite()
|
model=User, admin_site=AdminSite()
|
||||||
)
|
)
|
||||||
|
self.character_1 = self.user_1.character_ownerships.first().character
|
||||||
|
|
||||||
def _create_autogroups(self):
|
def _create_autogroups(self):
|
||||||
"""create autogroups for corps and alliances"""
|
"""create autogroups for corps and alliances"""
|
||||||
autogroups_config = AutogroupsConfig(
|
if _has_auto_groups:
|
||||||
corp_groups = True,
|
autogroups_config = AutogroupsConfig(
|
||||||
alliance_groups = True
|
corp_groups = True,
|
||||||
)
|
alliance_groups = True
|
||||||
autogroups_config.save()
|
)
|
||||||
for state in State.objects.all():
|
autogroups_config.save()
|
||||||
autogroups_config.states.add(state)
|
for state in State.objects.all():
|
||||||
autogroups_config.update_corp_group_membership(self.user_1)
|
autogroups_config.states.add(state)
|
||||||
|
autogroups_config.update_corp_group_membership(self.user_1)
|
||||||
|
|
||||||
# column rendering
|
# column rendering
|
||||||
|
|
||||||
@@ -315,8 +442,8 @@ class TestUserAdmin(TestCase):
|
|||||||
self, mock_task, mock_message_user
|
self, mock_task, mock_message_user
|
||||||
):
|
):
|
||||||
users_qs = User.objects.filter(pk__in=[self.user_1.pk, self.user_2.pk])
|
users_qs = User.objects.filter(pk__in=[self.user_1.pk, self.user_2.pk])
|
||||||
self.modeladmin.update_main_character_model(
|
update_main_character_model(
|
||||||
MockRequest(self.user_1), users_qs
|
self.modeladmin, MockRequest(self.user_1), users_qs
|
||||||
)
|
)
|
||||||
self.assertEqual(mock_task.delay.call_count, 2)
|
self.assertEqual(mock_task.delay.call_count, 2)
|
||||||
self.assertTrue(mock_message_user.called)
|
self.assertTrue(mock_message_user.called)
|
||||||
@@ -436,4 +563,19 @@ class TestUserAdmin(TestCase):
|
|||||||
changelist = my_modeladmin.get_changelist_instance(request)
|
changelist = my_modeladmin.get_changelist_instance(request)
|
||||||
queryset = changelist.get_queryset(request)
|
queryset = changelist.get_queryset(request)
|
||||||
expected = [self.user_1]
|
expected = [self.user_1]
|
||||||
self.assertSetEqual(set(queryset), set(expected))
|
self.assertSetEqual(set(queryset), set(expected))
|
||||||
|
|
||||||
|
def test_change_view_loads_normally(self):
|
||||||
|
User.objects.create_superuser(
|
||||||
|
username='superuser', password='secret', email='admin@example.com'
|
||||||
|
)
|
||||||
|
c = Client()
|
||||||
|
c.login(username='superuser', password='secret')
|
||||||
|
response = c.get(get_admin_change_view_url(self.user_1))
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
|
def test_search_works(self):
|
||||||
|
obj = User.objects.first()
|
||||||
|
response = make_generic_search_request(type(obj), obj.username)
|
||||||
|
expected = 200
|
||||||
|
self.assertEqual(response.status_code, expected)
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
from unittest.mock import Mock, patch
|
from unittest.mock import Mock, patch
|
||||||
|
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
|
|
||||||
from .. import app_settings
|
from .. import app_settings
|
||||||
|
|
||||||
MODULE_PATH = 'allianceauth.authentication'
|
MODULE_PATH = 'allianceauth.authentication'
|
||||||
|
|
||||||
|
|
||||||
class TestSetAppSetting(TestCase):
|
class TestSetAppSetting(TestCase):
|
||||||
|
|
||||||
@patch(MODULE_PATH + '.app_settings.settings')
|
@patch(MODULE_PATH + '.app_settings.settings')
|
||||||
@@ -17,7 +17,6 @@ class TestSetAppSetting(TestCase):
|
|||||||
)
|
)
|
||||||
self.assertEqual(result, False)
|
self.assertEqual(result, False)
|
||||||
|
|
||||||
|
|
||||||
@patch(MODULE_PATH + '.app_settings.settings')
|
@patch(MODULE_PATH + '.app_settings.settings')
|
||||||
def test_default_if_not_set_for_none(self, mock_settings):
|
def test_default_if_not_set_for_none(self, mock_settings):
|
||||||
mock_settings.TEST_SETTING_DUMMY = Mock(spec=None)
|
mock_settings.TEST_SETTING_DUMMY = Mock(spec=None)
|
||||||
@@ -28,7 +27,6 @@ class TestSetAppSetting(TestCase):
|
|||||||
)
|
)
|
||||||
self.assertEqual(result, None)
|
self.assertEqual(result, None)
|
||||||
|
|
||||||
|
|
||||||
@patch(MODULE_PATH + '.app_settings.settings')
|
@patch(MODULE_PATH + '.app_settings.settings')
|
||||||
def test_true_stays_true(self, mock_settings):
|
def test_true_stays_true(self, mock_settings):
|
||||||
mock_settings.TEST_SETTING_DUMMY = True
|
mock_settings.TEST_SETTING_DUMMY = True
|
||||||
@@ -56,7 +54,6 @@ class TestSetAppSetting(TestCase):
|
|||||||
)
|
)
|
||||||
self.assertEqual(result, False)
|
self.assertEqual(result, False)
|
||||||
|
|
||||||
|
|
||||||
@patch(MODULE_PATH + '.app_settings.settings')
|
@patch(MODULE_PATH + '.app_settings.settings')
|
||||||
def test_default_for_invalid_type_int(self, mock_settings):
|
def test_default_for_invalid_type_int(self, mock_settings):
|
||||||
mock_settings.TEST_SETTING_DUMMY = 'invalid type'
|
mock_settings.TEST_SETTING_DUMMY = 'invalid type'
|
||||||
@@ -95,7 +92,6 @@ class TestSetAppSetting(TestCase):
|
|||||||
)
|
)
|
||||||
self.assertEqual(result, 50)
|
self.assertEqual(result, 50)
|
||||||
|
|
||||||
|
|
||||||
@patch(MODULE_PATH + '.app_settings.settings')
|
@patch(MODULE_PATH + '.app_settings.settings')
|
||||||
def test_default_is_none_needs_required_type(self, mock_settings):
|
def test_default_is_none_needs_required_type(self, mock_settings):
|
||||||
mock_settings.TEST_SETTING_DUMMY = 'invalid type'
|
mock_settings.TEST_SETTING_DUMMY = 'invalid type'
|
||||||
@@ -104,5 +100,3 @@ class TestSetAppSetting(TestCase):
|
|||||||
'TEST_SETTING_DUMMY',
|
'TEST_SETTING_DUMMY',
|
||||||
default_value=None
|
default_value=None
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -7,11 +7,28 @@ from . import views
|
|||||||
app_name = 'authentication'
|
app_name = 'authentication'
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
url(r'^$', login_required(TemplateView.as_view(template_name='authentication/dashboard.html')),),
|
url(r'^$', views.index, name='index'),
|
||||||
url(r'^account/login/$', TemplateView.as_view(template_name='public/login.html'), name='login'),
|
url(
|
||||||
url(r'^account/characters/main/$', views.main_character_change, name='change_main_character'),
|
r'^account/login/$',
|
||||||
url(r'^account/characters/add/$', views.add_character, name='add_character'),
|
TemplateView.as_view(template_name='public/login.html'),
|
||||||
url(r'^help/$', login_required(TemplateView.as_view(template_name='allianceauth/help.html')), name='help'),
|
name='login'
|
||||||
url(r'^dashboard/$',
|
),
|
||||||
login_required(TemplateView.as_view(template_name='authentication/dashboard.html')), name='dashboard'),
|
url(
|
||||||
|
r'^account/characters/main/$',
|
||||||
|
views.main_character_change,
|
||||||
|
name='change_main_character'
|
||||||
|
),
|
||||||
|
url(
|
||||||
|
r'^account/characters/add/$',
|
||||||
|
views.add_character,
|
||||||
|
name='add_character'
|
||||||
|
),
|
||||||
|
url(
|
||||||
|
r'^help/$',
|
||||||
|
login_required(
|
||||||
|
TemplateView.as_view(template_name='allianceauth/help.html')
|
||||||
|
),
|
||||||
|
name='help'
|
||||||
|
),
|
||||||
|
url(r'^dashboard/$', views.dashboard, name='dashboard'),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -7,20 +7,58 @@ from django.contrib.auth.decorators import login_required
|
|||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.core import signing
|
from django.core import signing
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.shortcuts import redirect
|
from django.shortcuts import redirect, render
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
from allianceauth.eveonline.models import EveCharacter
|
||||||
from esi.decorators import token_required
|
from esi.decorators import token_required
|
||||||
from esi.models import Token
|
from esi.models import Token
|
||||||
from registration.backends.hmac.views import RegistrationView as BaseRegistrationView, \
|
|
||||||
ActivationView as BaseActivationView, REGISTRATION_SALT
|
from registration.backends.hmac.views import (
|
||||||
|
RegistrationView as BaseRegistrationView,
|
||||||
|
ActivationView as BaseActivationView,
|
||||||
|
REGISTRATION_SALT
|
||||||
|
)
|
||||||
from registration.signals import user_registered
|
from registration.signals import user_registered
|
||||||
|
|
||||||
from .models import CharacterOwnership
|
from .models import CharacterOwnership
|
||||||
from .forms import RegistrationForm
|
from .forms import RegistrationForm
|
||||||
|
|
||||||
|
if 'allianceauth.eveonline.autogroups' in settings.INSTALLED_APPS:
|
||||||
|
_has_auto_groups = True
|
||||||
|
from allianceauth.eveonline.autogroups.models import *
|
||||||
|
else:
|
||||||
|
_has_auto_groups = False
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
def index(request):
|
||||||
|
return redirect('authentication:dashboard')
|
||||||
|
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
def dashboard(request):
|
||||||
|
groups = request.user.groups.all()
|
||||||
|
if _has_auto_groups:
|
||||||
|
groups = groups\
|
||||||
|
.filter(managedalliancegroup__isnull=True)\
|
||||||
|
.filter(managedcorpgroup__isnull=True)
|
||||||
|
groups = groups.order_by('name')
|
||||||
|
characters = EveCharacter.objects\
|
||||||
|
.filter(character_ownership__user=request.user)\
|
||||||
|
.select_related()\
|
||||||
|
.order_by('character_name')
|
||||||
|
|
||||||
|
context = {
|
||||||
|
'groups': groups,
|
||||||
|
'characters': characters
|
||||||
|
}
|
||||||
|
return render(request, 'authentication/dashboard.html', context)
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@token_required(scopes=settings.LOGIN_TOKEN_SCOPES)
|
@token_required(scopes=settings.LOGIN_TOKEN_SCOPES)
|
||||||
def main_character_change(request, token):
|
def main_character_change(request, token):
|
||||||
@@ -31,7 +69,10 @@ def main_character_change(request, token):
|
|||||||
if not CharacterOwnership.objects.filter(character__character_id=token.character_id).exists():
|
if not CharacterOwnership.objects.filter(character__character_id=token.character_id).exists():
|
||||||
co = CharacterOwnership.objects.create_by_token(token)
|
co = CharacterOwnership.objects.create_by_token(token)
|
||||||
else:
|
else:
|
||||||
messages.error(request, 'Cannot change main character to %(char)s: character owned by a different account.' % ({'char': token.character_name}))
|
messages.error(
|
||||||
|
request,
|
||||||
|
_('Cannot change main character to %(char)s: character owned by a different account.') % ({'char': token.character_name})
|
||||||
|
)
|
||||||
co = None
|
co = None
|
||||||
if co:
|
if co:
|
||||||
request.user.profile.main_character = co.character
|
request.user.profile.main_character = co.character
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ from .models import EveCorporationInfo
|
|||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
TASK_PRIORITY = 7
|
||||||
|
|
||||||
@shared_task
|
@shared_task
|
||||||
def update_corp(corp_id):
|
def update_corp(corp_id):
|
||||||
@@ -27,11 +28,12 @@ def update_character(character_id):
|
|||||||
def run_model_update():
|
def run_model_update():
|
||||||
# update existing corp models
|
# update existing corp models
|
||||||
for corp in EveCorporationInfo.objects.all().values('corporation_id'):
|
for corp in EveCorporationInfo.objects.all().values('corporation_id'):
|
||||||
update_corp.delay(corp['corporation_id'])
|
update_corp.apply_async(args=[corp['corporation_id']], priority=TASK_PRIORITY)
|
||||||
|
|
||||||
# update existing alliance models
|
# update existing alliance models
|
||||||
for alliance in EveAllianceInfo.objects.all().values('alliance_id'):
|
for alliance in EveAllianceInfo.objects.all().values('alliance_id'):
|
||||||
update_alliance.delay(alliance['alliance_id'])
|
update_alliance.apply_async(args=[alliance['alliance_id']], priority=TASK_PRIORITY)
|
||||||
|
|
||||||
|
#update existing character models
|
||||||
for character in EveCharacter.objects.all().values('character_id'):
|
for character in EveCharacter.objects.all().values('character_id'):
|
||||||
update_character.delay(character['character_id'])
|
update_character.apply_async(args=[character['character_id']], priority=TASK_PRIORITY)
|
||||||
|
|||||||
@@ -80,28 +80,28 @@ class TestTasks(TestCase):
|
|||||||
character_name='character.name',
|
character_name='character.name',
|
||||||
corporation_id='character.corp.id',
|
corporation_id='character.corp.id',
|
||||||
corporation_name='character.corp.name',
|
corporation_name='character.corp.name',
|
||||||
corporation_ticker='character.corp.ticker',
|
corporation_ticker='c.c.t', # max 5 chars
|
||||||
alliance_id='character.alliance.id',
|
alliance_id='character.alliance.id',
|
||||||
alliance_name='character.alliance.name',
|
alliance_name='character.alliance.name',
|
||||||
)
|
)
|
||||||
|
|
||||||
run_model_update()
|
run_model_update()
|
||||||
|
|
||||||
self.assertEqual(mock_update_corp.delay.call_count, 1)
|
self.assertEqual(mock_update_corp.apply_async.call_count, 1)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
int(mock_update_corp.delay.call_args[0][0]),
|
int(mock_update_corp.apply_async.call_args[1]['args'][0]),
|
||||||
2345
|
2345
|
||||||
)
|
)
|
||||||
|
|
||||||
self.assertEqual(mock_update_alliance.delay.call_count, 1)
|
self.assertEqual(mock_update_alliance.apply_async.call_count, 1)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
int(mock_update_alliance.delay.call_args[0][0]),
|
int(mock_update_alliance.apply_async.call_args[1]['args'][0]),
|
||||||
3456
|
3456
|
||||||
)
|
)
|
||||||
|
|
||||||
self.assertEqual(mock_update_character.delay.call_count, 1)
|
self.assertEqual(mock_update_character.apply_async.call_count, 1)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
int(mock_update_character.delay.call_args[0][0]),
|
int(mock_update_character.apply_async.call_args[1]['args'][0]),
|
||||||
1234
|
1234
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,13 @@
|
|||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</h1>
|
</h1>
|
||||||
<h2>{% blocktrans %}{{ user }} has collected {{ n_fats }} link{{ n_fats|pluralize }} this month.{% endblocktrans %}</h2>
|
<h2>
|
||||||
|
{% blocktrans count links=n_fats trimmed %}
|
||||||
|
{{ user }} has collected one link this month.
|
||||||
|
{% plural %}
|
||||||
|
{{ user }} has collected {{ links }} links this month.
|
||||||
|
{% endblocktrans %}
|
||||||
|
</h2>
|
||||||
<table class="table table-responsive">
|
<table class="table table-responsive">
|
||||||
<tr>
|
<tr>
|
||||||
<th class="col-md-2 text-center">{% trans "Ship" %}</th>
|
<th class="col-md-2 text-center">{% trans "Ship" %}</th>
|
||||||
@@ -29,7 +35,13 @@
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
</table>
|
</table>
|
||||||
{% if created_fats %}
|
{% if created_fats %}
|
||||||
<h2>{% blocktrans %}{{ user }} has created {{ n_created_fats }} link{{ n_created_fats|pluralize }} this month.{% endblocktrans %}</h2>
|
<h2>
|
||||||
|
{% blocktrans count links=n_created_fats trimmed %}
|
||||||
|
{{ user }} has created one link this month.
|
||||||
|
{% plural %}
|
||||||
|
{{ user }} has created {{ links }} links this month.
|
||||||
|
{% endblocktrans %}
|
||||||
|
</h2>
|
||||||
{% if created_fats %}
|
{% if created_fats %}
|
||||||
<table class="table">
|
<table class="table">
|
||||||
<tr>
|
<tr>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from django.contrib.auth.models import Group as BaseGroup
|
from django.contrib.auth.models import Group as BaseGroup, User
|
||||||
from django.db.models import Count
|
from django.db.models import Count
|
||||||
from django.db.models.functions import Lower
|
from django.db.models.functions import Lower
|
||||||
from django.db.models.signals import pre_save, post_save, pre_delete, \
|
from django.db.models.signals import pre_save, post_save, pre_delete, \
|
||||||
@@ -13,8 +13,7 @@ from .models import GroupRequest
|
|||||||
from . import signals
|
from . import signals
|
||||||
|
|
||||||
if 'allianceauth.eveonline.autogroups' in settings.INSTALLED_APPS:
|
if 'allianceauth.eveonline.autogroups' in settings.INSTALLED_APPS:
|
||||||
_has_auto_groups = True
|
_has_auto_groups = True
|
||||||
from allianceauth.eveonline.autogroups.models import *
|
|
||||||
else:
|
else:
|
||||||
_has_auto_groups = False
|
_has_auto_groups = False
|
||||||
|
|
||||||
@@ -22,19 +21,24 @@ else:
|
|||||||
class AuthGroupInlineAdmin(admin.StackedInline):
|
class AuthGroupInlineAdmin(admin.StackedInline):
|
||||||
model = AuthGroup
|
model = AuthGroup
|
||||||
filter_horizontal = ('group_leaders', 'group_leader_groups', 'states',)
|
filter_horizontal = ('group_leaders', 'group_leader_groups', 'states',)
|
||||||
fields = ('description', 'group_leaders', 'group_leader_groups', 'states', 'internal', 'hidden', 'open', 'public')
|
fields = (
|
||||||
|
'description',
|
||||||
|
'group_leaders',
|
||||||
|
'group_leader_groups',
|
||||||
|
'states', 'internal',
|
||||||
|
'hidden',
|
||||||
|
'open',
|
||||||
|
'public'
|
||||||
|
)
|
||||||
verbose_name_plural = 'Auth Settings'
|
verbose_name_plural = 'Auth Settings'
|
||||||
verbose_name = ''
|
verbose_name = ''
|
||||||
|
|
||||||
def formfield_for_manytomany(self, db_field, request, **kwargs):
|
def formfield_for_manytomany(self, db_field, request, **kwargs):
|
||||||
"""overriding this formfield to have sorted lists in the form"""
|
"""overriding this formfield to have sorted lists in the form"""
|
||||||
if db_field.name == "group_leaders":
|
if db_field.name == "group_leaders":
|
||||||
kwargs["queryset"] = User.objects\
|
kwargs["queryset"] = User.objects.order_by(Lower('username'))
|
||||||
.filter(profile__state__name='Member')\
|
|
||||||
.order_by(Lower('username'))
|
|
||||||
elif db_field.name == "group_leader_groups":
|
elif db_field.name == "group_leader_groups":
|
||||||
kwargs["queryset"] = Group.objects\
|
kwargs["queryset"] = Group.objects.order_by(Lower('name'))
|
||||||
.order_by(Lower('name'))
|
|
||||||
return super().formfield_for_manytomany(db_field, request, **kwargs)
|
return super().formfield_for_manytomany(db_field, request, **kwargs)
|
||||||
|
|
||||||
def has_add_permission(self, request):
|
def has_add_permission(self, request):
|
||||||
@@ -103,14 +107,16 @@ class GroupAdmin(admin.ModelAdmin):
|
|||||||
'_member_count',
|
'_member_count',
|
||||||
'has_leader'
|
'has_leader'
|
||||||
)
|
)
|
||||||
list_filter = (
|
list_filter = [
|
||||||
'authgroup__internal',
|
'authgroup__internal',
|
||||||
'authgroup__hidden',
|
'authgroup__hidden',
|
||||||
'authgroup__open',
|
'authgroup__open',
|
||||||
'authgroup__public',
|
'authgroup__public',
|
||||||
IsAutoGroupFilter,
|
]
|
||||||
HasLeaderFilter
|
if _has_auto_groups:
|
||||||
)
|
list_filter.append(IsAutoGroupFilter)
|
||||||
|
list_filter.append(HasLeaderFilter)
|
||||||
|
|
||||||
search_fields = ('name', 'authgroup__description')
|
search_fields = ('name', 'authgroup__description')
|
||||||
|
|
||||||
def get_queryset(self, request):
|
def get_queryset(self, request):
|
||||||
|
|||||||
@@ -1,27 +1,53 @@
|
|||||||
from django.contrib.auth.models import Group
|
import logging
|
||||||
from django.db.models import Q
|
|
||||||
|
from django.contrib.auth.models import Group, User
|
||||||
|
from django.db.models import Q, QuerySet
|
||||||
|
|
||||||
|
from allianceauth.authentication.models import State
|
||||||
|
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class GroupManager:
|
class GroupManager:
|
||||||
def __init__(self):
|
|
||||||
pass
|
@classmethod
|
||||||
|
def get_joinable_groups_for_user(
|
||||||
|
cls, user: User, include_hidden = True
|
||||||
|
) -> QuerySet:
|
||||||
|
"""get groups a user could join incl. groups already joined"""
|
||||||
|
groups_qs = cls.get_joinable_groups(user.profile.state)
|
||||||
|
|
||||||
|
if not user.has_perm('groupmanagement.request_groups'):
|
||||||
|
groups_qs = groups_qs.filter(authgroup__public=True)
|
||||||
|
|
||||||
|
if not include_hidden:
|
||||||
|
groups_qs = groups_qs.filter(authgroup__hidden=False)
|
||||||
|
|
||||||
|
return groups_qs
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_joinable_groups(state):
|
def get_joinable_groups(state: State) -> QuerySet:
|
||||||
return Group.objects.select_related('authgroup').exclude(authgroup__internal=True)\
|
"""get groups that can be joined by user with given state"""
|
||||||
|
return Group.objects\
|
||||||
|
.select_related('authgroup')\
|
||||||
|
.exclude(authgroup__internal=True)\
|
||||||
.filter(Q(authgroup__states=state) | Q(authgroup__states=None))
|
.filter(Q(authgroup__states=state) | Q(authgroup__states=None))
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_all_non_internal_groups():
|
def get_all_non_internal_groups() -> QuerySet:
|
||||||
return Group.objects.select_related('authgroup').exclude(authgroup__internal=True)
|
"""get groups that are not internal"""
|
||||||
|
return Group.objects\
|
||||||
|
.select_related('authgroup')\
|
||||||
|
.exclude(authgroup__internal=True)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_group_leaders_groups(user):
|
def get_group_leaders_groups(user: User):
|
||||||
return Group.objects.select_related('authgroup').filter(authgroup__group_leaders__in=[user]) | \
|
return Group.objects.select_related('authgroup').filter(authgroup__group_leaders__in=[user]) | \
|
||||||
Group.objects.select_related('authgroup').filter(authgroup__group_leader_groups__in=user.groups.all())
|
Group.objects.select_related('authgroup').filter(authgroup__group_leader_groups__in=user.groups.all())
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def joinable_group(group, state):
|
def joinable_group(group: Group, state: State) -> bool:
|
||||||
"""
|
"""
|
||||||
Check if a group is a user/state joinable group, i.e.
|
Check if a group is a user/state joinable group, i.e.
|
||||||
not an internal group for Corp, Alliance, Members etc,
|
not an internal group for Corp, Alliance, Members etc,
|
||||||
@@ -30,12 +56,15 @@ class GroupManager:
|
|||||||
:param state: allianceauth.authentication.State object
|
:param state: allianceauth.authentication.State object
|
||||||
:return: bool True if its joinable, False otherwise
|
:return: bool True if its joinable, False otherwise
|
||||||
"""
|
"""
|
||||||
if len(group.authgroup.states.all()) != 0 and state not in group.authgroup.states.all():
|
if (len(group.authgroup.states.all()) != 0
|
||||||
|
and state not in group.authgroup.states.all()
|
||||||
|
):
|
||||||
return False
|
return False
|
||||||
return not group.authgroup.internal
|
else:
|
||||||
|
return not group.authgroup.internal
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def check_internal_group(group):
|
def check_internal_group(group: Group) -> bool:
|
||||||
"""
|
"""
|
||||||
Check if a group is auditable, i.e not an internal group
|
Check if a group is auditable, i.e not an internal group
|
||||||
:param group: django.contrib.auth.models.Group object
|
:param group: django.contrib.auth.models.Group object
|
||||||
@@ -44,20 +73,11 @@ class GroupManager:
|
|||||||
return not group.authgroup.internal
|
return not group.authgroup.internal
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def check_internal_group(group):
|
def has_management_permission(user: User) -> bool:
|
||||||
"""
|
|
||||||
Check if a group is auditable, i.e not an internal group
|
|
||||||
:param group: django.contrib.auth.models.Group object
|
|
||||||
:return: bool True if it is auditable, false otherwise
|
|
||||||
"""
|
|
||||||
return not group.authgroup.internal
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def has_management_permission(user):
|
|
||||||
return user.has_perm('auth.group_management')
|
return user.has_perm('auth.group_management')
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def can_manage_groups(cls, user):
|
def can_manage_groups(cls, user:User ) -> bool:
|
||||||
"""
|
"""
|
||||||
For use with user_passes_test decorator.
|
For use with user_passes_test decorator.
|
||||||
Check if the user can manage groups. Either has the
|
Check if the user can manage groups. Either has the
|
||||||
@@ -71,7 +91,7 @@ class GroupManager:
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def can_manage_group(cls, user, group):
|
def can_manage_group(cls, user: User, group: Group) -> bool:
|
||||||
"""
|
"""
|
||||||
Check user has permission to manage the given group
|
Check user has permission to manage the given group
|
||||||
:param user: User object to test permission of
|
:param user: User object to test permission of
|
||||||
@@ -79,5 +99,5 @@ class GroupManager:
|
|||||||
:return: True if the user can manage the group
|
:return: True if the user can manage the group
|
||||||
"""
|
"""
|
||||||
if user.is_authenticated:
|
if user.is_authenticated:
|
||||||
return cls.has_management_permission(user) or user.leads_groups.filter(group=group).exists()
|
return cls.has_management_permission(user) or cls.get_group_leaders_groups(user).filter(pk=group.pk).exists()
|
||||||
return False
|
return False
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
<p>
|
<p>
|
||||||
<a class="btn btn-default" href="{% url 'groupmanagement:membership' %}" role="button">
|
<a class="btn btn-default" href="{% url 'groupmanagement:membership' %}" role="button">
|
||||||
Back
|
{% trans "Back" %}
|
||||||
</a>
|
</a>
|
||||||
</p>
|
</p>
|
||||||
{% if entries %}
|
{% if entries %}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
<p>
|
<p>
|
||||||
<a class="btn btn-default" href="{% url 'groupmanagement:membership' %}" role="button">
|
<a class="btn btn-default" href="{% url 'groupmanagement:membership' %}" role="button">
|
||||||
Back
|
{% trans "Back" %}
|
||||||
</a>
|
</a>
|
||||||
</p>
|
</p>
|
||||||
{% if group.user_set %}
|
{% if group.user_set %}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
{% include 'groupmanagement/menu.html' %}
|
{% include 'groupmanagement/menu.html' %}
|
||||||
<div class="panel panel-default">
|
<div class="panel panel-default">
|
||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
Groups
|
{% trans "Groups" %}
|
||||||
</div>
|
</div>
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
{% if groups %}
|
{% if groups %}
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
from django.urls import reverse
|
||||||
|
|
||||||
|
|
||||||
|
def get_admin_change_view_url(obj: object) -> str:
|
||||||
|
return reverse(
|
||||||
|
'admin:{}_{}_change'.format(
|
||||||
|
obj._meta.app_label,
|
||||||
|
type(obj).__name__.lower()
|
||||||
|
),
|
||||||
|
args=(obj.pk,)
|
||||||
|
)
|
||||||
@@ -1,22 +1,29 @@
|
|||||||
from unittest.mock import patch
|
from unittest.mock import patch
|
||||||
|
|
||||||
from django.test import TestCase, RequestFactory
|
from django.conf import settings
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from django.contrib.admin.sites import AdminSite
|
from django.contrib.admin.sites import AdminSite
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
|
from django.test import TestCase, RequestFactory, Client
|
||||||
|
|
||||||
from allianceauth.authentication.models import CharacterOwnership, State
|
from allianceauth.authentication.models import CharacterOwnership, State
|
||||||
from allianceauth.eveonline.autogroups.models import AutogroupsConfig
|
|
||||||
from allianceauth.eveonline.models import (
|
from allianceauth.eveonline.models import (
|
||||||
EveCharacter, EveCorporationInfo, EveAllianceInfo
|
EveCharacter, EveCorporationInfo, EveAllianceInfo
|
||||||
)
|
)
|
||||||
|
|
||||||
from ..admin import (
|
from ..admin import (
|
||||||
IsAutoGroupFilter,
|
|
||||||
HasLeaderFilter,
|
HasLeaderFilter,
|
||||||
GroupAdmin,
|
GroupAdmin,
|
||||||
Group
|
Group
|
||||||
)
|
)
|
||||||
|
from . import get_admin_change_view_url
|
||||||
|
|
||||||
|
if 'allianceauth.eveonline.autogroups' in settings.INSTALLED_APPS:
|
||||||
|
_has_auto_groups = True
|
||||||
|
from allianceauth.eveonline.autogroups.models import AutogroupsConfig
|
||||||
|
from ..admin import IsAutoGroupFilter
|
||||||
|
else:
|
||||||
|
_has_auto_groups = False
|
||||||
|
|
||||||
|
|
||||||
MODULE_PATH = 'allianceauth.groupmanagement.admin'
|
MODULE_PATH = 'allianceauth.groupmanagement.admin'
|
||||||
@@ -210,14 +217,15 @@ class TestGroupAdmin(TestCase):
|
|||||||
|
|
||||||
def _create_autogroups(self):
|
def _create_autogroups(self):
|
||||||
"""create autogroups for corps and alliances"""
|
"""create autogroups for corps and alliances"""
|
||||||
autogroups_config = AutogroupsConfig(
|
if _has_auto_groups:
|
||||||
corp_groups = True,
|
autogroups_config = AutogroupsConfig(
|
||||||
alliance_groups = True
|
corp_groups = True,
|
||||||
)
|
alliance_groups = True
|
||||||
autogroups_config.save()
|
)
|
||||||
for state in State.objects.all():
|
autogroups_config.save()
|
||||||
autogroups_config.states.add(state)
|
for state in State.objects.all():
|
||||||
autogroups_config.update_corp_group_membership(self.user_1)
|
autogroups_config.states.add(state)
|
||||||
|
autogroups_config.update_corp_group_membership(self.user_1)
|
||||||
|
|
||||||
# column rendering
|
# column rendering
|
||||||
|
|
||||||
@@ -267,70 +275,72 @@ class TestGroupAdmin(TestCase):
|
|||||||
result = self.modeladmin._properties(self.group_6)
|
result = self.modeladmin._properties(self.group_6)
|
||||||
self.assertListEqual(result, expected)
|
self.assertListEqual(result, expected)
|
||||||
|
|
||||||
@patch(MODULE_PATH + '._has_auto_groups', True)
|
if _has_auto_groups:
|
||||||
def test_properties_6(self):
|
@patch(MODULE_PATH + '._has_auto_groups', True)
|
||||||
self._create_autogroups()
|
def test_properties_6(self):
|
||||||
expected = ['Auto Group']
|
self._create_autogroups()
|
||||||
my_group = Group.objects\
|
expected = ['Auto Group']
|
||||||
.filter(managedcorpgroup__isnull=False)\
|
my_group = Group.objects\
|
||||||
.first()
|
.filter(managedcorpgroup__isnull=False)\
|
||||||
result = self.modeladmin._properties(my_group)
|
.first()
|
||||||
self.assertListEqual(result, expected)
|
result = self.modeladmin._properties(my_group)
|
||||||
|
self.assertListEqual(result, expected)
|
||||||
|
|
||||||
# actions
|
# actions
|
||||||
|
|
||||||
# filters
|
# filters
|
||||||
|
|
||||||
@patch(MODULE_PATH + '._has_auto_groups', True)
|
if _has_auto_groups:
|
||||||
def test_filter_is_auto_group(self):
|
@patch(MODULE_PATH + '._has_auto_groups', True)
|
||||||
|
def test_filter_is_auto_group(self):
|
||||||
class GroupAdminTest(admin.ModelAdmin):
|
|
||||||
list_filter = (IsAutoGroupFilter,)
|
class GroupAdminTest(admin.ModelAdmin):
|
||||||
|
list_filter = (IsAutoGroupFilter,)
|
||||||
self._create_autogroups()
|
|
||||||
my_modeladmin = GroupAdminTest(Group, AdminSite())
|
self._create_autogroups()
|
||||||
|
my_modeladmin = GroupAdminTest(Group, AdminSite())
|
||||||
|
|
||||||
# Make sure the lookups are correct
|
# Make sure the lookups are correct
|
||||||
request = self.factory.get('/')
|
request = self.factory.get('/')
|
||||||
request.user = self.user_1
|
request.user = self.user_1
|
||||||
changelist = my_modeladmin.get_changelist_instance(request)
|
changelist = my_modeladmin.get_changelist_instance(request)
|
||||||
filters = changelist.get_filters(request)
|
filters = changelist.get_filters(request)
|
||||||
filterspec = filters[0][0]
|
filterspec = filters[0][0]
|
||||||
expected = [
|
expected = [
|
||||||
('yes', 'Yes'),
|
('yes', 'Yes'),
|
||||||
('no', 'No'),
|
('no', 'No'),
|
||||||
]
|
]
|
||||||
self.assertEqual(filterspec.lookup_choices, expected)
|
self.assertEqual(filterspec.lookup_choices, expected)
|
||||||
|
|
||||||
# Make sure the correct queryset is returned - no
|
# Make sure the correct queryset is returned - no
|
||||||
request = self.factory.get(
|
request = self.factory.get(
|
||||||
'/', {'is_auto_group__exact': 'no'}
|
'/', {'is_auto_group__exact': 'no'}
|
||||||
)
|
)
|
||||||
request.user = self.user_1
|
request.user = self.user_1
|
||||||
changelist = my_modeladmin.get_changelist_instance(request)
|
changelist = my_modeladmin.get_changelist_instance(request)
|
||||||
queryset = changelist.get_queryset(request)
|
queryset = changelist.get_queryset(request)
|
||||||
expected = [
|
expected = [
|
||||||
self.group_1,
|
self.group_1,
|
||||||
self.group_2,
|
self.group_2,
|
||||||
self.group_3,
|
self.group_3,
|
||||||
self.group_4,
|
self.group_4,
|
||||||
self.group_5,
|
self.group_5,
|
||||||
self.group_6
|
self.group_6
|
||||||
]
|
]
|
||||||
self.assertSetEqual(set(queryset), set(expected))
|
self.assertSetEqual(set(queryset), set(expected))
|
||||||
|
|
||||||
# Make sure the correct queryset is returned - yes
|
# Make sure the correct queryset is returned - yes
|
||||||
request = self.factory.get(
|
request = self.factory.get(
|
||||||
'/', {'is_auto_group__exact': 'yes'}
|
'/', {'is_auto_group__exact': 'yes'}
|
||||||
)
|
)
|
||||||
request.user = self.user_1
|
request.user = self.user_1
|
||||||
changelist = my_modeladmin.get_changelist_instance(request)
|
changelist = my_modeladmin.get_changelist_instance(request)
|
||||||
queryset = changelist.get_queryset(request)
|
queryset = changelist.get_queryset(request)
|
||||||
expected = Group.objects.exclude(
|
expected = Group.objects.exclude(
|
||||||
managedalliancegroup__isnull=True,
|
managedalliancegroup__isnull=True,
|
||||||
managedcorpgroup__isnull=True
|
managedcorpgroup__isnull=True
|
||||||
)
|
)
|
||||||
self.assertSetEqual(set(queryset), set(expected))
|
self.assertSetEqual(set(queryset), set(expected))
|
||||||
|
|
||||||
def test_filter_has_leader(self):
|
def test_filter_has_leader(self):
|
||||||
|
|
||||||
@@ -376,4 +386,12 @@ class TestGroupAdmin(TestCase):
|
|||||||
self.group_3
|
self.group_3
|
||||||
]
|
]
|
||||||
self.assertSetEqual(set(queryset), set(expected))
|
self.assertSetEqual(set(queryset), set(expected))
|
||||||
|
|
||||||
|
def test_change_view_loads_normally(self):
|
||||||
|
User.objects.create_superuser(
|
||||||
|
username='superuser', password='secret', email='admin@example.com'
|
||||||
|
)
|
||||||
|
c = Client()
|
||||||
|
c.login(username='superuser', password='secret')
|
||||||
|
response = c.get(get_admin_change_view_url(self.group_1))
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
@@ -1,92 +0,0 @@
|
|||||||
from unittest import mock
|
|
||||||
|
|
||||||
from django.test import TestCase
|
|
||||||
from allianceauth.tests.auth_utils import AuthUtils
|
|
||||||
from allianceauth.eveonline.models import EveCorporationInfo, EveAllianceInfo, EveCharacter
|
|
||||||
from django.contrib.auth.models import User, Group
|
|
||||||
from allianceauth.groupmanagement.managers import GroupManager
|
|
||||||
from allianceauth.groupmanagement.signals import check_groups_on_state_change
|
|
||||||
|
|
||||||
class GroupManagementVisibilityTestCase(TestCase):
|
|
||||||
@classmethod
|
|
||||||
def setUpTestData(cls):
|
|
||||||
cls.user = AuthUtils.create_user('test')
|
|
||||||
AuthUtils.add_main_character(cls.user, 'test character', '1', corp_id='2', corp_name='test_corp', corp_ticker='TEST', alliance_id='3', alliance_name='TEST')
|
|
||||||
cls.user.profile.refresh_from_db()
|
|
||||||
cls.alliance = EveAllianceInfo.objects.create(alliance_id='3', alliance_name='test alliance', alliance_ticker='TEST', executor_corp_id='2')
|
|
||||||
cls.corp = EveCorporationInfo.objects.create(corporation_id='2', corporation_name='test corp', corporation_ticker='TEST', alliance=cls.alliance, member_count=1)
|
|
||||||
cls.group1 = Group.objects.create(name='group1')
|
|
||||||
cls.group2 = Group.objects.create(name='group2')
|
|
||||||
cls.group3 = Group.objects.create(name='group3')
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
self.user.refresh_from_db()
|
|
||||||
|
|
||||||
def _refresh_user(self):
|
|
||||||
self.user = User.objects.get(pk=self.user.pk)
|
|
||||||
|
|
||||||
|
|
||||||
def test_can_manage_group(self):
|
|
||||||
|
|
||||||
|
|
||||||
self.group1.authgroup.group_leaders.add(self.user)
|
|
||||||
self.group2.authgroup.group_leader_groups.add(self.group1)
|
|
||||||
self._refresh_user()
|
|
||||||
groups = GroupManager.get_group_leaders_groups(self.user)
|
|
||||||
|
|
||||||
self.assertIn(self.group1, groups) #avail due to user
|
|
||||||
self.assertNotIn(self.group2, groups) #not avail due to group
|
|
||||||
self.assertNotIn(self.group3, groups) #not avail at all
|
|
||||||
|
|
||||||
self.user.groups.add(self.group1)
|
|
||||||
self._refresh_user()
|
|
||||||
groups = GroupManager.get_group_leaders_groups(self.user)
|
|
||||||
|
|
||||||
self.assertIn(self.group1, groups) #avail due to user
|
|
||||||
self.assertIn(self.group2, groups) #avail due to group1
|
|
||||||
self.assertNotIn(self.group3, groups) #not avail at all
|
|
||||||
|
|
||||||
class GroupManagementStateTestCase(TestCase):
|
|
||||||
@classmethod
|
|
||||||
def setUpTestData(cls):
|
|
||||||
cls.user = AuthUtils.create_user('test')
|
|
||||||
AuthUtils.add_main_character(cls.user, 'test character', '1', corp_id='2', corp_name='test_corp', corp_ticker='TEST', alliance_id='3', alliance_name='TEST')
|
|
||||||
cls.user.profile.refresh_from_db()
|
|
||||||
cls.alliance = EveAllianceInfo.objects.create(alliance_id='3', alliance_name='test alliance', alliance_ticker='TEST', executor_corp_id='2')
|
|
||||||
cls.corp = EveCorporationInfo.objects.create(corporation_id='2', corporation_name='test corp', corporation_ticker='TEST', alliance=cls.alliance, member_count=1)
|
|
||||||
cls.state_group = Group.objects.create(name='state_group')
|
|
||||||
cls.open_group = Group.objects.create(name='open_group')
|
|
||||||
cls.state = AuthUtils.create_state('test state', 500)
|
|
||||||
cls.state_group.authgroup.states.add(cls.state)
|
|
||||||
cls.state_group.authgroup.internal = False
|
|
||||||
cls.state_group.save()
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
self.user.refresh_from_db()
|
|
||||||
self.state.refresh_from_db()
|
|
||||||
|
|
||||||
def _refresh_user(self):
|
|
||||||
self.user = User.objects.get(pk=self.user.pk)
|
|
||||||
|
|
||||||
def _refresh_test_group(self):
|
|
||||||
self.state_group = Group.objects.get(pk=self.state_group.pk)
|
|
||||||
|
|
||||||
def test_drop_state_group(self):
|
|
||||||
|
|
||||||
self.user.groups.add(self.open_group)
|
|
||||||
self.user.groups.add(self.state_group)
|
|
||||||
self.assertEqual(self.user.profile.state.name, "Guest")
|
|
||||||
|
|
||||||
self.state.member_corporations.add(self.corp)
|
|
||||||
self._refresh_user()
|
|
||||||
self.assertEqual(self.user.profile.state, self.state)
|
|
||||||
groups = self.user.groups.all()
|
|
||||||
self.assertIn(self.state_group, groups) #keeps group
|
|
||||||
self.assertIn(self.open_group, groups) #public group unafected
|
|
||||||
|
|
||||||
self.state.member_corporations.clear()
|
|
||||||
self._refresh_user()
|
|
||||||
self.assertEqual(self.user.profile.state.name, "Guest")
|
|
||||||
groups = self.user.groups.all()
|
|
||||||
self.assertNotIn(self.state_group, groups) #looses group
|
|
||||||
self.assertIn(self.open_group, groups) #public group unafected
|
|
||||||
337
allianceauth/groupmanagement/tests/test_managers.py
Normal file
@@ -0,0 +1,337 @@
|
|||||||
|
from unittest.mock import Mock, patch
|
||||||
|
|
||||||
|
from django.contrib.auth.models import Group, User
|
||||||
|
from django.test import TestCase
|
||||||
|
from django.urls import reverse
|
||||||
|
|
||||||
|
from allianceauth.eveonline.models import EveCorporationInfo, EveAllianceInfo
|
||||||
|
from allianceauth.tests.auth_utils import AuthUtils
|
||||||
|
|
||||||
|
from ..models import AuthGroup
|
||||||
|
from ..managers import GroupManager
|
||||||
|
|
||||||
|
|
||||||
|
class MockUserNotAuthenticated():
|
||||||
|
def __init__(self):
|
||||||
|
self.is_authenticated = False
|
||||||
|
|
||||||
|
class GroupManagementVisibilityTestCase(TestCase):
|
||||||
|
@classmethod
|
||||||
|
def setUpTestData(cls):
|
||||||
|
cls.user = AuthUtils.create_user('test')
|
||||||
|
AuthUtils.add_main_character(
|
||||||
|
cls.user, 'test character', '1', corp_id='2', corp_name='test_corp', corp_ticker='TEST', alliance_id='3', alliance_name='TEST'
|
||||||
|
)
|
||||||
|
cls.user.profile.refresh_from_db()
|
||||||
|
cls.alliance = EveAllianceInfo.objects.create(alliance_id='3', alliance_name='test alliance', alliance_ticker='TEST', executor_corp_id='2')
|
||||||
|
cls.corp = EveCorporationInfo.objects.create(
|
||||||
|
corporation_id='2', corporation_name='test corp', corporation_ticker='TEST', alliance=cls.alliance, member_count=1
|
||||||
|
)
|
||||||
|
cls.group1 = Group.objects.create(name='group1')
|
||||||
|
cls.group2 = Group.objects.create(name='group2')
|
||||||
|
cls.group3 = Group.objects.create(name='group3')
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.user.refresh_from_db()
|
||||||
|
|
||||||
|
def _refresh_user(self):
|
||||||
|
self.user = User.objects.get(pk=self.user.pk)
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_group_leaders_groups(self):
|
||||||
|
self.group1.authgroup.group_leaders.add(self.user)
|
||||||
|
self.group2.authgroup.group_leader_groups.add(self.group1)
|
||||||
|
self._refresh_user()
|
||||||
|
groups = GroupManager.get_group_leaders_groups(self.user)
|
||||||
|
|
||||||
|
self.assertIn(self.group1, groups) #avail due to user
|
||||||
|
self.assertNotIn(self.group2, groups) #not avail due to group
|
||||||
|
self.assertNotIn(self.group3, groups) #not avail at all
|
||||||
|
|
||||||
|
self.user.groups.add(self.group1)
|
||||||
|
self._refresh_user()
|
||||||
|
groups = GroupManager.get_group_leaders_groups(self.user)
|
||||||
|
|
||||||
|
|
||||||
|
def test_can_manage_group(self):
|
||||||
|
self.group1.authgroup.group_leaders.add(self.user)
|
||||||
|
self.user.groups.add(self.group1)
|
||||||
|
self._refresh_user()
|
||||||
|
|
||||||
|
self.assertTrue(GroupManager.can_manage_group(self.user, self.group1))
|
||||||
|
self.assertFalse(GroupManager.can_manage_group(self.user, self.group2))
|
||||||
|
self.assertFalse(GroupManager.can_manage_group(self.user, self.group3))
|
||||||
|
|
||||||
|
self.group2.authgroup.group_leader_groups.add(self.group1)
|
||||||
|
self.group1.authgroup.group_leaders.remove(self.user)
|
||||||
|
self._refresh_user()
|
||||||
|
|
||||||
|
self.assertFalse(GroupManager.can_manage_group(self.user, self.group1))
|
||||||
|
self.assertTrue(GroupManager.can_manage_group(self.user, self.group2))
|
||||||
|
self.assertFalse(GroupManager.can_manage_group(self.user, self.group3))
|
||||||
|
|
||||||
|
|
||||||
|
class TestGroupManager(TestCase):
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setUpClass(cls):
|
||||||
|
super().setUpClass()
|
||||||
|
|
||||||
|
# group 1
|
||||||
|
cls.group_default = Group.objects.create(name='default')
|
||||||
|
cls.group_default.authgroup.description = 'Default Group'
|
||||||
|
cls.group_default.authgroup.internal = False
|
||||||
|
cls.group_default.authgroup.hidden = False
|
||||||
|
cls.group_default.authgroup.save()
|
||||||
|
|
||||||
|
# group 2
|
||||||
|
cls.group_internal = Group.objects.create(name='internal')
|
||||||
|
cls.group_internal.authgroup.description = 'Internal Group'
|
||||||
|
cls.group_internal.authgroup.internal = True
|
||||||
|
cls.group_internal.authgroup.save()
|
||||||
|
|
||||||
|
# group 3
|
||||||
|
cls.group_hidden = Group.objects.create(name='hidden')
|
||||||
|
cls.group_hidden.authgroup.description = 'Hidden Group'
|
||||||
|
cls.group_hidden.authgroup.internal = False
|
||||||
|
cls.group_hidden.authgroup.hidden = True
|
||||||
|
cls.group_hidden.authgroup.save()
|
||||||
|
|
||||||
|
# group 4
|
||||||
|
cls.group_open = Group.objects.create(name='open')
|
||||||
|
cls.group_open.authgroup.description = 'Open Group'
|
||||||
|
cls.group_open.authgroup.internal = False
|
||||||
|
cls.group_open.authgroup.hidden = False
|
||||||
|
cls.group_open.authgroup.open = True
|
||||||
|
cls.group_open.authgroup.save()
|
||||||
|
|
||||||
|
# group 5
|
||||||
|
cls.group_public_1 = Group.objects.create(name='public 1')
|
||||||
|
cls.group_public_1.authgroup.description = 'Public Group 1'
|
||||||
|
cls.group_public_1.authgroup.internal = False
|
||||||
|
cls.group_public_1.authgroup.hidden = False
|
||||||
|
cls.group_public_1.authgroup.public = True
|
||||||
|
cls.group_public_1.authgroup.save()
|
||||||
|
|
||||||
|
# group 6
|
||||||
|
cls.group_public_2 = Group.objects.create(name='public 2')
|
||||||
|
cls.group_public_2.authgroup.description = 'Public Group 2'
|
||||||
|
cls.group_public_2.authgroup.internal = False
|
||||||
|
cls.group_public_2.authgroup.hidden = True
|
||||||
|
cls.group_public_2.authgroup.open = True
|
||||||
|
cls.group_public_2.authgroup.public = True
|
||||||
|
cls.group_public_2.authgroup.save()
|
||||||
|
|
||||||
|
# group 7
|
||||||
|
cls.group_default_member = Group.objects.create(name='default members')
|
||||||
|
cls.group_default_member.authgroup.description = \
|
||||||
|
'Default Group for members only'
|
||||||
|
cls.group_default_member.authgroup.internal = False
|
||||||
|
cls.group_default_member.authgroup.hidden = False
|
||||||
|
cls.group_default_member.authgroup.open = False
|
||||||
|
cls.group_default_member.authgroup.public = False
|
||||||
|
cls.group_default_member.authgroup.states.add(
|
||||||
|
AuthUtils.get_member_state()
|
||||||
|
)
|
||||||
|
cls.group_default_member.authgroup.save()
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.user = AuthUtils.create_user('Bruce Wayne')
|
||||||
|
|
||||||
|
def test_get_joinable_group_member(self):
|
||||||
|
result = GroupManager.get_joinable_groups(
|
||||||
|
AuthUtils.get_member_state()
|
||||||
|
)
|
||||||
|
expected = {
|
||||||
|
self.group_default,
|
||||||
|
self.group_hidden,
|
||||||
|
self.group_open,
|
||||||
|
self.group_public_1,
|
||||||
|
self.group_public_2,
|
||||||
|
self.group_default_member
|
||||||
|
}
|
||||||
|
self.assertSetEqual(set(result), expected)
|
||||||
|
|
||||||
|
def test_get_joinable_group_guest(self):
|
||||||
|
result = GroupManager.get_joinable_groups(
|
||||||
|
AuthUtils.get_guest_state()
|
||||||
|
)
|
||||||
|
expected = {
|
||||||
|
self.group_default,
|
||||||
|
self.group_hidden,
|
||||||
|
self.group_open,
|
||||||
|
self.group_public_1,
|
||||||
|
self.group_public_2
|
||||||
|
}
|
||||||
|
self.assertSetEqual(set(result), expected)
|
||||||
|
|
||||||
|
def test_joinable_group_member(self):
|
||||||
|
member_state = AuthUtils.get_member_state()
|
||||||
|
for x in [
|
||||||
|
self.group_default,
|
||||||
|
self.group_hidden,
|
||||||
|
self.group_open,
|
||||||
|
self.group_public_1,
|
||||||
|
self.group_public_2,
|
||||||
|
self.group_default_member
|
||||||
|
]:
|
||||||
|
self.assertTrue(GroupManager.joinable_group(x, member_state))
|
||||||
|
|
||||||
|
for x in [
|
||||||
|
self.group_internal,
|
||||||
|
]:
|
||||||
|
self.assertFalse(GroupManager.joinable_group(x, member_state))
|
||||||
|
|
||||||
|
|
||||||
|
def test_joinable_group_guest(self):
|
||||||
|
guest_state = AuthUtils.get_guest_state()
|
||||||
|
for x in [
|
||||||
|
self.group_default,
|
||||||
|
self.group_hidden,
|
||||||
|
self.group_open,
|
||||||
|
self.group_public_1,
|
||||||
|
self.group_public_2
|
||||||
|
]:
|
||||||
|
self.assertTrue(GroupManager.joinable_group(x, guest_state))
|
||||||
|
|
||||||
|
for x in [
|
||||||
|
self.group_internal,
|
||||||
|
self.group_default_member
|
||||||
|
]:
|
||||||
|
self.assertFalse(GroupManager.joinable_group(x, guest_state))
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_all_non_internal_groups(self):
|
||||||
|
result = GroupManager.get_all_non_internal_groups()
|
||||||
|
expected = {
|
||||||
|
self.group_default,
|
||||||
|
self.group_hidden,
|
||||||
|
self.group_open,
|
||||||
|
self.group_public_1,
|
||||||
|
self.group_public_2,
|
||||||
|
self.group_default_member
|
||||||
|
}
|
||||||
|
self.assertSetEqual(set(result), expected)
|
||||||
|
|
||||||
|
def test_check_internal_group(self):
|
||||||
|
self.assertTrue(
|
||||||
|
GroupManager.check_internal_group(self.group_default)
|
||||||
|
)
|
||||||
|
self.assertFalse(
|
||||||
|
GroupManager.check_internal_group(self.group_internal)
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_get_joinable_groups_for_user_no_permission(self):
|
||||||
|
AuthUtils.assign_state(self.user, AuthUtils.get_guest_state())
|
||||||
|
result = GroupManager.get_joinable_groups_for_user(self.user)
|
||||||
|
expected= {self.group_public_1, self.group_public_2}
|
||||||
|
self.assertSetEqual(set(result), expected)
|
||||||
|
|
||||||
|
def test_get_joinable_groups_for_user_guest_w_permission_(self):
|
||||||
|
AuthUtils.assign_state(self.user, AuthUtils.get_guest_state())
|
||||||
|
AuthUtils.add_permission_to_user_by_name(
|
||||||
|
'groupmanagement.request_groups', self.user
|
||||||
|
)
|
||||||
|
result = GroupManager.get_joinable_groups_for_user(self.user)
|
||||||
|
expected = {
|
||||||
|
self.group_default,
|
||||||
|
self.group_hidden,
|
||||||
|
self.group_open,
|
||||||
|
self.group_public_1,
|
||||||
|
self.group_public_2
|
||||||
|
}
|
||||||
|
self.assertSetEqual(set(result), expected)
|
||||||
|
|
||||||
|
def test_get_joinable_groups_for_user_member_w_permission(self):
|
||||||
|
AuthUtils.assign_state(self.user, AuthUtils.get_member_state(), True)
|
||||||
|
AuthUtils.add_permission_to_user_by_name(
|
||||||
|
'groupmanagement.request_groups', self.user
|
||||||
|
)
|
||||||
|
result = GroupManager.get_joinable_groups_for_user(self.user)
|
||||||
|
expected = {
|
||||||
|
self.group_default,
|
||||||
|
self.group_hidden,
|
||||||
|
self.group_open,
|
||||||
|
self.group_public_1,
|
||||||
|
self.group_public_2,
|
||||||
|
self.group_default_member
|
||||||
|
}
|
||||||
|
self.assertSetEqual(set(result), expected)
|
||||||
|
|
||||||
|
def test_get_joinable_groups_for_user_member_w_permission_no_hidden(self):
|
||||||
|
AuthUtils.assign_state(self.user, AuthUtils.get_member_state(), True)
|
||||||
|
AuthUtils.add_permission_to_user_by_name(
|
||||||
|
'groupmanagement.request_groups', self.user
|
||||||
|
)
|
||||||
|
result = GroupManager.get_joinable_groups_for_user(
|
||||||
|
self.user, include_hidden=False
|
||||||
|
)
|
||||||
|
expected = {
|
||||||
|
self.group_default,
|
||||||
|
self.group_open,
|
||||||
|
self.group_public_1,
|
||||||
|
self.group_default_member
|
||||||
|
}
|
||||||
|
self.assertSetEqual(set(result), expected)
|
||||||
|
|
||||||
|
def test_has_management_permission(self):
|
||||||
|
user = AuthUtils.create_user('Clark Kent')
|
||||||
|
AuthUtils.add_permission_to_user_by_name(
|
||||||
|
'auth.group_management', user
|
||||||
|
)
|
||||||
|
self.assertTrue(GroupManager.has_management_permission(user))
|
||||||
|
|
||||||
|
def test_can_manage_groups_no_perm_no_group(self):
|
||||||
|
user = AuthUtils.create_user('Clark Kent')
|
||||||
|
self.assertFalse(GroupManager.can_manage_groups(user))
|
||||||
|
|
||||||
|
def test_can_manage_groups_user_not_authenticated(self):
|
||||||
|
user = MockUserNotAuthenticated()
|
||||||
|
self.assertFalse(GroupManager.can_manage_groups(user))
|
||||||
|
|
||||||
|
def test_can_manage_groups_has_perm(self):
|
||||||
|
user = AuthUtils.create_user('Clark Kent')
|
||||||
|
AuthUtils.add_permission_to_user_by_name(
|
||||||
|
'auth.group_management', user
|
||||||
|
)
|
||||||
|
self.assertTrue(GroupManager.can_manage_groups(user))
|
||||||
|
|
||||||
|
def test_can_manage_groups_no_perm_leads_group(self):
|
||||||
|
user = AuthUtils.create_user('Clark Kent')
|
||||||
|
self.group_default.authgroup.group_leaders.add(user)
|
||||||
|
self.assertTrue(GroupManager.can_manage_groups(user))
|
||||||
|
|
||||||
|
def test_can_manage_group_no_perm_no_group(self):
|
||||||
|
user = AuthUtils.create_user('Clark Kent')
|
||||||
|
self.assertFalse(
|
||||||
|
GroupManager.can_manage_group(user, self.group_default)
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_can_manage_group_has_perm(self):
|
||||||
|
user = AuthUtils.create_user('Clark Kent')
|
||||||
|
AuthUtils.add_permission_to_user_by_name(
|
||||||
|
'auth.group_management', user
|
||||||
|
)
|
||||||
|
self.assertTrue(
|
||||||
|
GroupManager.can_manage_group(user, self.group_default)
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_can_manage_group_no_perm_leads_correct_group(self):
|
||||||
|
user = AuthUtils.create_user('Clark Kent')
|
||||||
|
self.group_default.authgroup.group_leaders.add(user)
|
||||||
|
self.assertTrue(
|
||||||
|
GroupManager.can_manage_group(user, self.group_default)
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_can_manage_group_no_perm_leads_other_group(self):
|
||||||
|
user = AuthUtils.create_user('Clark Kent')
|
||||||
|
self.group_hidden.authgroup.group_leaders.add(user)
|
||||||
|
self.assertFalse(
|
||||||
|
GroupManager.can_manage_group(user, self.group_default)
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_can_manage_group_user_not_authenticated(self):
|
||||||
|
user = MockUserNotAuthenticated()
|
||||||
|
self.assertFalse(
|
||||||
|
GroupManager.can_manage_group(user, self.group_default)
|
||||||
|
)
|
||||||
167
allianceauth/groupmanagement/tests/test_models.py
Normal file
@@ -0,0 +1,167 @@
|
|||||||
|
from unittest import mock
|
||||||
|
|
||||||
|
from django.contrib.auth.models import User, Group
|
||||||
|
from django.test import TestCase
|
||||||
|
|
||||||
|
from allianceauth.tests.auth_utils import AuthUtils
|
||||||
|
from allianceauth.eveonline.models import (
|
||||||
|
EveCorporationInfo, EveAllianceInfo, EveCharacter
|
||||||
|
)
|
||||||
|
|
||||||
|
from ..models import GroupRequest, RequestLog
|
||||||
|
|
||||||
|
|
||||||
|
def create_testdata():
|
||||||
|
# clear DB
|
||||||
|
User.objects.all().delete()
|
||||||
|
Group.objects.all().delete()
|
||||||
|
EveCharacter.objects.all().delete()
|
||||||
|
EveCorporationInfo.objects.all().delete()
|
||||||
|
EveAllianceInfo.objects.all().delete()
|
||||||
|
|
||||||
|
# group 1
|
||||||
|
group = Group.objects.create(name='Superheros')
|
||||||
|
group.authgroup.description = 'Default Group'
|
||||||
|
group.authgroup.internal = False
|
||||||
|
group.authgroup.hidden = False
|
||||||
|
group.authgroup.save()
|
||||||
|
|
||||||
|
# user 1
|
||||||
|
user_1 = AuthUtils.create_user('Bruce Wayne')
|
||||||
|
AuthUtils.add_main_character_2(
|
||||||
|
user_1,
|
||||||
|
name='Bruce Wayne',
|
||||||
|
character_id=1001,
|
||||||
|
corp_id=2001,
|
||||||
|
corp_name='Wayne Technologies'
|
||||||
|
)
|
||||||
|
user_1.groups.add(group)
|
||||||
|
group.authgroup.group_leaders.add(user_1)
|
||||||
|
|
||||||
|
# user 2
|
||||||
|
user_2 = AuthUtils.create_user('Clark Kent')
|
||||||
|
AuthUtils.add_main_character_2(
|
||||||
|
user_2,
|
||||||
|
name='Clark Kent',
|
||||||
|
character_id=1002,
|
||||||
|
corp_id=2002,
|
||||||
|
corp_name='Wayne Technologies'
|
||||||
|
)
|
||||||
|
return group, user_1, user_2
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class TestGroupRequest(TestCase):
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setUpClass(cls):
|
||||||
|
super().setUpClass()
|
||||||
|
cls.group, cls.user_1, _ = create_testdata()
|
||||||
|
|
||||||
|
def test_main_char(self):
|
||||||
|
group_request = GroupRequest.objects.create(
|
||||||
|
status='Pending',
|
||||||
|
user=self.user_1,
|
||||||
|
group=self.group
|
||||||
|
)
|
||||||
|
expected = self.user_1.profile.main_character
|
||||||
|
self.assertEqual(group_request.main_char, expected)
|
||||||
|
|
||||||
|
def test_str(self):
|
||||||
|
group_request = GroupRequest.objects.create(
|
||||||
|
status='Pending',
|
||||||
|
user=self.user_1,
|
||||||
|
group=self.group
|
||||||
|
)
|
||||||
|
expected = 'Bruce Wayne:Superheros'
|
||||||
|
self.assertEqual(str(group_request), expected)
|
||||||
|
|
||||||
|
|
||||||
|
class TestRequestLog(TestCase):
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setUpClass(cls):
|
||||||
|
super().setUpClass()
|
||||||
|
cls.group, cls.user_1, cls.user_2 = create_testdata()
|
||||||
|
|
||||||
|
def test_requestor(self):
|
||||||
|
request_log = RequestLog.objects.create(
|
||||||
|
group=self.group,
|
||||||
|
request_info='Clark Kent:Superheros',
|
||||||
|
request_actor=self.user_1
|
||||||
|
)
|
||||||
|
expected = 'Clark Kent'
|
||||||
|
self.assertEqual(request_log.requestor(), expected)
|
||||||
|
|
||||||
|
def test_type_to_str_removed(self):
|
||||||
|
request_log = RequestLog.objects.create(
|
||||||
|
request_type=None,
|
||||||
|
group=self.group,
|
||||||
|
request_info='Clark Kent:Superheros',
|
||||||
|
request_actor=self.user_1
|
||||||
|
)
|
||||||
|
expected = 'Removed'
|
||||||
|
self.assertEqual(request_log.type_to_str(), expected)
|
||||||
|
|
||||||
|
def test_type_to_str_leave(self):
|
||||||
|
request_log = RequestLog.objects.create(
|
||||||
|
request_type=True,
|
||||||
|
group=self.group,
|
||||||
|
request_info='Clark Kent:Superheros',
|
||||||
|
request_actor=self.user_1
|
||||||
|
)
|
||||||
|
expected = 'Leave'
|
||||||
|
self.assertEqual(request_log.type_to_str(), expected)
|
||||||
|
|
||||||
|
def test_type_to_str_join(self):
|
||||||
|
request_log = RequestLog.objects.create(
|
||||||
|
request_type=False,
|
||||||
|
group=self.group,
|
||||||
|
request_info='Clark Kent:Superheros',
|
||||||
|
request_actor=self.user_1
|
||||||
|
)
|
||||||
|
expected = 'Join'
|
||||||
|
self.assertEqual(request_log.type_to_str(), expected)
|
||||||
|
|
||||||
|
def test_action_to_str_accept(self):
|
||||||
|
request_log = RequestLog.objects.create(
|
||||||
|
group=self.group,
|
||||||
|
request_info='Clark Kent:Superheros',
|
||||||
|
request_actor=self.user_1,
|
||||||
|
action = True
|
||||||
|
)
|
||||||
|
expected = 'Accept'
|
||||||
|
self.assertEqual(request_log.action_to_str(), expected)
|
||||||
|
|
||||||
|
def test_action_to_str_reject(self):
|
||||||
|
request_log = RequestLog.objects.create(
|
||||||
|
group=self.group,
|
||||||
|
request_info='Clark Kent:Superheros',
|
||||||
|
request_actor=self.user_1,
|
||||||
|
action = False
|
||||||
|
)
|
||||||
|
expected = 'Reject'
|
||||||
|
self.assertEqual(request_log.action_to_str(), expected)
|
||||||
|
|
||||||
|
def test_req_char(self):
|
||||||
|
request_log = RequestLog.objects.create(
|
||||||
|
group=self.group,
|
||||||
|
request_info='Clark Kent:Superheros',
|
||||||
|
request_actor=self.user_1,
|
||||||
|
action = False
|
||||||
|
)
|
||||||
|
expected = self.user_2.profile.main_character
|
||||||
|
self.assertEqual(request_log.req_char(), expected)
|
||||||
|
|
||||||
|
|
||||||
|
class TestAuthGroup(TestCase):
|
||||||
|
|
||||||
|
def test_str(self):
|
||||||
|
group = Group.objects.create(name='Superheros')
|
||||||
|
group.authgroup.description = 'Default Group'
|
||||||
|
group.authgroup.internal = False
|
||||||
|
group.authgroup.hidden = False
|
||||||
|
group.authgroup.save()
|
||||||
|
|
||||||
|
expected = 'Superheros'
|
||||||
|
self.assertEqual(str(group.authgroup), expected)
|
||||||
61
allianceauth/groupmanagement/tests/test_signals.py
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
from unittest import mock
|
||||||
|
|
||||||
|
from django.test import TestCase
|
||||||
|
from django.contrib.auth.models import User, Group
|
||||||
|
|
||||||
|
from allianceauth.eveonline.models import EveCorporationInfo, EveAllianceInfo
|
||||||
|
from allianceauth.tests.auth_utils import AuthUtils
|
||||||
|
|
||||||
|
from ..signals import check_groups_on_state_change
|
||||||
|
|
||||||
|
|
||||||
|
class GroupManagementStateTestCase(TestCase):
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setUpTestData(cls):
|
||||||
|
cls.user = AuthUtils.create_user('test')
|
||||||
|
AuthUtils.add_main_character(
|
||||||
|
cls.user, 'test character', '1', corp_id='2', corp_name='test_corp', corp_ticker='TEST', alliance_id='3', alliance_name='TEST'
|
||||||
|
)
|
||||||
|
cls.user.profile.refresh_from_db()
|
||||||
|
cls.alliance = EveAllianceInfo.objects.create(
|
||||||
|
alliance_id='3', alliance_name='test alliance', alliance_ticker='TEST', executor_corp_id='2'
|
||||||
|
)
|
||||||
|
cls.corp = EveCorporationInfo.objects.create(
|
||||||
|
corporation_id='2', corporation_name='test corp', corporation_ticker='TEST', alliance=cls.alliance, member_count=1
|
||||||
|
)
|
||||||
|
cls.state_group = Group.objects.create(name='state_group')
|
||||||
|
cls.open_group = Group.objects.create(name='open_group')
|
||||||
|
cls.state = AuthUtils.create_state('test state', 500)
|
||||||
|
cls.state_group.authgroup.states.add(cls.state)
|
||||||
|
cls.state_group.authgroup.internal = False
|
||||||
|
cls.state_group.save()
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.user.refresh_from_db()
|
||||||
|
self.state.refresh_from_db()
|
||||||
|
|
||||||
|
def _refresh_user(self):
|
||||||
|
self.user = User.objects.get(pk=self.user.pk)
|
||||||
|
|
||||||
|
def _refresh_test_group(self):
|
||||||
|
self.state_group = Group.objects.get(pk=self.state_group.pk)
|
||||||
|
|
||||||
|
def test_drop_state_group(self):
|
||||||
|
self.user.groups.add(self.open_group)
|
||||||
|
self.user.groups.add(self.state_group)
|
||||||
|
self.assertEqual(self.user.profile.state.name, "Guest")
|
||||||
|
|
||||||
|
self.state.member_corporations.add(self.corp)
|
||||||
|
self._refresh_user()
|
||||||
|
self.assertEqual(self.user.profile.state, self.state)
|
||||||
|
groups = self.user.groups.all()
|
||||||
|
self.assertIn(self.state_group, groups) #keeps group
|
||||||
|
self.assertIn(self.open_group, groups) #public group unafected
|
||||||
|
|
||||||
|
self.state.member_corporations.clear()
|
||||||
|
self._refresh_user()
|
||||||
|
self.assertEqual(self.user.profile.state.name, "Guest")
|
||||||
|
groups = self.user.groups.all()
|
||||||
|
self.assertNotIn(self.state_group, groups) #looses group
|
||||||
|
self.assertIn(self.open_group, groups) #public group unafected
|
||||||
22
allianceauth/groupmanagement/tests/test_views.py
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
from unittest.mock import Mock, patch
|
||||||
|
|
||||||
|
from django.test import RequestFactory, TestCase
|
||||||
|
from django.urls import reverse
|
||||||
|
|
||||||
|
from allianceauth.tests.auth_utils import AuthUtils
|
||||||
|
from esi.models import Token
|
||||||
|
|
||||||
|
from .. import views
|
||||||
|
|
||||||
|
|
||||||
|
class TestViews(TestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.factory = RequestFactory()
|
||||||
|
self.user = AuthUtils.create_user('Bruce Wayne')
|
||||||
|
|
||||||
|
def test_groups_view_can_load(self):
|
||||||
|
request = self.factory.get(reverse('groupmanagement:groups'))
|
||||||
|
request.user = self.user
|
||||||
|
response = views.groups_view(request)
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.contrib.auth.decorators import login_required
|
from django.contrib.auth.decorators import login_required
|
||||||
from django.contrib.auth.decorators import user_passes_test
|
from django.contrib.auth.decorators import user_passes_test
|
||||||
@@ -10,12 +11,12 @@ from django.db.models import Count
|
|||||||
from django.http import Http404
|
from django.http import Http404
|
||||||
from django.shortcuts import render, redirect, get_object_or_404
|
from django.shortcuts import render, redirect, get_object_or_404
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from .managers import GroupManager
|
|
||||||
from .models import GroupRequest, RequestLog
|
|
||||||
|
|
||||||
from allianceauth.notifications import notify
|
from allianceauth.notifications import notify
|
||||||
|
|
||||||
from django.conf import settings
|
from .managers import GroupManager
|
||||||
|
from .models import GroupRequest, RequestLog
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@@ -33,7 +34,8 @@ def group_management(request):
|
|||||||
group_requests = base_group_query.all()
|
group_requests = base_group_query.all()
|
||||||
else:
|
else:
|
||||||
# Group specific leader
|
# Group specific leader
|
||||||
group_requests = base_group_query.filter(group__authgroup__group_leaders__in=[request.user])
|
users__groups = GroupManager.get_group_leaders_groups(request.user)
|
||||||
|
group_requests = base_group_query.filter(group__in=users__groups)
|
||||||
|
|
||||||
for grouprequest in group_requests:
|
for grouprequest in group_requests:
|
||||||
if grouprequest.leave_request:
|
if grouprequest.leave_request:
|
||||||
@@ -234,7 +236,7 @@ def group_reject_request(request, group_request_id):
|
|||||||
raise p
|
raise p
|
||||||
except:
|
except:
|
||||||
messages.error(request, _('An unhandled error occurred while processing the application from %(mainchar)s to %(group)s.') % {"mainchar": group_request.main_char, "group": group_request.group})
|
messages.error(request, _('An unhandled error occurred while processing the application from %(mainchar)s to %(group)s.') % {"mainchar": group_request.main_char, "group": group_request.group})
|
||||||
logger.exception("Unhandled exception occured while user %s attempting to reject group request id %s" % (
|
logger.exception("Unhandled exception occurred while user %s attempting to reject group request id %s" % (
|
||||||
request.user, group_request_id))
|
request.user, group_request_id))
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@@ -268,9 +270,9 @@ def group_leave_accept_request(request, group_request_id):
|
|||||||
(request.user, group_request_id))
|
(request.user, group_request_id))
|
||||||
raise p
|
raise p
|
||||||
except:
|
except:
|
||||||
messages.error(request, _('An unhandled error occured while processing the application from %(mainchar)s to leave %(group)s.') % {
|
messages.error(request, _('An unhandled error occurred while processing the application from %(mainchar)s to leave %(group)s.') % {
|
||||||
"mainchar": group_request.main_char, "group": group_request.group})
|
"mainchar": group_request.main_char, "group": group_request.group})
|
||||||
logger.exception("Unhandled exception occured while user %s attempting to accept group leave request id %s" % (
|
logger.exception("Unhandled exception occurred while user %s attempting to accept group leave request id %s" % (
|
||||||
request.user, group_request_id))
|
request.user, group_request_id))
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@@ -302,9 +304,9 @@ def group_leave_reject_request(request, group_request_id):
|
|||||||
(request.user, group_request_id))
|
(request.user, group_request_id))
|
||||||
raise p
|
raise p
|
||||||
except:
|
except:
|
||||||
messages.error(request, _('An unhandled error occured while processing the application from %(mainchar)s to leave %(group)s.') % {
|
messages.error(request, _('An unhandled error occurred while processing the application from %(mainchar)s to leave %(group)s.') % {
|
||||||
"mainchar": group_request.main_char, "group": group_request.group})
|
"mainchar": group_request.main_char, "group": group_request.group})
|
||||||
logger.exception("Unhandled exception occured while user %s attempting to reject group leave request id %s" % (
|
logger.exception("Unhandled exception occurred while user %s attempting to reject group leave request id %s" % (
|
||||||
request.user, group_request_id))
|
request.user, group_request_id))
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@@ -314,24 +316,23 @@ def group_leave_reject_request(request, group_request_id):
|
|||||||
@login_required
|
@login_required
|
||||||
def groups_view(request):
|
def groups_view(request):
|
||||||
logger.debug("groups_view called by user %s" % request.user)
|
logger.debug("groups_view called by user %s" % request.user)
|
||||||
|
|
||||||
|
groups_qs = GroupManager.get_joinable_groups_for_user(
|
||||||
|
request.user, include_hidden=False
|
||||||
|
)
|
||||||
|
groups_qs = groups_qs.order_by('name')
|
||||||
groups = []
|
groups = []
|
||||||
|
for group in groups_qs:
|
||||||
|
group_request = GroupRequest.objects\
|
||||||
|
.filter(user=request.user)\
|
||||||
|
.filter(group=group)
|
||||||
|
groups.append({
|
||||||
|
'group': group,
|
||||||
|
'request': group_request[0] if group_request else None
|
||||||
|
})
|
||||||
|
|
||||||
group_query = GroupManager.get_joinable_groups(request.user.profile.state)
|
context = {'groups': groups}
|
||||||
|
return render(request, 'groupmanagement/groups.html', context=context)
|
||||||
if not request.user.has_perm('groupmanagement.request_groups'):
|
|
||||||
# Filter down to public groups only for non-members
|
|
||||||
group_query = group_query.filter(authgroup__public=True)
|
|
||||||
logger.debug("Not a member, only public groups will be available")
|
|
||||||
|
|
||||||
for group in group_query:
|
|
||||||
# Exclude hidden
|
|
||||||
if not group.authgroup.hidden:
|
|
||||||
group_request = GroupRequest.objects.filter(user=request.user).filter(group=group)
|
|
||||||
|
|
||||||
groups.append({'group': group, 'request': group_request[0] if group_request else None})
|
|
||||||
|
|
||||||
render_items = {'groups': groups}
|
|
||||||
return render(request, 'groupmanagement/groups.html', context=render_items)
|
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@@ -348,13 +349,13 @@ def group_request_add(request, group_id):
|
|||||||
# User is already a member of this group.
|
# User is already a member of this group.
|
||||||
logger.warning("User %s attempted to join group id %s but they are already a member." %
|
logger.warning("User %s attempted to join group id %s but they are already a member." %
|
||||||
(request.user, group_id))
|
(request.user, group_id))
|
||||||
messages.warning(request, "You are already a member of that group.")
|
messages.warning(request, _("You are already a member of that group."))
|
||||||
return redirect('groupmanagement:groups')
|
return redirect('groupmanagement:groups')
|
||||||
if not request.user.has_perm('groupmanagement.request_groups') and not group.authgroup.public:
|
if not request.user.has_perm('groupmanagement.request_groups') and not group.authgroup.public:
|
||||||
# Does not have the required permission, trying to join a non-public group
|
# Does not have the required permission, trying to join a non-public group
|
||||||
logger.warning("User %s attempted to join group id %s but it is not a public group" %
|
logger.warning("User %s attempted to join group id %s but it is not a public group" %
|
||||||
(request.user, group_id))
|
(request.user, group_id))
|
||||||
messages.warning(request, "You cannot join that group")
|
messages.warning(request, _("You cannot join that group"))
|
||||||
return redirect('groupmanagement:groups')
|
return redirect('groupmanagement:groups')
|
||||||
if group.authgroup.open:
|
if group.authgroup.open:
|
||||||
logger.info("%s joining %s as is an open group" % (request.user, group))
|
logger.info("%s joining %s as is an open group" % (request.user, group))
|
||||||
@@ -363,7 +364,7 @@ def group_request_add(request, group_id):
|
|||||||
req = GroupRequest.objects.filter(user=request.user, group=group)
|
req = GroupRequest.objects.filter(user=request.user, group=group)
|
||||||
if len(req) > 0:
|
if len(req) > 0:
|
||||||
logger.info("%s attempted to join %s but already has an open application" % (request.user, group))
|
logger.info("%s attempted to join %s but already has an open application" % (request.user, group))
|
||||||
messages.warning(request, "You already have a pending application for that group.")
|
messages.warning(request, _("You already have a pending application for that group."))
|
||||||
return redirect("groupmanagement:groups")
|
return redirect("groupmanagement:groups")
|
||||||
grouprequest = GroupRequest()
|
grouprequest = GroupRequest()
|
||||||
grouprequest.status = _('Pending')
|
grouprequest.status = _('Pending')
|
||||||
@@ -397,7 +398,7 @@ def group_request_leave(request, group_id):
|
|||||||
req = GroupRequest.objects.filter(user=request.user, group=group)
|
req = GroupRequest.objects.filter(user=request.user, group=group)
|
||||||
if len(req) > 0:
|
if len(req) > 0:
|
||||||
logger.info("%s attempted to leave %s but already has an pending leave request." % (request.user, group))
|
logger.info("%s attempted to leave %s but already has an pending leave request." % (request.user, group))
|
||||||
messages.warning(request, "You already have a pending leave request for that group.")
|
messages.warning(request, _("You already have a pending leave request for that group."))
|
||||||
return redirect("groupmanagement:groups")
|
return redirect("groupmanagement:groups")
|
||||||
if getattr(settings, 'AUTO_LEAVE', False):
|
if getattr(settings, 'AUTO_LEAVE', False):
|
||||||
logger.info("%s leaving joinable group %s due to auto_leave" % (request.user, group))
|
logger.info("%s leaving joinable group %s due to auto_leave" % (request.user, group))
|
||||||
|
|||||||
BIN
allianceauth/locale/en/LC_MESSAGES/django.mo
Normal file
2018
allianceauth/locale/en/LC_MESSAGES/django.po
Normal file
BIN
allianceauth/locale/ko_KR/LC_MESSAGES/django.mo
Normal file
2023
allianceauth/locale/ko_KR/LC_MESSAGES/django.po
Normal file
BIN
allianceauth/locale/ru/LC_MESSAGES/django.mo
Normal file
2038
allianceauth/locale/ru/LC_MESSAGES/django.po
Normal file
BIN
allianceauth/locale/zh_Hans/LC_MESSAGES/django.mo
Normal file
1811
allianceauth/locale/zh_Hans/LC_MESSAGES/django.po
Normal file
@@ -11,6 +11,15 @@ app = Celery('{{ project_name }}')
|
|||||||
# Using a string here means the worker don't have to serialize
|
# Using a string here means the worker don't have to serialize
|
||||||
# the configuration object to child processes.
|
# the configuration object to child processes.
|
||||||
app.config_from_object('django.conf:settings')
|
app.config_from_object('django.conf:settings')
|
||||||
|
|
||||||
|
# setup priorities ( 0 Highest, 9 Lowest )
|
||||||
|
app.conf.broker_transport_options = {
|
||||||
|
'priority_steps': list(range(10)), # setup que to have 10 steps
|
||||||
|
'queue_order_strategy': 'priority', # setup que to use prio sorting
|
||||||
|
}
|
||||||
|
app.conf.task_default_priority = 5 # anything called with the task.delay() will be given normal priority (5)
|
||||||
|
app.conf.worker_prefetch_multiplier = 1 # only prefetch single tasks at a time on the workers so that prio tasks happen
|
||||||
|
|
||||||
app.conf.ONCE = {
|
app.conf.ONCE = {
|
||||||
'backend': 'allianceauth.services.tasks.DjangoBackend',
|
'backend': 'allianceauth.services.tasks.DjangoBackend',
|
||||||
'settings': {}
|
'settings': {}
|
||||||
|
|||||||
@@ -83,6 +83,9 @@ LANGUAGES = (
|
|||||||
('en', ugettext('English')),
|
('en', ugettext('English')),
|
||||||
('de', ugettext('German')),
|
('de', ugettext('German')),
|
||||||
('es', ugettext('Spanish')),
|
('es', ugettext('Spanish')),
|
||||||
|
('zh-hans', ugettext('Chinese Simplified')),
|
||||||
|
('ru', ugettext('Russian')),
|
||||||
|
('ko', ugettext('Korean')),
|
||||||
)
|
)
|
||||||
|
|
||||||
TEMPLATES = [
|
TEMPLATES = [
|
||||||
@@ -217,6 +220,14 @@ LOGGING = {
|
|||||||
'maxBytes': 1024 * 1024 * 5, # edit this line to change max log file size
|
'maxBytes': 1024 * 1024 * 5, # edit this line to change max log file size
|
||||||
'backupCount': 5, # edit this line to change number of log backups
|
'backupCount': 5, # edit this line to change number of log backups
|
||||||
},
|
},
|
||||||
|
'extension_file': {
|
||||||
|
'level': 'DEBUG',
|
||||||
|
'class': 'logging.handlers.RotatingFileHandler',
|
||||||
|
'filename': os.path.join(BASE_DIR, 'log/extensions.log'),
|
||||||
|
'formatter': 'verbose',
|
||||||
|
'maxBytes': 1024 * 1024 * 5, # edit this line to change max log file size
|
||||||
|
'backupCount': 5, # edit this line to change number of log backups
|
||||||
|
},
|
||||||
'console': {
|
'console': {
|
||||||
'level': 'DEBUG', # edit this line to change logging level to console
|
'level': 'DEBUG', # edit this line to change logging level to console
|
||||||
'class': 'logging.StreamHandler',
|
'class': 'logging.StreamHandler',
|
||||||
@@ -233,6 +244,10 @@ LOGGING = {
|
|||||||
'handlers': ['log_file', 'console', 'notifications'],
|
'handlers': ['log_file', 'console', 'notifications'],
|
||||||
'level': 'DEBUG',
|
'level': 'DEBUG',
|
||||||
},
|
},
|
||||||
|
'extensions': {
|
||||||
|
'handlers': ['extension_file', 'console'],
|
||||||
|
'level': 'DEBUG',
|
||||||
|
},
|
||||||
'django': {
|
'django': {
|
||||||
'handlers': ['log_file', 'console'],
|
'handlers': ['log_file', 'console'],
|
||||||
'level': 'ERROR',
|
'level': 'ERROR',
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ from django.contrib.auth.mixins import LoginRequiredMixin, PermissionRequiredMix
|
|||||||
from django.db import models, IntegrityError
|
from django.db import models, IntegrityError
|
||||||
from django.core.exceptions import ObjectDoesNotExist
|
from django.core.exceptions import ObjectDoesNotExist
|
||||||
from django.shortcuts import render, Http404, redirect
|
from django.shortcuts import render, Http404, redirect
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
from .forms import ServicePasswordModelForm
|
from .forms import ServicePasswordModelForm
|
||||||
|
|
||||||
@@ -68,7 +69,7 @@ class BaseCreatePasswordServiceAccountView(BaseServiceView, ServiceCredentialsVi
|
|||||||
try:
|
try:
|
||||||
svc_obj = self.model.objects.create(user=request.user)
|
svc_obj = self.model.objects.create(user=request.user)
|
||||||
except IntegrityError:
|
except IntegrityError:
|
||||||
messages.error(request, "That service account already exists")
|
messages.error(request, _("That service account already exists"))
|
||||||
return redirect(self.index_redirect)
|
return redirect(self.index_redirect)
|
||||||
|
|
||||||
return render(request, self.template_name,
|
return render(request, self.template_name,
|
||||||
@@ -100,7 +101,7 @@ class BaseSetPasswordServiceAccountView(ServicesCRUDMixin, BaseServiceView, Upda
|
|||||||
def post(self, request, *args, **kwargs):
|
def post(self, request, *args, **kwargs):
|
||||||
result = super(BaseSetPasswordServiceAccountView, self).post(request, *args, **kwargs)
|
result = super(BaseSetPasswordServiceAccountView, self).post(request, *args, **kwargs)
|
||||||
if self.get_form().is_valid():
|
if self.get_form().is_valid():
|
||||||
messages.success(request, "Successfully set your {} password".format(self.service_name))
|
messages.success(request, _("Successfully set your {} password".format(self.service_name)))
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -20,11 +20,8 @@ class ServicesUserAdmin(admin.ModelAdmin):
|
|||||||
"all": ("services/admin.css",)
|
"all": ("services/admin.css",)
|
||||||
}
|
}
|
||||||
|
|
||||||
search_fields = (
|
search_fields = ('user__username',)
|
||||||
'user__username',
|
ordering = ('user__username',)
|
||||||
'uid'
|
|
||||||
)
|
|
||||||
ordering = ('user__username', )
|
|
||||||
list_select_related = True
|
list_select_related = True
|
||||||
list_display = (
|
list_display = (
|
||||||
user_profile_pic,
|
user_profile_pic,
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
from allianceauth import hooks
|
from allianceauth import hooks
|
||||||
|
|
||||||
from .hooks import MenuItemHook
|
from .hooks import MenuItemHook
|
||||||
from .hooks import ServicesHook
|
from .hooks import ServicesHook
|
||||||
|
|
||||||
@@ -6,7 +8,7 @@ from .hooks import ServicesHook
|
|||||||
class Services(MenuItemHook):
|
class Services(MenuItemHook):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
MenuItemHook.__init__(self,
|
MenuItemHook.__init__(self,
|
||||||
'Services',
|
_('Services'),
|
||||||
'fa fa-cogs fa-fw',
|
'fa fa-cogs fa-fw',
|
||||||
'services:services', 100)
|
'services:services', 100)
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,29 @@ from allianceauth.hooks import get_hooks
|
|||||||
from .models import NameFormatConfig
|
from .models import NameFormatConfig
|
||||||
|
|
||||||
|
|
||||||
|
def get_extension_logger(name):
|
||||||
|
"""
|
||||||
|
Takes the name of a plugin/extension and generates a child logger of the extensions logger
|
||||||
|
to be used by the extension to log events to the extensions logger.
|
||||||
|
|
||||||
|
The logging level is decided by whether or not DEBUG is set to true in the project settings. If
|
||||||
|
DEBUG is set to false, then the logging level is set to INFO.
|
||||||
|
|
||||||
|
:param: name: the name of the extension doing the logging
|
||||||
|
:return: an extensions child logger
|
||||||
|
"""
|
||||||
|
import logging
|
||||||
|
from django.conf import settings
|
||||||
|
|
||||||
|
logger = logging.getLogger('extensions.' + name)
|
||||||
|
logger.name = name
|
||||||
|
logger.level = logging.INFO
|
||||||
|
if settings.DEBUG:
|
||||||
|
logger.level = logging.DEBUG
|
||||||
|
|
||||||
|
return logger
|
||||||
|
|
||||||
|
|
||||||
class ServicesHook:
|
class ServicesHook:
|
||||||
"""
|
"""
|
||||||
Abstract base class for creating a compatible services
|
Abstract base class for creating a compatible services
|
||||||
|
|||||||
@@ -1,38 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
# Generated by Django 1.10.1 on 2016-09-05 21:40
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
|
|
||||||
from django.conf import settings
|
|
||||||
from django.db import migrations, models
|
|
||||||
import django.db.models.deletion
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
initial = True
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('auth', '0008_alter_user_username_max_length'),
|
|
||||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='DiscordAuthToken',
|
|
||||||
fields=[
|
|
||||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
||||||
('email', models.CharField(max_length=254, unique=True)),
|
|
||||||
('token', models.CharField(max_length=254)),
|
|
||||||
('user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='GroupCache',
|
|
||||||
fields=[
|
|
||||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
||||||
('created', models.DateTimeField(auto_now_add=True)),
|
|
||||||
('groups', models.TextField(default={})),
|
|
||||||
('service', models.CharField(choices=[(b'discourse', b'discourse'), (b'discord', b'discord')], max_length=254, unique=True)),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
# Generated by Django 1.10.1 on 2016-10-16 01:35
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
|
|
||||||
from django.db import migrations
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('services', '0001_initial'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.RemoveField(
|
|
||||||
model_name='discordauthtoken',
|
|
||||||
name='user',
|
|
||||||
),
|
|
||||||
migrations.DeleteModel(
|
|
||||||
name='DiscordAuthToken',
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
# Generated by Django 1.10.5 on 2017-09-02 06:07
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
|
|
||||||
from django.db import migrations
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('services', '0002_auto_20161016_0135'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.DeleteModel(
|
|
||||||
name='GroupCache',
|
|
||||||
),
|
|
||||||
]
|
|
||||||
18
allianceauth/services/migrations/0003_remove_broken_link.py
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 2.2.10 on 2020-03-21 13:11
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('services', '0002_nameformatter'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='nameformatconfig',
|
||||||
|
name='format',
|
||||||
|
field=models.CharField(help_text='For information on constructing name formats please see the official documentation, topic "Services Name Formats".', max_length=100),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -4,14 +4,30 @@ from allianceauth.authentication.models import State
|
|||||||
|
|
||||||
|
|
||||||
class NameFormatConfig(models.Model):
|
class NameFormatConfig(models.Model):
|
||||||
service_name = models.CharField(max_length=100, blank=False, null=False)
|
service_name = models.CharField(max_length=100, blank=False)
|
||||||
default_to_username = models.BooleanField(default=True, help_text="If a user has no main_character, "
|
default_to_username = models.BooleanField(
|
||||||
"default to using their Auth username instead.")
|
default=True,
|
||||||
format = models.CharField(max_length=100, blank=False, null=False,
|
help_text=
|
||||||
help_text='For information on constructing name formats, please see the '
|
'If a user has no main_character, '
|
||||||
'<a href="https://allianceauth.readthedocs.io/en/latest/features/nameformats">'
|
'default to using their Auth username instead.'
|
||||||
'name format documentation</a>')
|
)
|
||||||
states = models.ManyToManyField(State, help_text="States to apply this format to. You should only have one "
|
format = models.CharField(
|
||||||
"formatter for each state for each service.")
|
max_length=100,
|
||||||
|
blank=False,
|
||||||
|
help_text=
|
||||||
|
'For information on constructing name formats '
|
||||||
|
'please see the official documentation, '
|
||||||
|
'topic "Services Name Formats".'
|
||||||
|
)
|
||||||
|
states = models.ManyToManyField(
|
||||||
|
State,
|
||||||
|
help_text=
|
||||||
|
"States to apply this format to. You should only have one "
|
||||||
|
"formatter for each state for each service."
|
||||||
|
)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return '%s: %s' % (
|
||||||
|
self.service_name, ', '.join([str(x) for x in self.states.all()])
|
||||||
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -6,9 +6,8 @@ from ...admin import ServicesUserAdmin
|
|||||||
|
|
||||||
@admin.register(DiscordUser)
|
@admin.register(DiscordUser)
|
||||||
class DiscordUserAdmin(ServicesUserAdmin):
|
class DiscordUserAdmin(ServicesUserAdmin):
|
||||||
list_display = ServicesUserAdmin.list_display + (
|
list_display = ServicesUserAdmin.list_display + ('_uid',)
|
||||||
'_uid',
|
search_fields = ServicesUserAdmin.search_fields + ('uid', )
|
||||||
)
|
|
||||||
|
|
||||||
def _uid(self, obj):
|
def _uid(self, obj):
|
||||||
return obj.uid
|
return obj.uid
|
||||||
|
|||||||
@@ -5,8 +5,10 @@ from django.contrib.auth.decorators import login_required
|
|||||||
from django.contrib.auth.decorators import permission_required
|
from django.contrib.auth.decorators import permission_required
|
||||||
from django.contrib.auth.decorators import user_passes_test
|
from django.contrib.auth.decorators import user_passes_test
|
||||||
from django.shortcuts import redirect
|
from django.shortcuts import redirect
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
from allianceauth.services.views import superuser_test
|
from allianceauth.services.views import superuser_test
|
||||||
|
|
||||||
from .manager import DiscordOAuthManager
|
from .manager import DiscordOAuthManager
|
||||||
from .tasks import DiscordTasks
|
from .tasks import DiscordTasks
|
||||||
|
|
||||||
@@ -21,10 +23,10 @@ def deactivate_discord(request):
|
|||||||
logger.debug("deactivate_discord called by user %s" % request.user)
|
logger.debug("deactivate_discord called by user %s" % request.user)
|
||||||
if DiscordTasks.delete_user(request.user):
|
if DiscordTasks.delete_user(request.user):
|
||||||
logger.info("Successfully deactivated discord for user %s" % request.user)
|
logger.info("Successfully deactivated discord for user %s" % request.user)
|
||||||
messages.success(request, 'Deactivated Discord account.')
|
messages.success(request, _('Deactivated Discord account.'))
|
||||||
else:
|
else:
|
||||||
logger.error("Unsuccessful attempt to deactivate discord for user %s" % request.user)
|
logger.error("Unsuccessful attempt to deactivate discord for user %s" % request.user)
|
||||||
messages.error(request, 'An error occurred while processing your Discord account.')
|
messages.error(request, _('An error occurred while processing your Discord account.'))
|
||||||
return redirect("services:services")
|
return redirect("services:services")
|
||||||
|
|
||||||
|
|
||||||
@@ -36,7 +38,7 @@ def reset_discord(request):
|
|||||||
logger.info("Successfully deleted discord user for user %s - forwarding to discord activation." % request.user)
|
logger.info("Successfully deleted discord user for user %s - forwarding to discord activation." % request.user)
|
||||||
return redirect("discord:activate")
|
return redirect("discord:activate")
|
||||||
logger.error("Unsuccessful attempt to reset discord for user %s" % request.user)
|
logger.error("Unsuccessful attempt to reset discord for user %s" % request.user)
|
||||||
messages.error(request, 'An error occurred while processing your Discord account.')
|
messages.error(request, _('An error occurred while processing your Discord account.'))
|
||||||
return redirect("services:services")
|
return redirect("services:services")
|
||||||
|
|
||||||
|
|
||||||
@@ -57,10 +59,10 @@ def discord_callback(request):
|
|||||||
return redirect("services:services")
|
return redirect("services:services")
|
||||||
if DiscordTasks.add_user(request.user, code):
|
if DiscordTasks.add_user(request.user, code):
|
||||||
logger.info("Successfully activated Discord for user %s" % request.user)
|
logger.info("Successfully activated Discord for user %s" % request.user)
|
||||||
messages.success(request, 'Activated Discord account.')
|
messages.success(request, _('Activated Discord account.'))
|
||||||
else:
|
else:
|
||||||
logger.error("Failed to activate Discord for user %s" % request.user)
|
logger.error("Failed to activate Discord for user %s" % request.user)
|
||||||
messages.error(request, 'An error occurred while processing your Discord account.')
|
messages.error(request, _('An error occurred while processing your Discord account.'))
|
||||||
return redirect("services:services")
|
return redirect("services:services")
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ from django.conf import settings
|
|||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.contrib.auth.decorators import login_required
|
from django.contrib.auth.decorators import login_required
|
||||||
from django.shortcuts import render, redirect
|
from django.shortcuts import render, redirect
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
from .manager import DiscourseManager
|
from .manager import DiscourseManager
|
||||||
from .tasks import DiscourseTasks
|
from .tasks import DiscourseTasks
|
||||||
@@ -33,12 +34,12 @@ def discourse_sso(request):
|
|||||||
|
|
||||||
# Check if user has access
|
# Check if user has access
|
||||||
if not request.user.has_perm(ACCESS_PERM):
|
if not request.user.has_perm(ACCESS_PERM):
|
||||||
messages.error(request, 'You are not authorized to access Discourse.')
|
messages.error(request, _('You are not authorized to access Discourse.'))
|
||||||
logger.warning('User %s attempted to access Discourse but does not have permission.' % request.user)
|
logger.warning('User %s attempted to access Discourse but does not have permission.' % request.user)
|
||||||
return redirect('authentication:dashboard')
|
return redirect('authentication:dashboard')
|
||||||
|
|
||||||
if not request.user.profile.main_character:
|
if not request.user.profile.main_character:
|
||||||
messages.error(request, "You must have a main character set to access Discourse.")
|
messages.error(request, _("You must have a main character set to access Discourse."))
|
||||||
logger.warning('User %s attempted to access Discourse but does not have a main character.' % request.user)
|
logger.warning('User %s attempted to access Discourse but does not have a main character.' % request.user)
|
||||||
return redirect('authentication:characters')
|
return redirect('authentication:characters')
|
||||||
|
|
||||||
@@ -48,7 +49,7 @@ def discourse_sso(request):
|
|||||||
signature = request.GET.get('sig')
|
signature = request.GET.get('sig')
|
||||||
|
|
||||||
if None in [payload, signature]:
|
if None in [payload, signature]:
|
||||||
messages.error(request, 'No SSO payload or signature. Please contact support if this problem persists.')
|
messages.error(request, _('No SSO payload or signature. Please contact support if this problem persists.'))
|
||||||
return redirect('authentication:dashboard')
|
return redirect('authentication:dashboard')
|
||||||
|
|
||||||
# Validate the payload
|
# Validate the payload
|
||||||
@@ -58,7 +59,7 @@ def discourse_sso(request):
|
|||||||
assert 'nonce' in decoded
|
assert 'nonce' in decoded
|
||||||
assert len(payload) > 0
|
assert len(payload) > 0
|
||||||
except AssertionError:
|
except AssertionError:
|
||||||
messages.error(request, 'Invalid payload. Please contact support if this problem persists.')
|
messages.error(request, _('Invalid payload. Please contact support if this problem persists.'))
|
||||||
return redirect('authentication:dashboard')
|
return redirect('authentication:dashboard')
|
||||||
|
|
||||||
key = str(settings.DISCOURSE_SSO_SECRET).encode('utf-8')
|
key = str(settings.DISCOURSE_SSO_SECRET).encode('utf-8')
|
||||||
@@ -66,7 +67,7 @@ def discourse_sso(request):
|
|||||||
this_signature = h.hexdigest()
|
this_signature = h.hexdigest()
|
||||||
|
|
||||||
if this_signature != signature:
|
if this_signature != signature:
|
||||||
messages.error(request, 'Invalid payload. Please contact support if this problem persists.')
|
messages.error(request, _('Invalid payload. Please contact support if this problem persists.'))
|
||||||
return redirect('authentication:dashboard')
|
return redirect('authentication:dashboard')
|
||||||
|
|
||||||
## Build the return payload
|
## Build the return payload
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import logging
|
|||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.contrib.auth.decorators import login_required, permission_required
|
from django.contrib.auth.decorators import login_required, permission_required
|
||||||
from django.shortcuts import render, redirect
|
from django.shortcuts import render, redirect
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
from allianceauth.services.forms import ServicePasswordForm
|
from allianceauth.services.forms import ServicePasswordForm
|
||||||
from .manager import Ips4Manager
|
from .manager import Ips4Manager
|
||||||
@@ -27,7 +28,7 @@ def activate_ips4(request):
|
|||||||
logger.debug("Updated authserviceinfo for user %s with IPS4 credentials." % request.user)
|
logger.debug("Updated authserviceinfo for user %s with IPS4 credentials." % request.user)
|
||||||
# update_ips4_groups.delay(request.user.pk)
|
# update_ips4_groups.delay(request.user.pk)
|
||||||
logger.info("Successfully activated IPS4 for user %s" % request.user)
|
logger.info("Successfully activated IPS4 for user %s" % request.user)
|
||||||
messages.success(request, 'Activated IPSuite4 account.')
|
messages.success(request, _('Activated IPSuite4 account.'))
|
||||||
credentials = {
|
credentials = {
|
||||||
'username': result[0],
|
'username': result[0],
|
||||||
'password': result[1],
|
'password': result[1],
|
||||||
@@ -36,7 +37,7 @@ def activate_ips4(request):
|
|||||||
context={'credentials': credentials, 'service': 'IPSuite4'})
|
context={'credentials': credentials, 'service': 'IPSuite4'})
|
||||||
else:
|
else:
|
||||||
logger.error("Unsuccessful attempt to activate IPS4 for user %s" % request.user)
|
logger.error("Unsuccessful attempt to activate IPS4 for user %s" % request.user)
|
||||||
messages.error(request, 'An error occurred while processing your IPSuite4 account.')
|
messages.error(request, _('An error occurred while processing your IPSuite4 account.'))
|
||||||
return redirect("services:services")
|
return redirect("services:services")
|
||||||
|
|
||||||
|
|
||||||
@@ -49,7 +50,7 @@ def reset_ips4_password(request):
|
|||||||
# false we failed
|
# false we failed
|
||||||
if result != "":
|
if result != "":
|
||||||
logger.info("Successfully reset IPS4 password for user %s" % request.user)
|
logger.info("Successfully reset IPS4 password for user %s" % request.user)
|
||||||
messages.success(request, 'Reset IPSuite4 password.')
|
messages.success(request, _('Reset IPSuite4 password.'))
|
||||||
credentials = {
|
credentials = {
|
||||||
'username': request.user.ips4.username,
|
'username': request.user.ips4.username,
|
||||||
'password': result,
|
'password': result,
|
||||||
@@ -58,7 +59,7 @@ def reset_ips4_password(request):
|
|||||||
context={'credentials': credentials, 'service': 'IPSuite4'})
|
context={'credentials': credentials, 'service': 'IPSuite4'})
|
||||||
|
|
||||||
logger.error("Unsuccessful attempt to reset IPS4 password for user %s" % request.user)
|
logger.error("Unsuccessful attempt to reset IPS4 password for user %s" % request.user)
|
||||||
messages.error(request, 'An error occurred while processing your IPSuite4 account.')
|
messages.error(request, _('An error occurred while processing your IPSuite4 account.'))
|
||||||
return redirect("services:services")
|
return redirect("services:services")
|
||||||
|
|
||||||
|
|
||||||
@@ -76,10 +77,10 @@ def set_ips4_password(request):
|
|||||||
result = Ips4Manager.update_custom_password(request.user.ips4.username, plain_password=password)
|
result = Ips4Manager.update_custom_password(request.user.ips4.username, plain_password=password)
|
||||||
if result != "":
|
if result != "":
|
||||||
logger.info("Successfully set IPS4 password for user %s" % request.user)
|
logger.info("Successfully set IPS4 password for user %s" % request.user)
|
||||||
messages.success(request, 'Set IPSuite4 password.')
|
messages.success(request, _('Set IPSuite4 password.'))
|
||||||
else:
|
else:
|
||||||
logger.error("Failed to install custom IPS4 password for user %s" % request.user)
|
logger.error("Failed to install custom IPS4 password for user %s" % request.user)
|
||||||
messages.error(request, 'An error occurred while processing your IPSuite4 account.')
|
messages.error(request, _('An error occurred while processing your IPSuite4 account.'))
|
||||||
return redirect('services:services')
|
return redirect('services:services')
|
||||||
else:
|
else:
|
||||||
logger.debug("Request is not type POST - providing empty form.")
|
logger.debug("Request is not type POST - providing empty form.")
|
||||||
@@ -96,9 +97,9 @@ def deactivate_ips4(request):
|
|||||||
logger.debug("deactivate_ips4 called by user %s" % request.user)
|
logger.debug("deactivate_ips4 called by user %s" % request.user)
|
||||||
if Ips4Tasks.delete_user(request.user):
|
if Ips4Tasks.delete_user(request.user):
|
||||||
logger.info("Successfully deactivated IPS4 for user %s" % request.user)
|
logger.info("Successfully deactivated IPS4 for user %s" % request.user)
|
||||||
messages.success(request, 'Deactivated IPSuite4 account.')
|
messages.success(request, _('Deactivated IPSuite4 account.'))
|
||||||
else:
|
else:
|
||||||
logger.error("Unsuccessful attempt to deactivate IPS4 for user %s" % request.user)
|
logger.error("Unsuccessful attempt to deactivate IPS4 for user %s" % request.user)
|
||||||
messages.error(request, 'An error occurred while processing your IPSuite4 account.')
|
messages.error(request, _('An error occurred while processing your IPSuite4 account.'))
|
||||||
return redirect("services:services")
|
return redirect("services:services")
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import logging
|
|||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.template.loader import render_to_string
|
from django.template.loader import render_to_string
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
from allianceauth import hooks
|
from allianceauth import hooks
|
||||||
from allianceauth.services.hooks import ServicesHook, MenuItemHook
|
from allianceauth.services.hooks import ServicesHook, MenuItemHook
|
||||||
@@ -22,7 +23,7 @@ class OpenfireService(ServicesHook):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def title(self):
|
def title(self):
|
||||||
return "Jabber"
|
return _("Jabber")
|
||||||
|
|
||||||
def delete_user(self, user, notify_user=False):
|
def delete_user(self, user, notify_user=False):
|
||||||
logger.debug('Deleting user %s %s account' % (user, self.name))
|
logger.debug('Deleting user %s %s account' % (user, self.name))
|
||||||
@@ -74,7 +75,7 @@ def register_service():
|
|||||||
class JabberBroadcast(MenuItemHook):
|
class JabberBroadcast(MenuItemHook):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
MenuItemHook.__init__(self,
|
MenuItemHook.__init__(self,
|
||||||
'Jabber Broadcast',
|
_('Jabber Broadcast'),
|
||||||
'fa fa-lock fa-fw fa-bullhorn',
|
'fa fa-lock fa-fw fa-bullhorn',
|
||||||
'openfire:broadcast')
|
'openfire:broadcast')
|
||||||
|
|
||||||
@@ -87,7 +88,7 @@ class JabberBroadcast(MenuItemHook):
|
|||||||
class FleetBroadcastFormatter(MenuItemHook):
|
class FleetBroadcastFormatter(MenuItemHook):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
MenuItemHook.__init__(self,
|
MenuItemHook.__init__(self,
|
||||||
'Fleet Broadcast Formatter',
|
_('Fleet Broadcast Formatter'),
|
||||||
'fa fa-lock fa-fw fa-space-shuttle',
|
'fa fa-lock fa-fw fa-space-shuttle',
|
||||||
'services:fleet_format_tool')
|
'services:fleet_format_tool')
|
||||||
|
|
||||||
|
|||||||
@@ -5,8 +5,10 @@ from django.contrib import messages
|
|||||||
from django.contrib.auth.decorators import login_required, permission_required
|
from django.contrib.auth.decorators import login_required, permission_required
|
||||||
from django.contrib.auth.models import Group
|
from django.contrib.auth.models import Group
|
||||||
from django.shortcuts import render, redirect
|
from django.shortcuts import render, redirect
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
from allianceauth.services.forms import ServicePasswordForm
|
from allianceauth.services.forms import ServicePasswordForm
|
||||||
|
|
||||||
from .forms import JabberBroadcastForm
|
from .forms import JabberBroadcastForm
|
||||||
from .manager import OpenfireManager, PingBotException
|
from .manager import OpenfireManager, PingBotException
|
||||||
from .models import OpenfireUser
|
from .models import OpenfireUser
|
||||||
@@ -30,7 +32,7 @@ def activate_jabber(request):
|
|||||||
logger.debug("Updated authserviceinfo for user %s with jabber credentials. Updating groups." % request.user)
|
logger.debug("Updated authserviceinfo for user %s with jabber credentials. Updating groups." % request.user)
|
||||||
OpenfireTasks.update_groups.delay(request.user.pk)
|
OpenfireTasks.update_groups.delay(request.user.pk)
|
||||||
logger.info("Successfully activated jabber for user %s" % request.user)
|
logger.info("Successfully activated jabber for user %s" % request.user)
|
||||||
messages.success(request, 'Activated jabber account.')
|
messages.success(request, _('Activated jabber account.'))
|
||||||
credentials = {
|
credentials = {
|
||||||
'username': info[0],
|
'username': info[0],
|
||||||
'password': info[1],
|
'password': info[1],
|
||||||
@@ -39,7 +41,7 @@ def activate_jabber(request):
|
|||||||
context={'credentials': credentials, 'service': 'Jabber'})
|
context={'credentials': credentials, 'service': 'Jabber'})
|
||||||
else:
|
else:
|
||||||
logger.error("Unsuccessful attempt to activate jabber for user %s" % request.user)
|
logger.error("Unsuccessful attempt to activate jabber for user %s" % request.user)
|
||||||
messages.error(request, 'An error occurred while processing your jabber account.')
|
messages.error(request, _('An error occurred while processing your jabber account.'))
|
||||||
return redirect("services:services")
|
return redirect("services:services")
|
||||||
|
|
||||||
|
|
||||||
@@ -52,7 +54,7 @@ def deactivate_jabber(request):
|
|||||||
messages.success(request, 'Deactivated jabber account.')
|
messages.success(request, 'Deactivated jabber account.')
|
||||||
else:
|
else:
|
||||||
logger.error("Unsuccessful attempt to deactivate jabber for user %s" % request.user)
|
logger.error("Unsuccessful attempt to deactivate jabber for user %s" % request.user)
|
||||||
messages.error(request, 'An error occurred while processing your jabber account.')
|
messages.error(request, _('An error occurred while processing your jabber account.'))
|
||||||
return redirect("services:services")
|
return redirect("services:services")
|
||||||
|
|
||||||
|
|
||||||
@@ -65,7 +67,7 @@ def reset_jabber_password(request):
|
|||||||
# If our username is blank means we failed
|
# If our username is blank means we failed
|
||||||
if result != "":
|
if result != "":
|
||||||
logger.info("Successfully reset jabber password for user %s" % request.user)
|
logger.info("Successfully reset jabber password for user %s" % request.user)
|
||||||
messages.success(request, 'Reset jabber password.')
|
messages.success(request, _('Reset jabber password.'))
|
||||||
credentials = {
|
credentials = {
|
||||||
'username': request.user.openfire.username,
|
'username': request.user.openfire.username,
|
||||||
'password': result,
|
'password': result,
|
||||||
@@ -73,7 +75,7 @@ def reset_jabber_password(request):
|
|||||||
return render(request, 'services/service_credentials.html',
|
return render(request, 'services/service_credentials.html',
|
||||||
context={'credentials': credentials, 'service': 'Jabber'})
|
context={'credentials': credentials, 'service': 'Jabber'})
|
||||||
logger.error("Unsuccessful attempt to reset jabber for user %s" % request.user)
|
logger.error("Unsuccessful attempt to reset jabber for user %s" % request.user)
|
||||||
messages.error(request, 'An error occurred while processing your jabber account.')
|
messages.error(request, _('An error occurred while processing your jabber account.'))
|
||||||
return redirect("services:services")
|
return redirect("services:services")
|
||||||
|
|
||||||
|
|
||||||
@@ -114,7 +116,7 @@ def jabber_broadcast_view(request):
|
|||||||
|
|
||||||
OpenfireManager.send_broadcast_message(group_to_send, message_to_send)
|
OpenfireManager.send_broadcast_message(group_to_send, message_to_send)
|
||||||
|
|
||||||
messages.success(request, 'Sent jabber broadcast to %s' % group_to_send)
|
messages.success(request, _('Sent jabber broadcast to %s' % group_to_send))
|
||||||
logger.info("Sent jabber broadcast on behalf of user %s" % request.user)
|
logger.info("Sent jabber broadcast on behalf of user %s" % request.user)
|
||||||
except PingBotException as e:
|
except PingBotException as e:
|
||||||
messages.error(request, e)
|
messages.error(request, e)
|
||||||
@@ -143,10 +145,10 @@ def set_jabber_password(request):
|
|||||||
result = OpenfireManager.update_user_pass(request.user.openfire.username, password=password)
|
result = OpenfireManager.update_user_pass(request.user.openfire.username, password=password)
|
||||||
if result != "":
|
if result != "":
|
||||||
logger.info("Successfully set jabber password for user %s" % request.user)
|
logger.info("Successfully set jabber password for user %s" % request.user)
|
||||||
messages.success(request, 'Set jabber password.')
|
messages.success(request, _('Set jabber password.'))
|
||||||
else:
|
else:
|
||||||
logger.error("Failed to install custom jabber password for user %s" % request.user)
|
logger.error("Failed to install custom jabber password for user %s" % request.user)
|
||||||
messages.error(request, 'An error occurred while processing your jabber account.')
|
messages.error(request, _('An error occurred while processing your jabber account.'))
|
||||||
return redirect("services:services")
|
return redirect("services:services")
|
||||||
else:
|
else:
|
||||||
logger.debug("Request is not type POST - providing empty form.")
|
logger.debug("Request is not type POST - providing empty form.")
|
||||||
|
|||||||
@@ -3,8 +3,10 @@ import logging
|
|||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.contrib.auth.decorators import login_required, permission_required
|
from django.contrib.auth.decorators import login_required, permission_required
|
||||||
from django.shortcuts import render, redirect
|
from django.shortcuts import render, redirect
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
from allianceauth.services.forms import ServicePasswordForm
|
from allianceauth.services.forms import ServicePasswordForm
|
||||||
|
|
||||||
from .manager import Phpbb3Manager
|
from .manager import Phpbb3Manager
|
||||||
from .models import Phpbb3User
|
from .models import Phpbb3User
|
||||||
from .tasks import Phpbb3Tasks
|
from .tasks import Phpbb3Tasks
|
||||||
@@ -29,7 +31,7 @@ def activate_forum(request):
|
|||||||
logger.debug("Updated authserviceinfo for user %s with forum credentials. Updating groups." % request.user)
|
logger.debug("Updated authserviceinfo for user %s with forum credentials. Updating groups." % request.user)
|
||||||
Phpbb3Tasks.update_groups.delay(request.user.pk)
|
Phpbb3Tasks.update_groups.delay(request.user.pk)
|
||||||
logger.info("Successfully activated forum for user %s" % request.user)
|
logger.info("Successfully activated forum for user %s" % request.user)
|
||||||
messages.success(request, 'Activated forum account.')
|
messages.success(request, _('Activated forum account.'))
|
||||||
credentials = {
|
credentials = {
|
||||||
'username': result[0],
|
'username': result[0],
|
||||||
'password': result[1],
|
'password': result[1],
|
||||||
@@ -38,7 +40,7 @@ def activate_forum(request):
|
|||||||
context={'credentials': credentials, 'service': 'Forum'})
|
context={'credentials': credentials, 'service': 'Forum'})
|
||||||
else:
|
else:
|
||||||
logger.error("Unsuccessful attempt to activate forum for user %s" % request.user)
|
logger.error("Unsuccessful attempt to activate forum for user %s" % request.user)
|
||||||
messages.error(request, 'An error occurred while processing your forum account.')
|
messages.error(request, _('An error occurred while processing your forum account.'))
|
||||||
return redirect("services:services")
|
return redirect("services:services")
|
||||||
|
|
||||||
|
|
||||||
@@ -49,10 +51,10 @@ def deactivate_forum(request):
|
|||||||
# false we failed
|
# false we failed
|
||||||
if Phpbb3Tasks.delete_user(request.user):
|
if Phpbb3Tasks.delete_user(request.user):
|
||||||
logger.info("Successfully deactivated forum for user %s" % request.user)
|
logger.info("Successfully deactivated forum for user %s" % request.user)
|
||||||
messages.success(request, 'Deactivated forum account.')
|
messages.success(request, _('Deactivated forum account.'))
|
||||||
else:
|
else:
|
||||||
logger.error("Unsuccessful attempt to activate forum for user %s" % request.user)
|
logger.error("Unsuccessful attempt to activate forum for user %s" % request.user)
|
||||||
messages.error(request, 'An error occurred while processing your forum account.')
|
messages.error(request, _('An error occurred while processing your forum account.'))
|
||||||
return redirect("services:services")
|
return redirect("services:services")
|
||||||
|
|
||||||
|
|
||||||
@@ -66,7 +68,7 @@ def reset_forum_password(request):
|
|||||||
# false we failed
|
# false we failed
|
||||||
if result != "":
|
if result != "":
|
||||||
logger.info("Successfully reset forum password for user %s" % request.user)
|
logger.info("Successfully reset forum password for user %s" % request.user)
|
||||||
messages.success(request, 'Reset forum password.')
|
messages.success(request, _('Reset forum password.'))
|
||||||
credentials = {
|
credentials = {
|
||||||
'username': request.user.phpbb3.username,
|
'username': request.user.phpbb3.username,
|
||||||
'password': result,
|
'password': result,
|
||||||
@@ -75,7 +77,7 @@ def reset_forum_password(request):
|
|||||||
context={'credentials': credentials, 'service': 'Forum'})
|
context={'credentials': credentials, 'service': 'Forum'})
|
||||||
|
|
||||||
logger.error("Unsuccessful attempt to reset forum password for user %s" % request.user)
|
logger.error("Unsuccessful attempt to reset forum password for user %s" % request.user)
|
||||||
messages.error(request, 'An error occurred while processing your forum account.')
|
messages.error(request, _('An error occurred while processing your forum account.'))
|
||||||
return redirect("services:services")
|
return redirect("services:services")
|
||||||
|
|
||||||
|
|
||||||
@@ -95,10 +97,10 @@ def set_forum_password(request):
|
|||||||
password=password)
|
password=password)
|
||||||
if result != "":
|
if result != "":
|
||||||
logger.info("Successfully set forum password for user %s" % request.user)
|
logger.info("Successfully set forum password for user %s" % request.user)
|
||||||
messages.success(request, 'Set forum password.')
|
messages.success(request, _('Set forum password.'))
|
||||||
else:
|
else:
|
||||||
logger.error("Failed to install custom forum password for user %s" % request.user)
|
logger.error("Failed to install custom forum password for user %s" % request.user)
|
||||||
messages.error(request, 'An error occurred while processing your forum account.')
|
messages.error(request, _('An error occurred while processing your forum account.'))
|
||||||
return redirect("services:services")
|
return redirect("services:services")
|
||||||
else:
|
else:
|
||||||
logger.debug("Request is not type POST - providing empty form.")
|
logger.debug("Request is not type POST - providing empty form.")
|
||||||
|
|||||||
@@ -3,8 +3,10 @@ import logging
|
|||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.contrib.auth.decorators import login_required, permission_required
|
from django.contrib.auth.decorators import login_required, permission_required
|
||||||
from django.shortcuts import render, redirect
|
from django.shortcuts import render, redirect
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
from allianceauth.services.forms import ServicePasswordForm
|
from allianceauth.services.forms import ServicePasswordForm
|
||||||
|
|
||||||
from .manager import SmfManager
|
from .manager import SmfManager
|
||||||
from .models import SmfUser
|
from .models import SmfUser
|
||||||
from .tasks import SmfTasks
|
from .tasks import SmfTasks
|
||||||
@@ -29,7 +31,7 @@ def activate_smf(request):
|
|||||||
logger.debug("Updated authserviceinfo for user %s with smf credentials. Updating groups." % request.user)
|
logger.debug("Updated authserviceinfo for user %s with smf credentials. Updating groups." % request.user)
|
||||||
SmfTasks.update_groups.delay(request.user.pk)
|
SmfTasks.update_groups.delay(request.user.pk)
|
||||||
logger.info("Successfully activated smf for user %s" % request.user)
|
logger.info("Successfully activated smf for user %s" % request.user)
|
||||||
messages.success(request, 'Activated SMF account.')
|
messages.success(request, _('Activated SMF account.'))
|
||||||
credentials = {
|
credentials = {
|
||||||
'username': result[0],
|
'username': result[0],
|
||||||
'password': result[1],
|
'password': result[1],
|
||||||
@@ -38,7 +40,7 @@ def activate_smf(request):
|
|||||||
context={'credentials': credentials, 'service': 'SMF'})
|
context={'credentials': credentials, 'service': 'SMF'})
|
||||||
else:
|
else:
|
||||||
logger.error("Unsuccessful attempt to activate smf for user %s" % request.user)
|
logger.error("Unsuccessful attempt to activate smf for user %s" % request.user)
|
||||||
messages.error(request, 'An error occurred while processing your SMF account.')
|
messages.error(request, _('An error occurred while processing your SMF account.'))
|
||||||
return redirect("services:services")
|
return redirect("services:services")
|
||||||
|
|
||||||
|
|
||||||
@@ -50,10 +52,10 @@ def deactivate_smf(request):
|
|||||||
# false we failed
|
# false we failed
|
||||||
if result:
|
if result:
|
||||||
logger.info("Successfully deactivated smf for user %s" % request.user)
|
logger.info("Successfully deactivated smf for user %s" % request.user)
|
||||||
messages.success(request, 'Deactivated SMF account.')
|
messages.success(request, _('Deactivated SMF account.'))
|
||||||
else:
|
else:
|
||||||
logger.error("Unsuccessful attempt to activate smf for user %s" % request.user)
|
logger.error("Unsuccessful attempt to activate smf for user %s" % request.user)
|
||||||
messages.error(request, 'An error occurred while processing your SMF account.')
|
messages.error(request, _('An error occurred while processing your SMF account.'))
|
||||||
return redirect("services:services")
|
return redirect("services:services")
|
||||||
|
|
||||||
|
|
||||||
@@ -67,7 +69,7 @@ def reset_smf_password(request):
|
|||||||
# false we failed
|
# false we failed
|
||||||
if result != "":
|
if result != "":
|
||||||
logger.info("Successfully reset smf password for user %s" % request.user)
|
logger.info("Successfully reset smf password for user %s" % request.user)
|
||||||
messages.success(request, 'Reset SMF password.')
|
messages.success(request, _('Reset SMF password.'))
|
||||||
credentials = {
|
credentials = {
|
||||||
'username': request.user.smf.username,
|
'username': request.user.smf.username,
|
||||||
'password': result,
|
'password': result,
|
||||||
@@ -75,7 +77,7 @@ def reset_smf_password(request):
|
|||||||
return render(request, 'services/service_credentials.html',
|
return render(request, 'services/service_credentials.html',
|
||||||
context={'credentials': credentials, 'service': 'SMF'})
|
context={'credentials': credentials, 'service': 'SMF'})
|
||||||
logger.error("Unsuccessful attempt to reset smf password for user %s" % request.user)
|
logger.error("Unsuccessful attempt to reset smf password for user %s" % request.user)
|
||||||
messages.error(request, 'An error occurred while processing your SMF account.')
|
messages.error(request, _('An error occurred while processing your SMF account.'))
|
||||||
return redirect("services:services")
|
return redirect("services:services")
|
||||||
|
|
||||||
|
|
||||||
@@ -95,10 +97,10 @@ def set_smf_password(request):
|
|||||||
password=password)
|
password=password)
|
||||||
if result != "":
|
if result != "":
|
||||||
logger.info("Successfully set smf password for user %s" % request.user)
|
logger.info("Successfully set smf password for user %s" % request.user)
|
||||||
messages.success(request, 'Set SMF password.')
|
messages.success(request, _('Set SMF password.'))
|
||||||
else:
|
else:
|
||||||
logger.error("Failed to install custom smf password for user %s" % request.user)
|
logger.error("Failed to install custom smf password for user %s" % request.user)
|
||||||
messages.error(request, 'An error occurred while processing your SMF account.')
|
messages.error(request, _('An error occurred while processing your SMF account.'))
|
||||||
return redirect("services:services")
|
return redirect("services:services")
|
||||||
else:
|
else:
|
||||||
logger.debug("Request is not type POST - providing empty form.")
|
logger.debug("Request is not type POST - providing empty form.")
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ class Teamspeak3UserAdmin(ServicesUserAdmin):
|
|||||||
'uid',
|
'uid',
|
||||||
'perm_key'
|
'perm_key'
|
||||||
)
|
)
|
||||||
|
search_fields = ServicesUserAdmin.search_fields + ('uid', )
|
||||||
|
|
||||||
|
|
||||||
@admin.register(AuthTS)
|
@admin.register(AuthTS)
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ from django.contrib import messages
|
|||||||
from django.contrib.auth.decorators import login_required, permission_required
|
from django.contrib.auth.decorators import login_required, permission_required
|
||||||
from django.shortcuts import render, redirect
|
from django.shortcuts import render, redirect
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
from .manager import Teamspeak3Manager
|
from .manager import Teamspeak3Manager
|
||||||
from .forms import TeamspeakJoinForm
|
from .forms import TeamspeakJoinForm
|
||||||
from .models import Teamspeak3User
|
from .models import Teamspeak3User
|
||||||
@@ -29,10 +31,10 @@ def activate_teamspeak3(request):
|
|||||||
Teamspeak3User.objects.update_or_create(user=request.user, defaults={'uid': result[0], 'perm_key': result[1]})
|
Teamspeak3User.objects.update_or_create(user=request.user, defaults={'uid': result[0], 'perm_key': result[1]})
|
||||||
logger.debug("Updated authserviceinfo for user %s with TS3 credentials. Updating groups." % request.user)
|
logger.debug("Updated authserviceinfo for user %s with TS3 credentials. Updating groups." % request.user)
|
||||||
logger.info("Successfully activated TS3 for user %s" % request.user)
|
logger.info("Successfully activated TS3 for user %s" % request.user)
|
||||||
messages.success(request, 'Activated TeamSpeak3 account.')
|
messages.success(request, _('Activated TeamSpeak3 account.'))
|
||||||
return redirect("teamspeak3:verify")
|
return redirect("teamspeak3:verify")
|
||||||
logger.error("Unsuccessful attempt to activate TS3 for user %s" % request.user)
|
logger.error("Unsuccessful attempt to activate TS3 for user %s" % request.user)
|
||||||
messages.error(request, 'An error occurred while processing your TeamSpeak3 account.')
|
messages.error(request, _('An error occurred while processing your TeamSpeak3 account.'))
|
||||||
return redirect("services:services")
|
return redirect("services:services")
|
||||||
|
|
||||||
|
|
||||||
@@ -66,10 +68,10 @@ def deactivate_teamspeak3(request):
|
|||||||
logger.debug("deactivate_teamspeak3 called by user %s" % request.user)
|
logger.debug("deactivate_teamspeak3 called by user %s" % request.user)
|
||||||
if Teamspeak3Tasks.has_account(request.user) and Teamspeak3Tasks.delete_user(request.user):
|
if Teamspeak3Tasks.has_account(request.user) and Teamspeak3Tasks.delete_user(request.user):
|
||||||
logger.info("Successfully deactivated TS3 for user %s" % request.user)
|
logger.info("Successfully deactivated TS3 for user %s" % request.user)
|
||||||
messages.success(request, 'Deactivated TeamSpeak3 account.')
|
messages.success(request, _('Deactivated TeamSpeak3 account.'))
|
||||||
else:
|
else:
|
||||||
logger.error("Unsuccessful attempt to deactivate TS3 for user %s" % request.user)
|
logger.error("Unsuccessful attempt to deactivate TS3 for user %s" % request.user)
|
||||||
messages.error(request, 'An error occurred while processing your TeamSpeak3 account.')
|
messages.error(request, _('An error occurred while processing your TeamSpeak3 account.'))
|
||||||
return redirect("services:services")
|
return redirect("services:services")
|
||||||
|
|
||||||
|
|
||||||
@@ -92,8 +94,8 @@ def reset_teamspeak3_perm(request):
|
|||||||
logger.debug("Updated authserviceinfo for user %s with TS3 credentials. Updating groups." % request.user)
|
logger.debug("Updated authserviceinfo for user %s with TS3 credentials. Updating groups." % request.user)
|
||||||
Teamspeak3Tasks.update_groups.delay(request.user.pk)
|
Teamspeak3Tasks.update_groups.delay(request.user.pk)
|
||||||
logger.info("Successfully reset TS3 permission key for user %s" % request.user)
|
logger.info("Successfully reset TS3 permission key for user %s" % request.user)
|
||||||
messages.success(request, 'Reset TeamSpeak3 permission key.')
|
messages.success(request, _('Reset TeamSpeak3 permission key.'))
|
||||||
else:
|
else:
|
||||||
logger.error("Unsuccessful attempt to reset TS3 permission key for user %s" % request.user)
|
logger.error("Unsuccessful attempt to reset TS3 permission key for user %s" % request.user)
|
||||||
messages.error(request, 'An error occurred while processing your TeamSpeak3 account.')
|
messages.error(request, _('An error occurred while processing your TeamSpeak3 account.'))
|
||||||
return redirect("services:services")
|
return redirect("services:services")
|
||||||
|
|||||||
@@ -3,8 +3,10 @@ import logging
|
|||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.contrib.auth.decorators import login_required, permission_required
|
from django.contrib.auth.decorators import login_required, permission_required
|
||||||
from django.shortcuts import render, redirect
|
from django.shortcuts import render, redirect
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
from allianceauth.services.forms import ServicePasswordForm
|
from allianceauth.services.forms import ServicePasswordForm
|
||||||
|
|
||||||
from .manager import XenForoManager
|
from .manager import XenForoManager
|
||||||
from .models import XenforoUser
|
from .models import XenforoUser
|
||||||
from .tasks import XenforoTasks
|
from .tasks import XenforoTasks
|
||||||
@@ -25,7 +27,7 @@ def activate_xenforo_forum(request):
|
|||||||
if result['response']['status_code'] == 200:
|
if result['response']['status_code'] == 200:
|
||||||
XenforoUser.objects.update_or_create(user=request.user, defaults={'username': result['username']})
|
XenforoUser.objects.update_or_create(user=request.user, defaults={'username': result['username']})
|
||||||
logger.info("Updated user %s with XenForo credentials. Updating groups." % request.user)
|
logger.info("Updated user %s with XenForo credentials. Updating groups." % request.user)
|
||||||
messages.success(request, 'Activated XenForo account.')
|
messages.success(request, _('Activated XenForo account.'))
|
||||||
credentials = {
|
credentials = {
|
||||||
'username': result['username'],
|
'username': result['username'],
|
||||||
'password': result['password'],
|
'password': result['password'],
|
||||||
@@ -35,7 +37,7 @@ def activate_xenforo_forum(request):
|
|||||||
|
|
||||||
else:
|
else:
|
||||||
logger.error("Unsuccessful attempt to activate xenforo for user %s" % request.user)
|
logger.error("Unsuccessful attempt to activate xenforo for user %s" % request.user)
|
||||||
messages.error(request, 'An error occurred while processing your XenForo account.')
|
messages.error(request, _('An error occurred while processing your XenForo account.'))
|
||||||
return redirect("services:services")
|
return redirect("services:services")
|
||||||
|
|
||||||
|
|
||||||
@@ -45,9 +47,9 @@ def deactivate_xenforo_forum(request):
|
|||||||
logger.debug("deactivate_xenforo_forum called by user %s" % request.user)
|
logger.debug("deactivate_xenforo_forum called by user %s" % request.user)
|
||||||
if XenforoTasks.delete_user(request.user):
|
if XenforoTasks.delete_user(request.user):
|
||||||
logger.info("Successfully deactivated XenForo for user %s" % request.user)
|
logger.info("Successfully deactivated XenForo for user %s" % request.user)
|
||||||
messages.success(request, 'Deactivated XenForo account.')
|
messages.success(request, _('Deactivated XenForo account.'))
|
||||||
else:
|
else:
|
||||||
messages.error(request, 'An error occurred while processing your XenForo account.')
|
messages.error(request, _('An error occurred while processing your XenForo account.'))
|
||||||
return redirect("services:services")
|
return redirect("services:services")
|
||||||
|
|
||||||
|
|
||||||
@@ -60,7 +62,7 @@ def reset_xenforo_password(request):
|
|||||||
# Based on XenAPI's response codes
|
# Based on XenAPI's response codes
|
||||||
if result['response']['status_code'] == 200:
|
if result['response']['status_code'] == 200:
|
||||||
logger.info("Successfully reset XenForo password for user %s" % request.user)
|
logger.info("Successfully reset XenForo password for user %s" % request.user)
|
||||||
messages.success(request, 'Reset XenForo account password.')
|
messages.success(request, _('Reset XenForo account password.'))
|
||||||
credentials = {
|
credentials = {
|
||||||
'username': request.user.xenforo.username,
|
'username': request.user.xenforo.username,
|
||||||
'password': result['password'],
|
'password': result['password'],
|
||||||
@@ -68,7 +70,7 @@ def reset_xenforo_password(request):
|
|||||||
return render(request, 'services/service_credentials.html',
|
return render(request, 'services/service_credentials.html',
|
||||||
context={'credentials': credentials, 'service': 'XenForo'})
|
context={'credentials': credentials, 'service': 'XenForo'})
|
||||||
logger.error("Unsuccessful attempt to reset XenForo password for user %s" % request.user)
|
logger.error("Unsuccessful attempt to reset XenForo password for user %s" % request.user)
|
||||||
messages.error(request, 'An error occurred while processing your XenForo account.')
|
messages.error(request, _('An error occurred while processing your XenForo account.'))
|
||||||
return redirect("services:services")
|
return redirect("services:services")
|
||||||
|
|
||||||
|
|
||||||
@@ -86,10 +88,10 @@ def set_xenforo_password(request):
|
|||||||
result = XenForoManager.update_user_password(request.user.xenforo.username, password)
|
result = XenForoManager.update_user_password(request.user.xenforo.username, password)
|
||||||
if result['response']['status_code'] == 200:
|
if result['response']['status_code'] == 200:
|
||||||
logger.info("Successfully reset XenForo password for user %s" % request.user)
|
logger.info("Successfully reset XenForo password for user %s" % request.user)
|
||||||
messages.success(request, 'Changed XenForo password.')
|
messages.success(request, _('Changed XenForo password.'))
|
||||||
else:
|
else:
|
||||||
logger.error("Failed to install custom XenForo password for user %s" % request.user)
|
logger.error("Failed to install custom XenForo password for user %s" % request.user)
|
||||||
messages.error(request, 'An error occurred while processing your XenForo account.')
|
messages.error(request, _('An error occurred while processing your XenForo account.'))
|
||||||
return redirect('services:services')
|
return redirect('services:services')
|
||||||
else:
|
else:
|
||||||
logger.debug("Request is not type POST - providing empty form.")
|
logger.debug("Request is not type POST - providing empty form.")
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{% block page_title %}
|
{% block page_title %}
|
||||||
{% blocktrans with service_name=view.service_name|title %}Delete {{ service_name }} Account?{% endblocktrans %}
|
{% blocktrans with service_name=view.service_name|title %}Delete {{ service_name }} Account?{% endblocktrans %}
|
||||||
{% endblock page_title %}
|
{% endblock page_title %}
|
||||||
@@ -18,8 +17,8 @@
|
|||||||
<form action="" method="post">
|
<form action="" method="post">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
<p>
|
<p>
|
||||||
{% blocktrans trimmed %}
|
{% blocktrans trimmed with service_name=view.service_name|title %}
|
||||||
Are you sure you want to delete your {{ view.service_name }} account {{ object }}?
|
Are you sure you want to delete your {{ service_name }} account {{ object }}?
|
||||||
{% endblocktrans %}
|
{% endblocktrans %}
|
||||||
</p>
|
</p>
|
||||||
<input class="btn btn-danger btn-block" type="submit" value="Confirm" />
|
<input class="btn btn-danger btn-block" type="submit" value="Confirm" />
|
||||||
|
|||||||
17
allianceauth/services/tests/test_models.py
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
from django.test import TestCase
|
||||||
|
from allianceauth.tests.auth_utils import AuthUtils
|
||||||
|
|
||||||
|
from ..models import NameFormatConfig
|
||||||
|
|
||||||
|
|
||||||
|
class TestNameFormatConfig(TestCase):
|
||||||
|
|
||||||
|
def test_str(self):
|
||||||
|
obj = NameFormatConfig.objects.create(
|
||||||
|
service_name='mumble',
|
||||||
|
format='{{character_name}}'
|
||||||
|
)
|
||||||
|
obj.states.add(AuthUtils.get_member_state())
|
||||||
|
obj.states.add(AuthUtils.get_guest_state())
|
||||||
|
expected = 'mumble: Member, Guest'
|
||||||
|
self.assertEqual(str(obj), expected)
|
||||||
@@ -90,10 +90,9 @@
|
|||||||
<th class="text-center">{% trans "Ship Type" %}</th>
|
<th class="text-center">{% trans "Ship Type" %}</th>
|
||||||
<th class="text-center">{% trans "Killboard Loss Amt" %}</th>
|
<th class="text-center">{% trans "Killboard Loss Amt" %}</th>
|
||||||
<th class="text-center">{% trans "SRP ISK Cost" %}
|
<th class="text-center">{% trans "SRP ISK Cost" %}
|
||||||
{% blocktrans %}<i class="glyphicon glyphicon-question-sign" rel="tooltip" title="Click value to edit
|
<i class="glyphicon glyphicon-question-sign" rel="tooltip" title="{% blocktrans trimmed %}Click value to edit
|
||||||
Enter to save&next
|
Enter to save & next
|
||||||
ESC to cancel"
|
ESC to cancel{% endblocktrans %}"id="blah"></i></th>
|
||||||
id="blah"></i></th>{% endblocktrans %}
|
|
||||||
<th class="text-center">{% trans "Post Time" %}</th>
|
<th class="text-center">{% trans "Post Time" %}</th>
|
||||||
<th class="text-center">{% trans "Status" %}</th>
|
<th class="text-center">{% trans "Status" %}</th>
|
||||||
{% if perms.auth.srp_management %}
|
{% if perms.auth.srp_management %}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ from django.contrib.humanize.templatetags.humanize import intcomma
|
|||||||
from django.http import JsonResponse, Http404
|
from django.http import JsonResponse, Http404
|
||||||
from django.shortcuts import render, redirect, get_object_or_404
|
from django.shortcuts import render, redirect, get_object_or_404
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from django.db.models import Sum
|
from django.db.models import Sum
|
||||||
from allianceauth.authentication.decorators import permissions_required
|
from allianceauth.authentication.decorators import permissions_required
|
||||||
from allianceauth.eveonline.providers import provider
|
from allianceauth.eveonline.providers import provider
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
[ZoneTransfer]
|
|
||||||
ZoneId=3
|
|
||||||
ReferrerUrl=https://github.com/ErikKalkoken/filterDropDown/blob/master/js/filterDropDown.min.js
|
|
||||||
HostUrl=https://raw.githubusercontent.com/ErikKalkoken/filterDropDown/master/js/filterDropDown.min.js
|
|
||||||
@@ -89,7 +89,7 @@
|
|||||||
{% if task_queue_length < 0 %}
|
{% if task_queue_length < 0 %}
|
||||||
{% trans "Error retrieving task queue length" %}
|
{% trans "Error retrieving task queue length" %}
|
||||||
{% else %}
|
{% else %}
|
||||||
{% blocktrans count tasks=task_queue_length %}
|
{% blocktrans trimmed count tasks=task_queue_length %}
|
||||||
{{ tasks }} task
|
{{ tasks }} task
|
||||||
{% plural %}
|
{% plural %}
|
||||||
{{ tasks }} tasks
|
{{ tasks }} tasks
|
||||||
|
|||||||
@@ -1,27 +1,45 @@
|
|||||||
from allianceauth.authentication.models import UserProfile, State, get_guest_state
|
from django.contrib.auth.models import User, Group, Permission
|
||||||
from allianceauth.authentication.signals import state_member_alliances_changed, state_member_characters_changed, \
|
|
||||||
state_member_corporations_changed, state_saved
|
|
||||||
from django.contrib.auth.models import User, Group
|
|
||||||
from django.db.models.signals import m2m_changed, pre_save, post_save
|
from django.db.models.signals import m2m_changed, pre_save, post_save
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
from esi.models import Token
|
|
||||||
from allianceauth.eveonline.models import EveCharacter
|
|
||||||
|
|
||||||
from allianceauth.services.signals import m2m_changed_group_permissions, m2m_changed_user_permissions, \
|
from esi.models import Token
|
||||||
m2m_changed_state_permissions
|
|
||||||
from allianceauth.services.signals import m2m_changed_user_groups, disable_services_on_inactive
|
from allianceauth.authentication.models import (
|
||||||
|
UserProfile, State, get_guest_state
|
||||||
|
)
|
||||||
|
from allianceauth.eveonline.models import EveCharacter
|
||||||
|
from allianceauth.authentication.signals import (
|
||||||
|
state_member_alliances_changed,
|
||||||
|
state_member_characters_changed,
|
||||||
|
state_member_corporations_changed,
|
||||||
|
state_saved,
|
||||||
|
reassess_on_profile_save,
|
||||||
|
assign_state_on_active_change,
|
||||||
|
check_state_on_character_update
|
||||||
|
)
|
||||||
|
from allianceauth.services.signals import (
|
||||||
|
m2m_changed_group_permissions,
|
||||||
|
m2m_changed_user_permissions,
|
||||||
|
m2m_changed_state_permissions,
|
||||||
|
m2m_changed_user_groups, disable_services_on_inactive
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class AuthUtils:
|
class AuthUtils:
|
||||||
def __init__(self):
|
"""Utilities for making it easier to create tests for Alliance Auth"""
|
||||||
pass
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _create_user(username):
|
def _create_user(username):
|
||||||
return User.objects.create(username=username)
|
return User.objects.create(username=username)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def create_user(cls, username, disconnect_signals=False):
|
def create_user(cls, username, disconnect_signals=False):
|
||||||
|
"""create a new user
|
||||||
|
|
||||||
|
username: Name of the user
|
||||||
|
|
||||||
|
disconnect_signals: whether to run process without signals
|
||||||
|
"""
|
||||||
if disconnect_signals:
|
if disconnect_signals:
|
||||||
cls.disconnect_signals()
|
cls.disconnect_signals()
|
||||||
user = cls._create_user(username)
|
user = cls._create_user(username)
|
||||||
@@ -95,6 +113,11 @@ class AuthUtils:
|
|||||||
m2m_changed.disconnect(state_member_characters_changed, sender=State.member_characters.through)
|
m2m_changed.disconnect(state_member_characters_changed, sender=State.member_characters.through)
|
||||||
m2m_changed.disconnect(state_member_alliances_changed, sender=State.member_alliances.through)
|
m2m_changed.disconnect(state_member_alliances_changed, sender=State.member_alliances.through)
|
||||||
post_save.disconnect(state_saved, sender=State)
|
post_save.disconnect(state_saved, sender=State)
|
||||||
|
post_save.disconnect(reassess_on_profile_save, sender=UserProfile)
|
||||||
|
pre_save.disconnect(assign_state_on_active_change, sender=User)
|
||||||
|
post_save.disconnect(
|
||||||
|
check_state_on_character_update, sender=EveCharacter
|
||||||
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def connect_signals(cls):
|
def connect_signals(cls):
|
||||||
@@ -107,6 +130,9 @@ class AuthUtils:
|
|||||||
m2m_changed.connect(state_member_characters_changed, sender=State.member_characters.through)
|
m2m_changed.connect(state_member_characters_changed, sender=State.member_characters.through)
|
||||||
m2m_changed.connect(state_member_alliances_changed, sender=State.member_alliances.through)
|
m2m_changed.connect(state_member_alliances_changed, sender=State.member_alliances.through)
|
||||||
post_save.connect(state_saved, sender=State)
|
post_save.connect(state_saved, sender=State)
|
||||||
|
post_save.connect(reassess_on_profile_save, sender=UserProfile)
|
||||||
|
pre_save.connect(assign_state_on_active_change, sender=User)
|
||||||
|
post_save.connect(check_state_on_character_update, sender=EveCharacter)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def add_main_character(cls, user, name, character_id, corp_id='', corp_name='', corp_ticker='', alliance_id='',
|
def add_main_character(cls, user, name, character_id, corp_id='', corp_name='', corp_ticker='', alliance_id='',
|
||||||
@@ -122,6 +148,40 @@ class AuthUtils:
|
|||||||
)
|
)
|
||||||
UserProfile.objects.update_or_create(user=user, defaults={'main_character': char})
|
UserProfile.objects.update_or_create(user=user, defaults={'main_character': char})
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def add_main_character_2(
|
||||||
|
cls,
|
||||||
|
user,
|
||||||
|
name,
|
||||||
|
character_id,
|
||||||
|
corp_id='',
|
||||||
|
corp_name='',
|
||||||
|
corp_ticker='',
|
||||||
|
alliance_id='',
|
||||||
|
alliance_name='',
|
||||||
|
disconnect_signals=False
|
||||||
|
):
|
||||||
|
"""new version that works in all cases"""
|
||||||
|
if disconnect_signals:
|
||||||
|
cls.disconnect_signals()
|
||||||
|
|
||||||
|
char = EveCharacter.objects.create(
|
||||||
|
character_id=character_id,
|
||||||
|
character_name=name,
|
||||||
|
corporation_id=corp_id,
|
||||||
|
corporation_name=corp_name,
|
||||||
|
corporation_ticker=corp_ticker,
|
||||||
|
alliance_id=alliance_id,
|
||||||
|
alliance_name=alliance_name,
|
||||||
|
)
|
||||||
|
user.profile.main_character = char
|
||||||
|
user.profile.save()
|
||||||
|
|
||||||
|
if disconnect_signals:
|
||||||
|
cls.connect_signals()
|
||||||
|
|
||||||
|
return char
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def add_permissions_to_groups(cls, perms, groups, disconnect_signals=True):
|
def add_permissions_to_groups(cls, perms, groups, disconnect_signals=True):
|
||||||
if disconnect_signals:
|
if disconnect_signals:
|
||||||
@@ -130,14 +190,67 @@ class AuthUtils:
|
|||||||
for group in groups:
|
for group in groups:
|
||||||
for perm in perms:
|
for perm in perms:
|
||||||
group.permissions.add(perm)
|
group.permissions.add(perm)
|
||||||
|
group = Group.objects.get(pk=group.pk) # reload permission cache
|
||||||
|
|
||||||
if disconnect_signals:
|
if disconnect_signals:
|
||||||
cls.connect_signals()
|
cls.connect_signals()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def add_permissions_to_state(cls, perms, states, disconnect_signals=True):
|
def add_permissions_to_state(cls, perms, states, disconnect_signals=True):
|
||||||
return cls.add_permissions_to_groups(perms, states, disconnect_signals=disconnect_signals)
|
return cls.add_permissions_to_groups(
|
||||||
|
perms, states, disconnect_signals=disconnect_signals
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def add_permissions_to_user(cls, perms, user, disconnect_signals=True):
|
||||||
|
"""add list of permissions to user
|
||||||
|
|
||||||
|
perms: list of Permission objects
|
||||||
|
|
||||||
|
user: user object
|
||||||
|
|
||||||
|
disconnect_signals: whether to run process without signals
|
||||||
|
"""
|
||||||
|
if disconnect_signals:
|
||||||
|
cls.disconnect_signals()
|
||||||
|
|
||||||
|
for perm in perms:
|
||||||
|
user.user_permissions.add(perm)
|
||||||
|
|
||||||
|
user = User.objects.get(pk=user.pk) # reload permission cache
|
||||||
|
if disconnect_signals:
|
||||||
|
cls.connect_signals()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def add_permission_to_user_by_name(
|
||||||
|
cls, perm, user, disconnect_signals=True
|
||||||
|
):
|
||||||
|
"""returns permission specified by qualified name
|
||||||
|
|
||||||
|
perm: Permission name as 'app_label.codename'
|
||||||
|
|
||||||
|
user: user object
|
||||||
|
|
||||||
|
disconnect_signals: whether to run process without signals
|
||||||
|
"""
|
||||||
|
p = cls.get_permission_by_name(perm)
|
||||||
|
cls.add_permissions_to_user([p], user, disconnect_signals)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_permission_by_name(perm: str) -> Permission:
|
||||||
|
"""returns permission specified by qualified name
|
||||||
|
|
||||||
|
perm: Permission name as 'app_label.codename'
|
||||||
|
|
||||||
|
Returns: Permission object or throws exception if not found
|
||||||
|
"""
|
||||||
|
perm_parts = perm.split('.')
|
||||||
|
if len(perm_parts) != 2:
|
||||||
|
raise ValueError('Invalid format for permission name')
|
||||||
|
|
||||||
|
return Permission.objects.get(
|
||||||
|
content_type__app_label=perm_parts[0], codename=perm_parts[1]
|
||||||
|
)
|
||||||
|
|
||||||
class BaseViewTestCase(TestCase):
|
class BaseViewTestCase(TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
|||||||
60
allianceauth/tests/test_auth_utils.py
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
from unittest import mock
|
||||||
|
|
||||||
|
from django.contrib.auth.models import User, Group, Permission
|
||||||
|
from django.test import TestCase
|
||||||
|
|
||||||
|
from allianceauth.eveonline.models import (
|
||||||
|
EveCorporationInfo, EveAllianceInfo, EveCharacter
|
||||||
|
)
|
||||||
|
|
||||||
|
from .auth_utils import AuthUtils
|
||||||
|
|
||||||
|
|
||||||
|
class TestAuthUtils(TestCase):
|
||||||
|
|
||||||
|
def test_can_create_user(self):
|
||||||
|
user = AuthUtils.create_user('Bruce Wayne')
|
||||||
|
self.assertTrue(User.objects.filter(username='Bruce Wayne').exists())
|
||||||
|
|
||||||
|
def test_can_add_main_character_2(self):
|
||||||
|
user = AuthUtils.create_user('Bruce Wayne')
|
||||||
|
character = AuthUtils.add_main_character_2(
|
||||||
|
user,
|
||||||
|
name='Bruce Wayne',
|
||||||
|
character_id=1001,
|
||||||
|
corp_id=2001,
|
||||||
|
corp_name='Wayne Technologies',
|
||||||
|
corp_ticker='WYT',
|
||||||
|
alliance_id=3001,
|
||||||
|
alliance_name='Wayne Enterprises'
|
||||||
|
)
|
||||||
|
expected = character
|
||||||
|
self.assertEqual(user.profile.main_character, expected)
|
||||||
|
|
||||||
|
def test_can_add_permission_to_group(self):
|
||||||
|
group = Group.objects.create(name='Dummy Group')
|
||||||
|
p = AuthUtils.get_permission_by_name('auth.group_management')
|
||||||
|
AuthUtils.add_permissions_to_groups([p], [group])
|
||||||
|
self.assertTrue(group.permissions.filter(pk=p.pk).exists())
|
||||||
|
|
||||||
|
def test_can_add_permission_to_user_by_name(self):
|
||||||
|
user = AuthUtils.create_user('Bruce Wayne')
|
||||||
|
AuthUtils.add_permission_to_user_by_name(
|
||||||
|
'auth.timer_management', user
|
||||||
|
)
|
||||||
|
self.assertTrue(user.has_perm('auth.timer_management'))
|
||||||
|
|
||||||
|
|
||||||
|
class TestGetPermissionByName(TestCase):
|
||||||
|
|
||||||
|
def test_can_get_permission_by_name(self):
|
||||||
|
expected = Permission.objects.get(
|
||||||
|
content_type__app_label='auth', codename='timer_management'
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
AuthUtils.get_permission_by_name('auth.timer_management'), expected
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_raises_exception_on_invalid_permission_format(self):
|
||||||
|
with self.assertRaises(ValueError):
|
||||||
|
AuthUtils.get_permission_by_name('timer_management')
|
||||||
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 258 KiB After Width: | Height: | Size: 258 KiB |
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 4.2 KiB |
|
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 3.1 KiB |
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 903 B After Width: | Height: | Size: 903 B |
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
BIN
docs/_static/images/features/apps/fat.png
vendored
Normal file
|
After Width: | Height: | Size: 32 KiB |
BIN
docs/_static/images/features/apps/hr.png
vendored
Normal file
|
After Width: | Height: | Size: 35 KiB |
BIN
docs/_static/images/features/apps/optimer.png
vendored
Normal file
|
After Width: | Height: | Size: 42 KiB |
BIN
docs/_static/images/features/apps/permissions_tool/audit.png
vendored
Normal file
|
After Width: | Height: | Size: 99 KiB |
BIN
docs/_static/images/features/apps/permissions_tool/overview.png
vendored
Normal file
|
After Width: | Height: | Size: 63 KiB |
BIN
docs/_static/images/features/apps/srp.png
vendored
Normal file
|
After Width: | Height: | Size: 27 KiB |
BIN
docs/_static/images/features/apps/timerboard.png
vendored
Normal file
|
After Width: | Height: | Size: 59 KiB |
BIN
docs/_static/images/features/core/dashboard/dashboard.png
vendored
Normal file
|
After Width: | Height: | Size: 107 KiB |
|
Before Width: | Height: | Size: 51 KiB After Width: | Height: | Size: 51 KiB |
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 36 KiB |
|
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 31 KiB |
|
Before Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 56 KiB |
@@ -54,7 +54,7 @@ master_doc = 'index'
|
|||||||
|
|
||||||
# General information about the project.
|
# General information about the project.
|
||||||
project = u'Alliance Auth'
|
project = u'Alliance Auth'
|
||||||
copyright = u'2018, Alliance Auth'
|
copyright = u'2018-2020, Alliance Auth'
|
||||||
author = u'R4stl1n'
|
author = u'R4stl1n'
|
||||||
|
|
||||||
# The version info for the project you're documenting, acts as replacement for
|
# The version info for the project you're documenting, acts as replacement for
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# Documentation
|
# Alliance Auth documentation
|
||||||
|
|
||||||
The documentation for Alliance Auth uses [Sphinx](http://www.sphinx-doc.org/) to build documentation. When a new commit
|
The documentation for Alliance Auth uses [Sphinx](http://www.sphinx-doc.org/) to build documentation. When a new commit
|
||||||
to specific branches is made (master, primarily), the repository is automatically pulled, docs built and deployed on
|
to specific branches is made (master, primarily), the repository is automatically pulled, docs built and deployed on
|
||||||
10
docs/development/aa_core/index.md
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
# Developing AA Core
|
||||||
|
|
||||||
|
This section contains important information on how to develop Alliance Auth itself.
|
||||||
|
|
||||||
|
```eval_rst
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 1
|
||||||
|
|
||||||
|
documentation
|
||||||
|
```
|
||||||