mirror of
https://gitlab.com/allianceauth/allianceauth.git
synced 2026-02-04 14:16:21 +01:00
Compare commits
71 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a75e93dbfc | ||
|
|
0aa66c5729 | ||
|
|
4c2434219d | ||
|
|
8c65fda33b | ||
|
|
14f2751bbb | ||
|
|
d37a543c39 | ||
|
|
4947e0c483 | ||
|
|
f87c630b86 | ||
|
|
73789ea734 | ||
|
|
5a16c9c495 | ||
|
|
9dd8357f67 | ||
|
|
623e77a268 | ||
|
|
73403b98df | ||
|
|
7aa1a2f336 | ||
|
|
08e42d2f56 | ||
|
|
69248fd7bb | ||
|
|
0af188c6ab | ||
|
|
8b6d32d0d1 | ||
|
|
3c11c25d69 | ||
|
|
12e6cc63e8 | ||
|
|
d429c8b59a | ||
|
|
ddd7a3551b | ||
|
|
49ede92e06 | ||
|
|
b813213328 | ||
|
|
14065b3ca9 | ||
|
|
41f9dc490a | ||
|
|
48d25ca73f | ||
|
|
e49e04034c | ||
|
|
c7860f8e5c | ||
|
|
adb982114a | ||
|
|
5b8983deac | ||
|
|
1730bc3b98 | ||
|
|
4374064d98 | ||
|
|
c1d7994045 | ||
|
|
7bda367cc8 | ||
|
|
3de7a2ccd2 | ||
|
|
9cc278df31 | ||
|
|
a0bab07e2f | ||
|
|
149bbd92ca | ||
|
|
1de3c989d7 | ||
|
|
2e547945e2 | ||
|
|
4d4a9a27af | ||
|
|
5b41d0995f | ||
|
|
ab98d72022 | ||
|
|
8a7cd3f74d | ||
|
|
35cb56d6e9 | ||
|
|
a7a2ffd16b | ||
|
|
dbeda324e0 | ||
|
|
bf1fe99d98 | ||
|
|
41429ec7c7 | ||
|
|
ee9ed13a66 | ||
|
|
490ce286ff | ||
|
|
099c2c0a21 | ||
|
|
46e15f7fa1 | ||
|
|
6677e63e08 | ||
|
|
6d6a3a3d6b | ||
|
|
5006246cf1 | ||
|
|
6187fb9b86 | ||
|
|
86f57ccd56 | ||
|
|
854096bac7 | ||
|
|
9d2b3bb157 | ||
|
|
22bda62e59 | ||
|
|
c8ad1dcc7a | ||
|
|
7212a7a328 | ||
|
|
f6b1b7b6bb | ||
|
|
53a9d72c4a | ||
|
|
ca10fbcde5 | ||
|
|
b4d33e5dfc | ||
|
|
37bed989f1 | ||
|
|
0b7520e3b1 | ||
|
|
48c8ccfe97 |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -42,7 +42,6 @@ nosetests.xml
|
|||||||
coverage.xml
|
coverage.xml
|
||||||
|
|
||||||
# Translations
|
# Translations
|
||||||
*.mo
|
|
||||||
*.pot
|
*.pot
|
||||||
|
|
||||||
# Django stuff:
|
# Django stuff:
|
||||||
@@ -63,3 +62,5 @@ celerybeat-schedule
|
|||||||
|
|
||||||
#pycharm
|
#pycharm
|
||||||
.idea/*
|
.idea/*
|
||||||
|
|
||||||
|
/nbproject/
|
||||||
|
|||||||
41
.gitlab-ci.yml
Normal file
41
.gitlab-ci.yml
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
# Official language image. Look for the different tagged releases at:
|
||||||
|
# https://hub.docker.com/r/library/python/tags/
|
||||||
|
|
||||||
|
.job_template: &job_definition
|
||||||
|
# Change pip's cache directory to be inside the project directory since we can
|
||||||
|
# only cache local items.
|
||||||
|
variables:
|
||||||
|
PIP_CACHE_DIR: "$CI_PROJECT_DIR/.cache"
|
||||||
|
|
||||||
|
# Pip's cache doesn't store the python packages
|
||||||
|
# https://pip.pypa.io/en/stable/reference/pip_install/#caching
|
||||||
|
#
|
||||||
|
# If you want to also cache the installed packages, you have to install
|
||||||
|
# them in a virtualenv and cache it as well.
|
||||||
|
cache:
|
||||||
|
paths:
|
||||||
|
- .cache/pip
|
||||||
|
- venv/
|
||||||
|
|
||||||
|
before_script:
|
||||||
|
- python -V # Print out python version for debugging
|
||||||
|
- pip install virtualenv tox
|
||||||
|
- virtualenv venv
|
||||||
|
- source venv/bin/activate
|
||||||
|
|
||||||
|
coverage: '/TOTAL.+ ([0-9]{1,3}%)/'
|
||||||
|
|
||||||
|
|
||||||
|
py36-dj111:
|
||||||
|
<<: *job_definition
|
||||||
|
image: python:3.6-stretch
|
||||||
|
script:
|
||||||
|
- export TOXENV=py36-dj111
|
||||||
|
- tox
|
||||||
|
|
||||||
|
py36-dj20:
|
||||||
|
<<: *job_definition
|
||||||
|
image: python:3.6-stretch
|
||||||
|
script:
|
||||||
|
- export TOXENV=py36-dj20
|
||||||
|
- tox
|
||||||
@@ -3,8 +3,9 @@ Alliance Auth
|
|||||||
|
|
||||||
[](https://gitter.im/R4stl1n/allianceauth?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
[](https://gitter.im/R4stl1n/allianceauth?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||||
[](http://allianceauth.readthedocs.io/?badge=latest)
|
[](http://allianceauth.readthedocs.io/?badge=latest)
|
||||||
[](https://travis-ci.org/allianceauth/allianceauth)
|
[](https://gitlab.com/allianceauth/allianceauth/commits/master)
|
||||||
[](https://coveralls.io/github/allianceauth/allianceauth?branch=master)
|
[](https://gitlab.com/allianceauth/allianceauth/commits/master)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
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.
|
||||||
|
|||||||
@@ -1,7 +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.0.0'
|
__version__ = '2.1b1'
|
||||||
NAME = 'Alliance Auth v%s' % __version__
|
NAME = 'Alliance Auth v%s' % __version__
|
||||||
default_app_config = 'allianceauth.apps.AllianceAuthConfig'
|
default_app_config = 'allianceauth.apps.AllianceAuthConfig'
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
from django.conf.urls import include
|
from django.conf.urls import include
|
||||||
|
from django.contrib.auth.decorators import user_passes_test
|
||||||
|
from django.core.exceptions import PermissionDenied
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
from django.shortcuts import redirect
|
from django.shortcuts import redirect
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
@@ -35,3 +37,32 @@ def main_character_required(view_func):
|
|||||||
messages.error(request, _('A main character is required to perform that action. Add one below.'))
|
messages.error(request, _('A main character is required to perform that action. Add one below.'))
|
||||||
return redirect('authentication:dashboard')
|
return redirect('authentication:dashboard')
|
||||||
return login_required(_wrapped_view)
|
return login_required(_wrapped_view)
|
||||||
|
|
||||||
|
|
||||||
|
def permissions_required(perm, login_url=None, raise_exception=False):
|
||||||
|
"""
|
||||||
|
Decorator for views that checks whether a user has a particular permission
|
||||||
|
enabled, redirecting to the log-in page if necessary.
|
||||||
|
If the raise_exception parameter is given the PermissionDenied exception
|
||||||
|
is raised.
|
||||||
|
|
||||||
|
This decorator is identical to the django permission_required except it
|
||||||
|
allows for passing a tuple/list of perms that will return true if any one
|
||||||
|
of them is present.
|
||||||
|
"""
|
||||||
|
def check_perms(user):
|
||||||
|
if isinstance(perm, str):
|
||||||
|
perms = (perm,)
|
||||||
|
else:
|
||||||
|
perms = perm
|
||||||
|
# First check if the user has the permission (even anon users)
|
||||||
|
for perm_ in perms:
|
||||||
|
perm_ = (perm_,)
|
||||||
|
if user.has_perms(perm_):
|
||||||
|
return True
|
||||||
|
# In case the 403 handler should be called raise the exception
|
||||||
|
if raise_exception:
|
||||||
|
raise PermissionDenied
|
||||||
|
# As the last resort, show the login form
|
||||||
|
return False
|
||||||
|
return user_passes_test(check_perms, login_url=login_url)
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ def create_member_group(apps, schema_editor):
|
|||||||
member_state_name = getattr(settings, 'DEFAULT_AUTH_GROUP', 'Member')
|
member_state_name = getattr(settings, 'DEFAULT_AUTH_GROUP', 'Member')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
g = Group.objects.get(name=member_state_name)
|
g, _ = Group.objects.get_or_create(name=member_state_name)
|
||||||
# move permissions back
|
# move permissions back
|
||||||
state = State.objects.get(name=member_state_name)
|
state = State.objects.get(name=member_state_name)
|
||||||
[g.permissions.add(p.pk) for p in state.permissions.all()]
|
[g.permissions.add(p.pk) for p in state.permissions.all()]
|
||||||
@@ -51,7 +51,7 @@ def create_member_group(apps, schema_editor):
|
|||||||
# move users back
|
# move users back
|
||||||
for profile in state.userprofile_set.all().select_related('user'):
|
for profile in state.userprofile_set.all().select_related('user'):
|
||||||
profile.user.groups.add(g.pk)
|
profile.user.groups.add(g.pk)
|
||||||
except (Group.DoesNotExist, State.DoesNotExist):
|
except State.DoesNotExist:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
@@ -67,7 +67,7 @@ def create_blue_state(apps, schema_editor):
|
|||||||
# move group permissions to state
|
# move group permissions to state
|
||||||
g = Group.objects.get(name=blue_state_name)
|
g = Group.objects.get(name=blue_state_name)
|
||||||
[s.permissions.add(p.pk) for p in g.permissions.all()]
|
[s.permissions.add(p.pk) for p in g.permissions.all()]
|
||||||
g.permissions.clear()
|
g.delete()
|
||||||
except Group.DoesNotExist:
|
except Group.DoesNotExist:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@@ -84,7 +84,7 @@ def create_blue_group(apps, schema_editor):
|
|||||||
blue_state_name = getattr(settings, 'DEFAULT_BLUE_GROUP', 'Blue')
|
blue_state_name = getattr(settings, 'DEFAULT_BLUE_GROUP', 'Blue')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
g = Group.objects.get(name=blue_state_name)
|
g, _ = Group.objects.get_or_create(name=blue_state_name)
|
||||||
# move permissions back
|
# move permissions back
|
||||||
state = State.objects.get(name=blue_state_name)
|
state = State.objects.get(name=blue_state_name)
|
||||||
[g.permissions.add(p.pk) for p in state.permissions.all()]
|
[g.permissions.add(p.pk) for p in state.permissions.all()]
|
||||||
@@ -92,7 +92,7 @@ def create_blue_group(apps, schema_editor):
|
|||||||
# move users back
|
# move users back
|
||||||
for profile in state.userprofile_set.all().select_related('user'):
|
for profile in state.userprofile_set.all().select_related('user'):
|
||||||
profile.user.groups.add(g.pk)
|
profile.user.groups.add(g.pk)
|
||||||
except (Group.DoesNotExist, State.DoesNotExist):
|
except State.DoesNotExist:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
@@ -133,15 +133,24 @@ def create_profiles(apps, schema_editor):
|
|||||||
auth['n'] == 1 and EveCharacter.objects.filter(character_id=auth['main_char_id']).exists()]
|
auth['n'] == 1 and EveCharacter.objects.filter(character_id=auth['main_char_id']).exists()]
|
||||||
|
|
||||||
auths = AuthServicesInfo.objects.filter(main_char_id__in=unique_mains).select_related('user')
|
auths = AuthServicesInfo.objects.filter(main_char_id__in=unique_mains).select_related('user')
|
||||||
|
|
||||||
|
blue_state_name = getattr(settings, 'DEFAULT_BLUE_GROUP', 'Blue')
|
||||||
|
member_state_name = getattr(settings, 'DEFAULT_AUTH_GROUP', 'Member')
|
||||||
|
|
||||||
|
states = {
|
||||||
|
'Member': State.objects.get(name=member_state_name),
|
||||||
|
'Blue': State.objects.get(name=blue_state_name),
|
||||||
|
}
|
||||||
|
guest_state = State.objects.get(name='Guest')
|
||||||
|
|
||||||
for auth in auths:
|
for auth in auths:
|
||||||
# carry states and mains forward
|
# carry states and mains forward
|
||||||
state = State.objects.get(name=auth.state if auth.state else 'Guest')
|
state = states.get(auth.state, guest_state)
|
||||||
char = EveCharacter.objects.get(character_id=auth.main_char_id)
|
char = EveCharacter.objects.get(character_id=auth.main_char_id)
|
||||||
UserProfile.objects.create(user=auth.user, state=state, main_character=char)
|
UserProfile.objects.create(user=auth.user, state=state, main_character=char)
|
||||||
for auth in AuthServicesInfo.objects.exclude(main_char_id__in=unique_mains).select_related('user'):
|
for auth in AuthServicesInfo.objects.exclude(main_char_id__in=unique_mains).select_related('user'):
|
||||||
# prepare empty profiles
|
# prepare empty profiles
|
||||||
state = State.objects.get(name='Guest')
|
UserProfile.objects.create(user=auth.user, state=guest_state)
|
||||||
UserProfile.objects.create(user=auth.user, state=state)
|
|
||||||
|
|
||||||
|
|
||||||
def recreate_authservicesinfo(apps, schema_editor):
|
def recreate_authservicesinfo(apps, schema_editor):
|
||||||
@@ -149,6 +158,14 @@ def recreate_authservicesinfo(apps, schema_editor):
|
|||||||
UserProfile = apps.get_model('authentication', 'UserProfile')
|
UserProfile = apps.get_model('authentication', 'UserProfile')
|
||||||
User = apps.get_model('auth', 'User')
|
User = apps.get_model('auth', 'User')
|
||||||
|
|
||||||
|
blue_state_name = getattr(settings, 'DEFAULT_BLUE_GROUP', 'Blue')
|
||||||
|
member_state_name = getattr(settings, 'DEFAULT_AUTH_GROUP', 'Member')
|
||||||
|
|
||||||
|
states = {
|
||||||
|
member_state_name: 'Member',
|
||||||
|
blue_state_name: 'Blue',
|
||||||
|
}
|
||||||
|
|
||||||
# recreate all missing AuthServicesInfo models
|
# recreate all missing AuthServicesInfo models
|
||||||
AuthServicesInfo.objects.bulk_create([AuthServicesInfo(user_id=u.pk) for u in User.objects.all()])
|
AuthServicesInfo.objects.bulk_create([AuthServicesInfo(user_id=u.pk) for u in User.objects.all()])
|
||||||
|
|
||||||
@@ -159,8 +176,8 @@ def recreate_authservicesinfo(apps, schema_editor):
|
|||||||
|
|
||||||
# repopulate states we understand
|
# repopulate states we understand
|
||||||
for profile in UserProfile.objects.exclude(state__name='Guest').filter(
|
for profile in UserProfile.objects.exclude(state__name='Guest').filter(
|
||||||
state__name__in=['Member', 'Blue']).select_related('user', 'state'):
|
state__name__in=[member_state_name, blue_state_name]).select_related('user', 'state'):
|
||||||
AuthServicesInfo.objects.update_or_create(user=profile.user, defaults={'state': profile.state.name})
|
AuthServicesInfo.objects.update_or_create(user=profile.user, defaults={'state': states[profile.state.name]})
|
||||||
|
|
||||||
|
|
||||||
def disable_passwords(apps, schema_editor):
|
def disable_passwords(apps, schema_editor):
|
||||||
|
|||||||
@@ -103,12 +103,16 @@ def record_character_ownership(sender, instance, created, *args, **kwargs):
|
|||||||
|
|
||||||
@receiver(pre_delete, sender=CharacterOwnership)
|
@receiver(pre_delete, sender=CharacterOwnership)
|
||||||
def validate_main_character(sender, instance, *args, **kwargs):
|
def validate_main_character(sender, instance, *args, **kwargs):
|
||||||
if instance.user.profile.main_character == instance.character:
|
try:
|
||||||
logger.info("Ownership of a main character {0} has been revoked. Resetting {1} main character.".format(
|
if instance.user.profile.main_character == instance.character:
|
||||||
instance.character, instance.user))
|
logger.info("Ownership of a main character {0} has been revoked. Resetting {1} main character.".format(
|
||||||
# clear main character as user no longer owns them
|
instance.character, instance.user))
|
||||||
instance.user.profile.main_character = None
|
# clear main character as user no longer owns them
|
||||||
instance.user.profile.save()
|
instance.user.profile.main_character = None
|
||||||
|
instance.user.profile.save()
|
||||||
|
except UserProfile.DoesNotExist:
|
||||||
|
# a user is being deleted
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
@receiver(post_delete, sender=Token)
|
@receiver(post_delete, sender=Token)
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
from allianceauth.services.hooks import MenuItemHook, UrlHook
|
from allianceauth.services.hooks import MenuItemHook, UrlHook
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from allianceauth import hooks
|
from allianceauth import hooks
|
||||||
from allianceauth.corputils import urls
|
from allianceauth.corputils import urls
|
||||||
|
|
||||||
@@ -7,7 +7,7 @@ from allianceauth.corputils import urls
|
|||||||
class CorpStats(MenuItemHook):
|
class CorpStats(MenuItemHook):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
MenuItemHook.__init__(self,
|
MenuItemHook.__init__(self,
|
||||||
'Corporation Stats',
|
_('Corporation Stats'),
|
||||||
'fa fa-share-alt fa-fw',
|
'fa fa-share-alt fa-fw',
|
||||||
'corputils:view',
|
'corputils:view',
|
||||||
navactive=['corputils:'])
|
navactive=['corputils:'])
|
||||||
|
|||||||
@@ -12,6 +12,16 @@ from allianceauth.notifications import notify
|
|||||||
from allianceauth.corputils.managers import CorpStatsManager
|
from allianceauth.corputils.managers import CorpStatsManager
|
||||||
|
|
||||||
SWAGGER_SPEC_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'swagger.json')
|
SWAGGER_SPEC_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'swagger.json')
|
||||||
|
"""
|
||||||
|
Swagger spec operations:
|
||||||
|
|
||||||
|
Character
|
||||||
|
get_characters_character_id
|
||||||
|
get_corporations_corporation_id_members
|
||||||
|
Universe
|
||||||
|
post_universe_names
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@@ -47,11 +57,11 @@ class CorpStats(models.Model):
|
|||||||
# the swagger spec doesn't have a maxItems count
|
# the swagger spec doesn't have a maxItems count
|
||||||
# manual testing says we can do over 350, but let's not risk it
|
# manual testing says we can do over 350, but let's not risk it
|
||||||
member_id_chunks = [member_ids[i:i + 255] for i in range(0, len(member_ids), 255)]
|
member_id_chunks = [member_ids[i:i + 255] for i in range(0, len(member_ids), 255)]
|
||||||
member_name_chunks = [c.Character.get_characters_names(character_ids=id_chunk).result() for id_chunk in
|
member_name_chunks = [c.Universe.post_universe_names(ids=id_chunk).result() for id_chunk in
|
||||||
member_id_chunks]
|
member_id_chunks]
|
||||||
member_list = {}
|
member_list = {}
|
||||||
for name_chunk in member_name_chunks:
|
for name_chunk in member_name_chunks:
|
||||||
member_list.update({m['character_id']: m['character_name'] for m in name_chunk})
|
member_list.update({m['id']: m['name'] for m in name_chunk})
|
||||||
|
|
||||||
# bulk create new member models
|
# bulk create new member models
|
||||||
missing_members = [m_id for m_id in member_ids if
|
missing_members = [m_id for m_id in member_ids if
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -11,7 +11,7 @@
|
|||||||
{% if corpstats.corp.alliance %}{% else %}col-lg-offset-3{% endif %}"><img
|
{% if corpstats.corp.alliance %}{% else %}col-lg-offset-3{% endif %}"><img
|
||||||
class="ra-avatar" src="{{ corpstats.corp.logo_url_128 }}"></td>
|
class="ra-avatar" src="{{ corpstats.corp.logo_url_128 }}"></td>
|
||||||
{% if corpstats.corp.alliance %}
|
{% if corpstats.corp.alliance %}
|
||||||
<td class="text-center col-lg-6"><img class="ra-avatar" src="{{ corpstats.alliance.logo_url_128 }}">
|
<td class="text-center col-lg-6"><img class="ra-avatar" src="{{ corpstats.corp.alliance.logo_url_128 }}">
|
||||||
</td>
|
</td>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</tr>
|
</tr>
|
||||||
@@ -202,4 +202,4 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ class CorpStatsUpdateTestCase(TestCase):
|
|||||||
def test_update_add_member(self, SwaggerClient):
|
def test_update_add_member(self, SwaggerClient):
|
||||||
SwaggerClient.from_spec.return_value.Character.get_characters_character_id.return_value.result.return_value = {'corporation_id': 2}
|
SwaggerClient.from_spec.return_value.Character.get_characters_character_id.return_value.result.return_value = {'corporation_id': 2}
|
||||||
SwaggerClient.from_spec.return_value.Corporation.get_corporations_corporation_id_members.return_value.result.return_value = [1]
|
SwaggerClient.from_spec.return_value.Corporation.get_corporations_corporation_id_members.return_value.result.return_value = [1]
|
||||||
SwaggerClient.from_spec.return_value.Character.get_characters_names.return_value.result.return_value = [{'character_id': 1, 'character_name': 'test character'}]
|
SwaggerClient.from_spec.return_value.Universe.post_universe_names.return_value.result.return_value = [{'id': 1, 'name': 'test character'}]
|
||||||
self.corpstats.update()
|
self.corpstats.update()
|
||||||
self.assertTrue(CorpMember.objects.filter(character_id='1', character_name='test character', corpstats=self.corpstats).exists())
|
self.assertTrue(CorpMember.objects.filter(character_id='1', character_name='test character', corpstats=self.corpstats).exists())
|
||||||
|
|
||||||
@@ -95,7 +95,7 @@ class CorpStatsUpdateTestCase(TestCase):
|
|||||||
CorpMember.objects.create(character_id='2', character_name='old test character', corpstats=self.corpstats)
|
CorpMember.objects.create(character_id='2', character_name='old test character', corpstats=self.corpstats)
|
||||||
SwaggerClient.from_spec.return_value.Character.get_characters_character_id.return_value.result.return_value = {'corporation_id': 2}
|
SwaggerClient.from_spec.return_value.Character.get_characters_character_id.return_value.result.return_value = {'corporation_id': 2}
|
||||||
SwaggerClient.from_spec.return_value.Corporation.get_corporations_corporation_id_members.return_value.result.return_value = [1]
|
SwaggerClient.from_spec.return_value.Corporation.get_corporations_corporation_id_members.return_value.result.return_value = [1]
|
||||||
SwaggerClient.from_spec.return_value.Character.get_characters_names.return_value.result.return_value = [{'character_id': 1, 'character_name': 'test character'}]
|
SwaggerClient.from_spec.return_value.Universe.post_universe_names.return_value.result.return_value = [{'id': 1, 'name': 'test character'}]
|
||||||
self.corpstats.update()
|
self.corpstats.update()
|
||||||
self.assertFalse(CorpMember.objects.filter(character_id='2', corpstats=self.corpstats).exists())
|
self.assertFalse(CorpMember.objects.filter(character_id='2', corpstats=self.corpstats).exists())
|
||||||
|
|
||||||
|
|||||||
@@ -13,11 +13,17 @@ from allianceauth.eveonline.models import EveCharacter, EveCorporationInfo
|
|||||||
from .models import CorpStats
|
from .models import CorpStats
|
||||||
|
|
||||||
SWAGGER_SPEC_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'swagger.json')
|
SWAGGER_SPEC_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'swagger.json')
|
||||||
|
"""
|
||||||
|
Swagger spec operations:
|
||||||
|
|
||||||
|
get_characters_character_id
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
def access_corpstats_test(user):
|
def access_corpstats_test(user):
|
||||||
return user.has_perm('corputils.view_corp_corpstats') or user.has_perm(
|
return user.has_perm('corputils.view_corp_corpstats') or user.has_perm(
|
||||||
'corputils.view_alliance_corpstats') or user.has_perm('corputils.view_state_corpstats')
|
'corputils.view_alliance_corpstats') or user.has_perm('corputils.view_state_corpstats') or user.has_perm(
|
||||||
|
'corputils.add_corpstats')
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@@ -62,7 +68,7 @@ def corpstats_view(request, corp_id=None):
|
|||||||
corpstats = get_object_or_404(CorpStats, corp=corp)
|
corpstats = get_object_or_404(CorpStats, corp=corp)
|
||||||
|
|
||||||
# get available models
|
# get available models
|
||||||
available = CorpStats.objects.visible_to(request.user)
|
available = CorpStats.objects.visible_to(request.user).order_by('corp__corporation_name')
|
||||||
|
|
||||||
# ensure we can see the requested model
|
# ensure we can see the requested model
|
||||||
if corpstats and corpstats not in available:
|
if corpstats and corpstats not in available:
|
||||||
|
|||||||
@@ -4,6 +4,16 @@ import logging
|
|||||||
import os
|
import os
|
||||||
|
|
||||||
SWAGGER_SPEC_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'swagger.json')
|
SWAGGER_SPEC_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'swagger.json')
|
||||||
|
"""
|
||||||
|
Swagger spec operations:
|
||||||
|
|
||||||
|
get_alliances_alliance_id
|
||||||
|
get_alliances_alliance_id_corporations
|
||||||
|
get_corporations_corporation_id
|
||||||
|
get_characters_character_id
|
||||||
|
get_universe_types_type_id
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -1,12 +1,12 @@
|
|||||||
from . import urls
|
from . import urls
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from allianceauth import hooks
|
from allianceauth import hooks
|
||||||
from allianceauth.services.hooks import MenuItemHook, UrlHook
|
from allianceauth.services.hooks import MenuItemHook, UrlHook
|
||||||
|
|
||||||
|
|
||||||
@hooks.register('menu_item_hook')
|
@hooks.register('menu_item_hook')
|
||||||
def register_menu():
|
def register_menu():
|
||||||
return MenuItemHook('Fleet Activity Tracking', 'fa fa-users fa-lightbulb-o fa-fw', 'fatlink:view',
|
return MenuItemHook(_('Fleet Activity Tracking'), 'fa fa-users fa-lightbulb-o fa-fw', 'fatlink:view',
|
||||||
navactive=['fatlink:'])
|
navactive=['fatlink:'])
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 2.0.6 on 2018-08-03 04:30
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('fleetactivitytracking', '0005_remove_fat_name'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='fat',
|
||||||
|
name='shiptype',
|
||||||
|
field=models.CharField(max_length=100),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -24,7 +24,7 @@ class Fat(models.Model):
|
|||||||
character = models.ForeignKey(EveCharacter, on_delete=models.CASCADE)
|
character = models.ForeignKey(EveCharacter, on_delete=models.CASCADE)
|
||||||
fatlink = models.ForeignKey(Fatlink, on_delete=models.CASCADE)
|
fatlink = models.ForeignKey(Fatlink, on_delete=models.CASCADE)
|
||||||
system = models.CharField(max_length=30)
|
system = models.CharField(max_length=30)
|
||||||
shiptype = models.CharField(max_length=30)
|
shiptype = models.CharField(max_length=100)
|
||||||
station = models.CharField(max_length=125)
|
station = models.CharField(max_length=125)
|
||||||
user = models.ForeignKey(User, on_delete=models.CASCADE)
|
user = models.ForeignKey(User, on_delete=models.CASCADE)
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -22,6 +22,16 @@ from allianceauth.eveonline.models import EveCharacter
|
|||||||
from allianceauth.eveonline.models import EveCorporationInfo
|
from allianceauth.eveonline.models import EveCorporationInfo
|
||||||
|
|
||||||
SWAGGER_SPEC_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'swagger.json')
|
SWAGGER_SPEC_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'swagger.json')
|
||||||
|
"""
|
||||||
|
Swagger spec operations:
|
||||||
|
|
||||||
|
get_characters_character_id_location
|
||||||
|
get_characters_character_id_ship
|
||||||
|
get_universe_systems_system_id
|
||||||
|
get_universe_stations_station_id
|
||||||
|
get_universe_structures_structure_id
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
<div class="col-lg-6">
|
<div class="col-lg-6">
|
||||||
<div class="table-responsive">
|
<div class="table-responsive">
|
||||||
<table class="table table-condensed table-hover table-striped">
|
<table class="table table-condensed table-hover table-striped">
|
||||||
<tr>
|
<tr>
|
||||||
<th class="col-md-1"></th>
|
<th class="col-md-1"></th>
|
||||||
@@ -26,7 +26,7 @@
|
|||||||
{% for char_name, user_id in member_list %}
|
{% for char_name, user_id in member_list %}
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
<img src="http://image.eveonline.com/Character/{{ user_id.char_id }}_32.jpg" class="img-circle">
|
<img src="https://imageserver.eveonline.com/Character/{{ user_id.char_id }}_32.jpg" class="img-circle">
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<p>{{ user_id.char_name }}</p>
|
<p>{{ user_id.char_name }}</p>
|
||||||
|
|||||||
@@ -8,12 +8,12 @@
|
|||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="col-lg-12">
|
<div class="col-lg-12">
|
||||||
{% include "fleetup/menu.html" %}
|
{% include "fleetup/menu.html" %}
|
||||||
<div class="panel">
|
<div>
|
||||||
{% for a, j in doctrine.items %}
|
{% for a, j in doctrine.items %}
|
||||||
{% regroup j.Data|dictsort:"Role" by Role as role_list %}
|
{% regroup j.Data|dictsort:"Role" by Role as role_list %}
|
||||||
|
|
||||||
{% for Role in role_list %}
|
{% for Role in role_list %}
|
||||||
|
|
||||||
<div class="panel panel-default">
|
<div class="panel panel-default">
|
||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
<h3 class="panel-title"><b>{{ Role.grouper }}</b></h3>
|
<h3 class="panel-title"><b>{{ Role.grouper }}</b></h3>
|
||||||
@@ -50,7 +50,7 @@
|
|||||||
{% load humanize %}{{ item.EstPrice|intword }}
|
{% load humanize %}{{ item.EstPrice|intword }}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
{% for categories in item.Categories %}
|
{% for categories in item.Categories %}
|
||||||
{{ categories }},
|
{{ categories }},
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</td>
|
</td>
|
||||||
|
|||||||
@@ -8,12 +8,12 @@
|
|||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="col-lg-12">
|
<div class="col-lg-12">
|
||||||
{% include "fleetup/menu.html" %}
|
{% include "fleetup/menu.html" %}
|
||||||
<div class="panel">
|
<div>
|
||||||
{% if doctrines_list %}
|
{% if doctrines_list %}
|
||||||
{% for a, j in doctrines_list.items %}
|
{% for a, j in doctrines_list.items %}
|
||||||
{% regroup j|dictsort:"FolderName" by FolderName as folder_list %}
|
{% regroup j|dictsort:"FolderName" by FolderName as folder_list %}
|
||||||
{% for FolderName in folder_list %}
|
{% for FolderName in folder_list %}
|
||||||
<div class="col-lg-8">
|
<div>
|
||||||
<div class="panel panel-default">
|
<div class="panel panel-default">
|
||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
<h3 class="panel-title"><b>{{ FolderName.grouper }}</b></h3>
|
<h3 class="panel-title"><b>{{ FolderName.grouper }}</b></h3>
|
||||||
@@ -29,11 +29,11 @@
|
|||||||
<th class="col-lg-2">Note</th>-->
|
<th class="col-lg-2">Note</th>-->
|
||||||
</tr>
|
</tr>
|
||||||
{% for item in FolderName.list %}
|
{% for item in FolderName.list %}
|
||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
<a href="{% url 'fleetup:doctrine' item.DoctrineId %}"><img src="https://image.eveonline.com/InventoryType/{{ item.IconId }}_32.png"></a>
|
<a href="{% url 'fleetup:doctrine' item.DoctrineId %}"><img src="https://image.eveonline.com/InventoryType/{{ item.IconId }}_32.png"></a>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
{{ item.Name }}
|
{{ item.Name }}
|
||||||
</td>
|
</td>
|
||||||
|
|||||||
@@ -8,9 +8,9 @@
|
|||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="col-lg-12">
|
<div class="col-lg-12">
|
||||||
{% include "fleetup/menu.html" %}
|
{% include "fleetup/menu.html" %}
|
||||||
<div class="tab-content">
|
<div class="tab-content row">
|
||||||
<div id="fit" class="tab-pane fade in active">
|
<div id="fit" class="tab-pane fade in active">
|
||||||
<div class="col-lg-3">
|
<div class="col-lg-4">
|
||||||
{% for x, y in fitting_data.items %}
|
{% for x, y in fitting_data.items %}
|
||||||
<div class="panel panel-default">
|
<div class="panel panel-default">
|
||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
@@ -18,22 +18,24 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
{% for doctrin in y.Doctrines %}
|
{% for doctrin in y.Doctrines %}
|
||||||
<h4>{{ doctrin.Name }}</h4>
|
<div class="clearfix">
|
||||||
<div class="col-lg-12">
|
<h4>{{ doctrin.Name }}</h4>
|
||||||
<p>{% trans "Role in doctrine:" %} {{ doctrin.Role }}</p>
|
<div class="col-lg-12">
|
||||||
</div>
|
<p>{% trans "Role in doctrine:" %} {{ doctrin.Role }}</p>
|
||||||
<div class="col-lg-4">
|
</div>
|
||||||
<p>{% trans "Priority:" %}</p>
|
<div class="col-lg-4">
|
||||||
</div>
|
<p>{% trans "Priority:" %}</p>
|
||||||
<div class="col-lg-8">
|
</div>
|
||||||
<div class="progress">
|
<div class="col-lg-8">
|
||||||
<div class="progress-bar progress-bar-striped" role="progressbar" aria-valuenow="{{ doctrin.Priority }}" aria-valuemin="0" aria-valuemax="5" style="width: {% widthratio doctrin.Priority 5 100 %}%;">
|
<div class="progress">
|
||||||
{{ doctrin.Priority }}/5
|
<div class="progress-bar progress-bar-striped" role="progressbar" aria-valuenow="{{ doctrin.Priority }}" aria-valuemin="0" aria-valuemax="5" style="width: {% widthratio doctrin.Priority 5 100 %}%;">
|
||||||
|
{{ doctrin.Priority }}/5
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="pull-right">
|
||||||
<div class="pull-right">
|
<a class="btn btn-primary" href="{% url 'fleetup:doctrine' doctrin.DoctrineId %}">{% trans "See doctrine" %}</a>
|
||||||
<a class="btn btn-primary" href="{% url 'fleetup:doctrine' doctrin.DoctrineId %}">{% trans "See doctrine" %}</a>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
@@ -56,10 +58,10 @@
|
|||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
<div class="list-group">
|
<div class="list-group">
|
||||||
{% for arbit, orbit in doctrines_list.items %}
|
{% for arbit, orbit in doctrines_list.items %}
|
||||||
|
|
||||||
{% for fitting in orbit.Data %}
|
{% for fitting in orbit.Data %}
|
||||||
<a href="{% url 'fleetup:fitting' fitting.FittingId %}" class="list-group-item">
|
<a href="{% url 'fleetup:fitting' fitting.FittingId %}" class="list-group-item">
|
||||||
|
|
||||||
<h4 class="list-group-item-heading">{{ fitting.Name }}<span class="pull-right"><img src="https://image.eveonline.com/InventoryType/{{ fitting.EveTypeId }}_32.png" class="img-circle"></span></h4>
|
<h4 class="list-group-item-heading">{{ fitting.Name }}<span class="pull-right"><img src="https://image.eveonline.com/InventoryType/{{ fitting.EveTypeId }}_32.png" class="img-circle"></span></h4>
|
||||||
<p class="list-group-item-heading">{{ fitting.Role }} - {{ fitting.ShipType }}</p>
|
<p class="list-group-item-heading">{{ fitting.Role }} - {{ fitting.ShipType }}</p>
|
||||||
</a>
|
</a>
|
||||||
@@ -107,8 +109,8 @@
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-lg-3">
|
<div class="col-lg-4">
|
||||||
<div class="panel panel-default">
|
<div class="panel panel-default">
|
||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
<h3 class="panel-title">{% trans "EFT/Export" %}</h3>
|
<h3 class="panel-title">{% trans "EFT/Export" %}</h3>
|
||||||
|
|||||||
@@ -20,11 +20,11 @@
|
|||||||
<th class="col-md-2">{% trans "Categories" %}</th>
|
<th class="col-md-2">{% trans "Categories" %}</th>
|
||||||
</tr>
|
</tr>
|
||||||
{% for id, fittings in fitting_list %}
|
{% for id, fittings in fitting_list %}
|
||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
<a href="{% url 'fleetup:fitting' fittings.fitting_id %}"><img src="https://image.eveonline.com/InventoryType/{{ fittings.icon_id }}_32.png"></a>
|
<a href="{% url 'fleetup:fitting' fittings.fitting_id %}"><img src="https://image.eveonline.com/InventoryType/{{ fittings.icon_id }}_32.png"></a>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
{{ fittings.name }}
|
{{ fittings.name }}
|
||||||
</td>
|
</td>
|
||||||
@@ -38,12 +38,12 @@
|
|||||||
{% load humanize %}{{ fittings.estimated|intword }}
|
{% load humanize %}{{ fittings.estimated|intword }}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
{% for categories in fittings.categories %}
|
{% for categories in fittings.categories %}
|
||||||
{{ categories }},
|
{{ categories }},
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</table>
|
</table>
|
||||||
{% else %}
|
{% else %}
|
||||||
|
|||||||
@@ -1,256 +1,254 @@
|
|||||||
{% extends "allianceauth/base.html" %}
|
{% extends "allianceauth/base.html" %}
|
||||||
{% load bootstrap %}
|
{% load bootstrap %}
|
||||||
{% load staticfiles %}
|
{% load staticfiles %}
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
|
||||||
{% block page_title %}FleetUp{% endblock page_title %}
|
{% block page_title %}FleetUp{% endblock page_title %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="col-lg-12">
|
<div class="col-lg-12">
|
||||||
{% include "fleetup/menu.html" %}
|
{% include "fleetup/menu.html" %}
|
||||||
<div class="panel">
|
<div>
|
||||||
<ul class="nav nav-tabs">
|
<ul class="nav nav-tabs">
|
||||||
<li class="active"><a data-toggle="tab" href="#operations">{% trans "Operations" %}</a></li>
|
<li class="active"><a data-toggle="tab" href="#operations">{% trans "Operations" %}</a></li>
|
||||||
<li><a data-toggle="tab" href="#timers">{% trans "Timers" %}</a></li>
|
<li><a data-toggle="tab" href="#timers">{% trans "Timers" %}</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<div class="tab-content">
|
<div class="tab-content row">
|
||||||
<div id="operations" class="tab-pane fade in active">
|
<div id="operations" class="tab-pane fade in active">
|
||||||
<div class="col-lg-7">
|
<div class="col-lg-8">
|
||||||
{% if operations_list %}
|
{% if operations_list %}
|
||||||
{% for subject, start in operations_list %}
|
{% for subject, start in operations_list %}
|
||||||
<div class="panel panel-default">
|
<div class="panel panel-default">
|
||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
<h3 class="panel-title"><b>{{ start.subject }}</b></h3>
|
<h3 class="panel-title"><b>{{ start.subject }}</b></h3>
|
||||||
</div>
|
</div>
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
<table class="table table-condensed">
|
<table class="table table-condensed">
|
||||||
<tr>
|
<tr>
|
||||||
<th class="col-md-6">{% trans "Start" %}</th>
|
<th class="col-md-6">{% trans "Start" %}</th>
|
||||||
<th class="col-md-6">{% trans "End" %}</th>
|
<th class="col-md-6">{% trans "End" %}</th>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="col-md-6">{{ start.start|date:"l d M H:i" }} <span class="label label-success">{% trans "Eve Time" %}</span></td>
|
<td class="col-md-6">{{ start.start|date:"l d M H:i" }} <span class="label label-success">{% trans "Eve Time" %}</span></td>
|
||||||
|
|
||||||
<td class="col-md-6">{{ start.end|date:"l d M H:i" }} <span class="label label-success">{% trans "Eve Time" %}</span></td>
|
<td class="col-md-6">{{ start.end|date:"l d M H:i" }} <span class="label label-success">{% trans "Eve Time" %}</span></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="col-md-6">
|
<td class="col-md-6">
|
||||||
<span id="localtime{{ start.operation_id }}"></span> <span class='label label-success'>Local time</span><br>
|
<span id="localtime{{ start.operation_id }}"></span> <span class='label label-success'>Local time</span><br>
|
||||||
<div id="countdown{{ start.operation_id }}"></div>
|
<div id="countdown{{ start.operation_id }}"></div>
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
<td class="col-md-6"></td>
|
<td class="col-md-6"></td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
<p>{{ start.details }}</p>
|
{{ start.details|linebreaks }}
|
||||||
|
|
||||||
<div class="col-lg-12">
|
<table class="table table-condensed table-striped">
|
||||||
<table class="table table-condensed table-striped">
|
<tr>
|
||||||
<tr>
|
<th class="col-md-4">{% trans "Location" %}</th>
|
||||||
<th class="col-md-4">{% trans "Location" %}</th>
|
<th class="col-md-4">{% trans "Doctrine" %}</th>
|
||||||
<th class="col-md-4">{% trans "Doctrine" %}</th>
|
<th class="col-md-2">{% trans "Organizer" %}</th>
|
||||||
<th class="col-md-2">{% trans "Organizer" %}</th>
|
<th class="col-md-2">{% trans "URL" %}</th>
|
||||||
<th class="col-md-2">{% trans "URL" %}</th>
|
</tr>
|
||||||
</tr>
|
<tr>
|
||||||
<tr>
|
<td>
|
||||||
<td>
|
{{ start.location }} - {{ start.location_info }} <a href="http://evemaps.dotlan.net/system/{{ start.location }}" target="_blank" class="label label-success">Dotlan</a>
|
||||||
{{ start.location }} - {{ start.location_info }} <a href="http://evemaps.dotlan.net/system/{{ start.location }}" target="_blank" class="label label-success">Dotlan</a>
|
</td>
|
||||||
</td>
|
<td>
|
||||||
<td>
|
{% if start.doctrine %}
|
||||||
{% if start.doctrine %}
|
{% for doctrine in start.doctrine %}
|
||||||
{% for doctrine in start.doctrine %}
|
|
||||||
|
<a href="{% url 'fleetup:doctrine' doctrine.Id %}" class="label label-success">{{ doctrine.Name }}</a>
|
||||||
<a href="{% url 'fleetup:doctrine' doctrine.Id %}" class="label label-success">{{ doctrine.Name }}</a>
|
|
||||||
|
{% endfor %}
|
||||||
{% endfor %}
|
|
||||||
|
{% else %}
|
||||||
{% else %}
|
<span class="label label-danger">{% trans "TBA" %}</span>
|
||||||
<span class="label label-danger">{% trans "TBA" %}</span>
|
{% endif %}
|
||||||
{% endif %}
|
</td>
|
||||||
</td>
|
<td>
|
||||||
<td>
|
{{ start.organizer }}
|
||||||
{{ start.organizer }}
|
</td>
|
||||||
</td>
|
<td>
|
||||||
<td>
|
{% ifequal start.url "" %}
|
||||||
{% ifequal start.url "" %}
|
<div class="label label-danger">{% trans "No link" %}</div>
|
||||||
<div class="label label-danger">{% trans "No link" %}</div>
|
{% else %}
|
||||||
{% else %}
|
<a href="{{ start.url }}" target="_blank" class="label label-success">{% trans "External link" %}</a>
|
||||||
<a href="{{ start.url }}" target="_blank" class="label label-success">{% trans "External link" %}</a>
|
{% endifequal %}
|
||||||
{% endifequal %}
|
</td>
|
||||||
</td>
|
</tr>
|
||||||
</tr>
|
</table>
|
||||||
</table>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
{% endfor %}
|
||||||
</div>
|
{% else %}
|
||||||
{% endfor %}
|
<h3>{% trans "There seems to be no Operations in the near future." %}</h3>
|
||||||
{% else %}
|
{% endif %}
|
||||||
<h3>{% trans "There seems to be no Operations in the near future." %}</h3>
|
</div>
|
||||||
{% endif %}
|
<div class="col-lg-4">
|
||||||
</div>
|
<div class="panel panel-default">
|
||||||
<div class="col-lg-3">
|
<div class="panel-heading">
|
||||||
<div class="panel panel-default">
|
<h2 class="panel-title">{% trans "Current Eve Time:" %}</h2>
|
||||||
<div class="panel-heading">
|
</div>
|
||||||
<h2 class="panel-title">{% trans "Current Eve Time:" %}</h2>
|
<div class="panel-body">
|
||||||
</div>
|
<div id="current-time"></div>
|
||||||
<div class="panel-body">
|
</div>
|
||||||
<div id="current-time"></div>
|
</div>
|
||||||
</div>
|
{% if timers_list %}
|
||||||
</div>
|
<div class="panel panel-default">
|
||||||
{% if timers_list %}
|
<div class="panel-heading">
|
||||||
<div class="panel panel-default">
|
<h2 class="panel-title">{% trans "Timers" %}</h2>
|
||||||
<div class="panel-heading">
|
</div>
|
||||||
<h2 class="panel-title">{% trans "Timers" %}</h2>
|
<div class="panel-body">
|
||||||
</div>
|
<table class="table table-condensed table-hover table-striped">
|
||||||
<div class="panel-body">
|
{% for notes, type in timers_list %}
|
||||||
<table class="table table-condensed table-hover table-striped">
|
<tr>
|
||||||
{% for notes, type in timers_list %}
|
<td>
|
||||||
<tr>
|
{{ type.solarsystem }}
|
||||||
<td>
|
</td>
|
||||||
{{ type.solarsystem }}
|
<td>
|
||||||
</td>
|
{{ type.expires|date:"l d M H:i" }}
|
||||||
<td>
|
</td>
|
||||||
{{ type.expires|date:"l d M H:i" }}
|
</tr>
|
||||||
</td>
|
{% endfor %}
|
||||||
</tr>
|
</table>
|
||||||
{% endfor %}
|
</div>
|
||||||
</table>
|
</div>
|
||||||
</div>
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
</div>
|
||||||
</div>
|
<div id="timers" class="tab-pane fade in">
|
||||||
</div>
|
<div class="col-lg-12">
|
||||||
<div id="timers" class="tab-pane fade in">
|
{% if timers_list %}
|
||||||
<div class="col-lg-12">
|
<div class="panel panel-default">
|
||||||
{% if timers_list %}
|
<div class="panel-heading">
|
||||||
<div class="panel panel-default">
|
<h2 class="panel-title">{% trans "Timers" %}</h2>
|
||||||
<div class="panel-heading">
|
</div>
|
||||||
<h2 class="panel-title">{% trans "Timers" %}</h2>
|
<div class="panel-body">
|
||||||
</div>
|
<div class="col-lg-12">
|
||||||
<div class="panel-body">
|
<table class="table table-condensed table-hover table-striped">
|
||||||
<div class="col-lg-12">
|
<tr>
|
||||||
<table class="table table-condensed table-hover table-striped">
|
<th class="col-lg-1">{% trans "Type" %}</th>
|
||||||
<tr>
|
<th class="col-lg-1">{% trans "Structure" %}</th>
|
||||||
<th class="col-lg-1">{% trans "Type" %}</th>
|
<th class="col-lg-2">{% trans "Location" %}</th>
|
||||||
<th class="col-lg-1">{% trans "Structure" %}</th>
|
<th class="col-lg-2">{% trans "Expires(EVE-time)" %}</th>
|
||||||
<th class="col-lg-2">{% trans "Location" %}</th>
|
<th class="col-lg-1">{% trans "Owner" %}</th>
|
||||||
<th class="col-lg-2">{% trans "Expires(EVE-time)" %}</th>
|
<th class="col-lg-2">{% trans "Note" %}</th>
|
||||||
<th class="col-lg-1">{% trans "Owner" %}</th>
|
</tr>
|
||||||
<th class="col-lg-2">{% trans "Note" %}</th>
|
{% for notes, type in timers_list %}
|
||||||
</tr>
|
<tr>
|
||||||
{% for notes, type in timers_list %}
|
<td>
|
||||||
<tr>
|
{% ifequal type.type "Final" %}
|
||||||
<td>
|
<span class="label label-danger">
|
||||||
{% ifequal type.type "Final" %}
|
{{ type.type }}</span>{% else %}{{ type.type }}{% endifequal %}
|
||||||
<span class="label label-danger">
|
</td>
|
||||||
{{ type.type }}</span>{% else %}{{ type.type }}{% endifequal %}
|
<td>
|
||||||
</td>
|
{{ type.timer_type }}
|
||||||
<td>
|
</td>
|
||||||
{{ type.timer_type }}
|
<td>
|
||||||
</td>
|
{{ type.solarsystem }} - Planet:{{ type.planet }} Moon:{{ type.moon }}
|
||||||
<td>
|
</td>
|
||||||
{{ type.solarsystem }} - Planet:{{ type.planet }} Moon:{{ type.moon }}
|
<td>
|
||||||
</td>
|
{{ type.expires|date:"l d M H:i" }}
|
||||||
<td>
|
</td>
|
||||||
{{ type.expires|date:"l d M H:i" }}
|
<td>
|
||||||
</td>
|
{{ type.owner }}
|
||||||
<td>
|
</td>
|
||||||
{{ type.owner }}
|
<td>
|
||||||
</td>
|
{{ type.notes }}
|
||||||
<td>
|
</td>
|
||||||
{{ type.notes }}
|
</tr>
|
||||||
</td>
|
{% endfor %}
|
||||||
</tr>
|
</table>
|
||||||
{% endfor %}
|
</div>
|
||||||
</table>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
{% else %}
|
||||||
</div>
|
<h3>{% trans "There seems to be no Timers in the near future." %}</h3>
|
||||||
{% else %}
|
{% endif %}
|
||||||
<h3>{% trans "There seems to be no Timers in the near future." %}</h3>
|
</div>
|
||||||
{% endif %}
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
{% include 'bundles/moment-js.html' with locale=True %}
|
||||||
</div>
|
<script src="{% static 'js/timers.js' %}"></script>
|
||||||
{% include 'bundles/moment-js.html' with locale=True %}
|
<script type="text/javascript">
|
||||||
<script src="{% static 'js/timers.js' %}"></script>
|
// Data
|
||||||
<script type="text/javascript">
|
var timers = [
|
||||||
// Data
|
{% for start, op in operations_list %}
|
||||||
var timers = [
|
{
|
||||||
{% for start, op in operations_list %}
|
'id': {{ op.operation_id }},
|
||||||
{
|
'start': moment("{{ op.start | date:"c" }}"),
|
||||||
'id': {{ op.operation_id }},
|
'end': moment("{{ op.end | date:"c" }}"),
|
||||||
'start': moment("{{ op.start | date:"c" }}"),
|
'expired': false
|
||||||
'end': moment("{{ op.end | date:"c" }}"),
|
},
|
||||||
'expired': false
|
{% endfor %}
|
||||||
},
|
]
|
||||||
{% endfor %}
|
</script>
|
||||||
]
|
<script type="text/javascript">
|
||||||
</script>
|
|
||||||
<script type="text/javascript">
|
timedUpdate();
|
||||||
|
setAllLocalTimes();
|
||||||
timedUpdate();
|
|
||||||
setAllLocalTimes();
|
// Start timed updates
|
||||||
|
setInterval(timedUpdate, 1000);
|
||||||
// Start timed updates
|
|
||||||
setInterval(timedUpdate, 1000);
|
function timedUpdate() {
|
||||||
|
updateClock();
|
||||||
function timedUpdate() {
|
updateAllTimers();
|
||||||
updateClock();
|
}
|
||||||
updateAllTimers();
|
|
||||||
}
|
function updateAllTimers () {
|
||||||
|
var l = timers.length;
|
||||||
function updateAllTimers () {
|
for (var i=0; i < l; ++i) {
|
||||||
var l = timers.length;
|
if (timers[i].expired) continue;
|
||||||
for (var i=0; i < l; ++i) {
|
updateTimer(timers[i]);
|
||||||
if (timers[i].expired) continue;
|
}
|
||||||
updateTimer(timers[i]);
|
}
|
||||||
}
|
|
||||||
}
|
/**
|
||||||
|
* Update a timer
|
||||||
/**
|
* @param timer Timer information
|
||||||
* Update a timer
|
* @param timer.start Date of the timer
|
||||||
* @param timer Timer information
|
* @param timer.id Id number of the timer
|
||||||
* @param timer.start Date of the timer
|
* @param timer.expired
|
||||||
* @param timer.id Id number of the timer
|
*/
|
||||||
* @param timer.expired
|
function updateTimer(timer) {
|
||||||
*/
|
if (timer.start.isAfter(Date.now())) {
|
||||||
function updateTimer(timer) {
|
var duration = moment.duration(timer.start - moment(), 'milliseconds');
|
||||||
if (timer.start.isAfter(Date.now())) {
|
document.getElementById("countdown" + timer.id).innerHTML = getDurationString(duration);
|
||||||
var duration = moment.duration(timer.start - moment(), 'milliseconds');
|
} else {
|
||||||
document.getElementById("countdown" + timer.id).innerHTML = getDurationString(duration);
|
timer.expired = true;
|
||||||
} else {
|
document.getElementById("countdown" + timer.id).innerHTML = "";
|
||||||
timer.expired = true;
|
}
|
||||||
document.getElementById("countdown" + timer.id).innerHTML = "";
|
}
|
||||||
}
|
|
||||||
}
|
/**
|
||||||
|
* Set all local time fields
|
||||||
/**
|
*/
|
||||||
* Set all local time fields
|
function setAllLocalTimes() {
|
||||||
*/
|
var l = timers.length;
|
||||||
function setAllLocalTimes() {
|
for (var i=0; i < l; ++i) {
|
||||||
var l = timers.length;
|
setLocalTime(timers[i]);
|
||||||
for (var i=0; i < l; ++i) {
|
}
|
||||||
setLocalTime(timers[i]);
|
}
|
||||||
}
|
|
||||||
}
|
/**
|
||||||
|
* Set the local time info for the timer
|
||||||
/**
|
* @param timer Timer information
|
||||||
* Set the local time info for the timer
|
* @param timer.start Date of the timer
|
||||||
* @param timer Timer information
|
* @param timer.id Id number of the timer
|
||||||
* @param timer.start Date of the timer
|
*/
|
||||||
* @param timer.id Id number of the timer
|
function setLocalTime(timer) {
|
||||||
*/
|
document.getElementById("localtime" + timer.id).innerHTML = timer.start.format("ddd @ LT");
|
||||||
function setLocalTime(timer) {
|
}
|
||||||
document.getElementById("localtime" + timer.id).innerHTML = timer.start.format("ddd @ LT");
|
|
||||||
}
|
function updateClock() {
|
||||||
|
document.getElementById("current-time").innerHTML = "<b>" + moment.utc().format('ddd, ll HH:mm:ss z') + "</b>";
|
||||||
function updateClock() {
|
}
|
||||||
document.getElementById("current-time").innerHTML = "<b>" + moment.utc().format('ddd, ll HH:mm:ss z') + "</b>";
|
</script>
|
||||||
}
|
{% endblock content %}
|
||||||
</script>
|
|
||||||
{% endblock content %}
|
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ from .models import GroupRequest
|
|||||||
|
|
||||||
class AuthGroupInlineAdmin(admin.StackedInline):
|
class AuthGroupInlineAdmin(admin.StackedInline):
|
||||||
model = AuthGroup
|
model = AuthGroup
|
||||||
filter_horizontal = ('group_leaders',)
|
filter_horizontal = ('group_leaders', 'states',)
|
||||||
fields = ('description', 'group_leaders', 'internal', 'hidden', 'open', 'public')
|
fields = ('description', 'group_leaders', 'states', 'internal', 'hidden', 'open', 'public')
|
||||||
verbose_name_plural = 'Auth Settings'
|
verbose_name_plural = 'Auth Settings'
|
||||||
verbose_name = ''
|
verbose_name = ''
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
from django.contrib.auth.models import Group
|
from django.contrib.auth.models import Group
|
||||||
|
from django.db.models import Q
|
||||||
|
|
||||||
|
|
||||||
class GroupManager:
|
class GroupManager:
|
||||||
@@ -6,7 +7,12 @@ class GroupManager:
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_joinable_groups():
|
def get_joinable_groups(state):
|
||||||
|
return Group.objects.select_related('authgroup').exclude(authgroup__internal=True)\
|
||||||
|
.filter(Q(authgroup__states=state) | Q(authgroup__states=None))
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_all_non_internal_groups():
|
||||||
return Group.objects.select_related('authgroup').exclude(authgroup__internal=True)
|
return Group.objects.select_related('authgroup').exclude(authgroup__internal=True)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@@ -14,13 +20,35 @@ class GroupManager:
|
|||||||
return Group.objects.select_related('authgroup').filter(authgroup__group_leaders__in=[user])
|
return Group.objects.select_related('authgroup').filter(authgroup__group_leaders__in=[user])
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def joinable_group(group):
|
def joinable_group(group, state):
|
||||||
"""
|
"""
|
||||||
Check if a group is a user 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,
|
||||||
|
or restricted from the user's current state.
|
||||||
:param group: django.contrib.auth.models.Group object
|
:param group: django.contrib.auth.models.Group 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():
|
||||||
|
return False
|
||||||
|
return not group.authgroup.internal
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def check_internal_group(group):
|
||||||
|
"""
|
||||||
|
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 check_internal_group(group):
|
||||||
|
"""
|
||||||
|
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
|
return not group.authgroup.internal
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
|||||||
28
allianceauth/groupmanagement/migrations/0009_requestlog.py
Normal file
28
allianceauth/groupmanagement/migrations/0009_requestlog.py
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
# Generated by Django 2.0.6 on 2018-06-04 02:45
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('auth', '0008_alter_user_username_max_length'),
|
||||||
|
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||||
|
('groupmanagement', '0008_remove_authgroup_permissions'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='RequestLog',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('request_type', models.NullBooleanField(default=0)),
|
||||||
|
('request_info', models.CharField(max_length=254)),
|
||||||
|
('action', models.BooleanField(default=0)),
|
||||||
|
('group', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='auth.Group')),
|
||||||
|
('request_actor', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
# Generated by Django 2.0.6 on 2018-07-11 00:17
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('authentication', '0016_ownershiprecord'),
|
||||||
|
('groupmanagement', '0009_requestlog'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='authgroup',
|
||||||
|
name='states',
|
||||||
|
field=models.ManyToManyField(blank=True, help_text='States listed here will have the ability to join this group provided they have the proper permissions.', related_name='valid_states', to='authentication.State'),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -3,6 +3,7 @@ from django.contrib.auth.models import User
|
|||||||
from django.db import models
|
from django.db import models
|
||||||
from django.db.models.signals import post_save
|
from django.db.models.signals import post_save
|
||||||
from django.dispatch import receiver
|
from django.dispatch import receiver
|
||||||
|
from allianceauth.authentication.models import State
|
||||||
|
|
||||||
|
|
||||||
class GroupRequest(models.Model):
|
class GroupRequest(models.Model):
|
||||||
@@ -23,6 +24,37 @@ class GroupRequest(models.Model):
|
|||||||
return self.user.username + ":" + self.group.name
|
return self.user.username + ":" + self.group.name
|
||||||
|
|
||||||
|
|
||||||
|
class RequestLog(models.Model):
|
||||||
|
request_type = models.NullBooleanField(default=0)
|
||||||
|
group = models.ForeignKey(Group, on_delete=models.CASCADE)
|
||||||
|
request_info = models.CharField(max_length=254)
|
||||||
|
action = models.BooleanField(default=0)
|
||||||
|
request_actor = models.ForeignKey(User, on_delete=models.CASCADE)
|
||||||
|
|
||||||
|
def requestor(self):
|
||||||
|
return self.request_info.split(":")[0]
|
||||||
|
|
||||||
|
def type_to_str(self):
|
||||||
|
if self.request_type is None:
|
||||||
|
return "Removed"
|
||||||
|
elif self.request_type is True:
|
||||||
|
return "Leave"
|
||||||
|
elif self.request_type is False:
|
||||||
|
return "Join"
|
||||||
|
|
||||||
|
def action_to_str(self):
|
||||||
|
if self.action is True:
|
||||||
|
return "Accept"
|
||||||
|
elif self.action is False:
|
||||||
|
return "Reject"
|
||||||
|
|
||||||
|
def req_char(self):
|
||||||
|
usr = self.requestor()
|
||||||
|
user = User.objects.get(username=usr)
|
||||||
|
return user.profile.main_character
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class AuthGroup(models.Model):
|
class AuthGroup(models.Model):
|
||||||
"""
|
"""
|
||||||
Extends Django Group model with a one-to-one field
|
Extends Django Group model with a one-to-one field
|
||||||
@@ -65,6 +97,10 @@ class AuthGroup(models.Model):
|
|||||||
"specifically. Use the auth.group_management permission to allow "
|
"specifically. Use the auth.group_management permission to allow "
|
||||||
"a user to manage all groups.")
|
"a user to manage all groups.")
|
||||||
|
|
||||||
|
states = models.ManyToManyField(State, related_name='valid_states', blank=True,
|
||||||
|
help_text="States listed here will have the ability to join this group provided "
|
||||||
|
"they have the proper permissions.")
|
||||||
|
|
||||||
description = models.CharField(max_length=512, blank=True, help_text="Description of the group shown to users.")
|
description = models.CharField(max_length=512, blank=True, help_text="Description of the group shown to users.")
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
|
|||||||
@@ -0,0 +1,40 @@
|
|||||||
|
{% extends "allianceauth/base.html" %}
|
||||||
|
{% load staticfiles %}
|
||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
{% block page_title %}{{ group }} {% trans "Audit Log" %}{% endblock page_title %}
|
||||||
|
{% block extra_css %}{% endblock extra_css %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="col-lg-12">
|
||||||
|
<br>
|
||||||
|
{% include 'groupmanagement/menu.html' %}
|
||||||
|
<div>
|
||||||
|
{% if entries %}
|
||||||
|
<h3>{{ group }} Audit Log</h3>
|
||||||
|
<table class="table">
|
||||||
|
<tr>
|
||||||
|
<th class="text-center">{% trans "Requestor" %}</th>
|
||||||
|
<th class="text-center">{% trans "Main Character" %}</th>
|
||||||
|
<th class="text-center">{% trans "Group" %}</th>
|
||||||
|
<th class="text-center">{% trans "Type" %}</th>
|
||||||
|
<th class="text-center">{% trans "Action" %}</th>
|
||||||
|
<th class="text-center">{% trans "Actor" %}</th>
|
||||||
|
</tr>
|
||||||
|
{% for entry in entries %}
|
||||||
|
<tr>
|
||||||
|
<td class="text-center">{{ entry.requestor }}</td>
|
||||||
|
<td class="text-center">{{ entry.req_char }}</td>
|
||||||
|
<td class="text-center">{{ entry.group }}</td>
|
||||||
|
<td class="text-center">{{ entry.type_to_str }}</td>
|
||||||
|
<td class="text-center">{{ entry.action_to_str }}</td>
|
||||||
|
<td class="text-center">{{ entry.request_actor }}</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</table>
|
||||||
|
{% else %}
|
||||||
|
<div class="alert alert-warning text-center">{% trans "No entries found." %}</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock content %}
|
||||||
@@ -41,6 +41,9 @@
|
|||||||
title="{% trans "View Members" %}">
|
title="{% trans "View Members" %}">
|
||||||
<i class="glyphicon glyphicon-eye-open"></i>
|
<i class="glyphicon glyphicon-eye-open"></i>
|
||||||
</a>
|
</a>
|
||||||
|
<a href="{% url "groupmanagement:audit_log" group.id %}" class="btn btn-info" title="{% trans "Audit Members" %}">
|
||||||
|
<i class="glyphicon glyphicon-list-alt"></i>
|
||||||
|
</a>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ urlpatterns = [
|
|||||||
name='membership'),
|
name='membership'),
|
||||||
url(r'^membership/(\w+)/$', views.group_membership_list,
|
url(r'^membership/(\w+)/$', views.group_membership_list,
|
||||||
name='membership_list'),
|
name='membership_list'),
|
||||||
|
url(r'^membership/(\w+)/audit/', views.group_membership_audit, name="audit_log"),
|
||||||
url(r'^membership/(\w+)/remove/(\w+)/$', views.group_membership_remove,
|
url(r'^membership/(\w+)/remove/(\w+)/$', views.group_membership_remove,
|
||||||
name='membership_remove'),
|
name='membership_remove'),
|
||||||
url(r'^request_add/(\w+)', views.group_request_add,
|
url(r'^request_add/(\w+)', views.group_request_add,
|
||||||
|
|||||||
@@ -10,10 +10,12 @@ 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 .managers import GroupManager
|
||||||
from .models import GroupRequest
|
from .models import GroupRequest, RequestLog
|
||||||
|
|
||||||
from allianceauth.notifications import notify
|
from allianceauth.notifications import notify
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
@@ -53,7 +55,7 @@ def group_membership(request):
|
|||||||
# Get all open and closed groups
|
# Get all open and closed groups
|
||||||
if GroupManager.has_management_permission(request.user):
|
if GroupManager.has_management_permission(request.user):
|
||||||
# Full access
|
# Full access
|
||||||
groups = GroupManager.get_joinable_groups()
|
groups = GroupManager.get_all_non_internal_groups()
|
||||||
else:
|
else:
|
||||||
# Group leader specific
|
# Group leader specific
|
||||||
groups = GroupManager.get_group_leaders_groups(request.user)
|
groups = GroupManager.get_group_leaders_groups(request.user)
|
||||||
@@ -65,6 +67,32 @@ def group_membership(request):
|
|||||||
return render(request, 'groupmanagement/groupmembership.html', context=render_items)
|
return render(request, 'groupmanagement/groupmembership.html', context=render_items)
|
||||||
|
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
@user_passes_test(GroupManager.can_manage_groups)
|
||||||
|
def group_membership_audit(request, group_id):
|
||||||
|
logger.debug("group_management_audit called by user %s" % request.user)
|
||||||
|
group = get_object_or_404(Group, id=group_id)
|
||||||
|
try:
|
||||||
|
|
||||||
|
# Check its a joinable group i.e. not corp or internal
|
||||||
|
# And the user has permission to manage it
|
||||||
|
if not GroupManager.check_internal_group(group) or not GroupManager.can_manage_group(request.user, group):
|
||||||
|
logger.warning("User %s attempted to view the membership of group %s but permission was denied" %
|
||||||
|
(request.user, group_id))
|
||||||
|
raise PermissionDenied
|
||||||
|
|
||||||
|
except ObjectDoesNotExist:
|
||||||
|
raise Http404("Group does not exist")
|
||||||
|
|
||||||
|
entries = RequestLog.objects.filter(group=group)
|
||||||
|
|
||||||
|
render_items = {'entries': entries, 'group': group.name}
|
||||||
|
|
||||||
|
return render(request, 'groupmanagement/audit.html', context=render_items)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@user_passes_test(GroupManager.can_manage_groups)
|
@user_passes_test(GroupManager.can_manage_groups)
|
||||||
def group_membership_list(request, group_id):
|
def group_membership_list(request, group_id):
|
||||||
@@ -74,7 +102,7 @@ def group_membership_list(request, group_id):
|
|||||||
|
|
||||||
# Check its a joinable group i.e. not corp or internal
|
# Check its a joinable group i.e. not corp or internal
|
||||||
# And the user has permission to manage it
|
# And the user has permission to manage it
|
||||||
if not GroupManager.joinable_group(group) or not GroupManager.can_manage_group(request.user, group):
|
if not GroupManager.check_internal_group(group) or not GroupManager.can_manage_group(request.user, group):
|
||||||
logger.warning("User %s attempted to view the membership of group %s but permission was denied" %
|
logger.warning("User %s attempted to view the membership of group %s but permission was denied" %
|
||||||
(request.user, group_id))
|
(request.user, group_id))
|
||||||
raise PermissionDenied
|
raise PermissionDenied
|
||||||
@@ -105,13 +133,16 @@ def group_membership_remove(request, group_id, user_id):
|
|||||||
try:
|
try:
|
||||||
# Check its a joinable group i.e. not corp or internal
|
# Check its a joinable group i.e. not corp or internal
|
||||||
# And the user has permission to manage it
|
# And the user has permission to manage it
|
||||||
if not GroupManager.joinable_group(group) or not GroupManager.can_manage_group(request.user, group):
|
if not GroupManager.check_internal_group(group) or not GroupManager.can_manage_group(request.user, group):
|
||||||
logger.warning("User %s attempted to remove a user from group %s but permission was denied" % (request.user,
|
logger.warning("User %s attempted to remove a user from group %s but permission was denied" % (request.user,
|
||||||
group_id))
|
group_id))
|
||||||
raise PermissionDenied
|
raise PermissionDenied
|
||||||
|
|
||||||
try:
|
try:
|
||||||
user = group.user_set.get(id=user_id)
|
user = group.user_set.get(id=user_id)
|
||||||
|
request_info = user.username + ":" + group.name
|
||||||
|
log = RequestLog(request_type=None,group=group,request_info=request_info,action=1,request_actor=request.user)
|
||||||
|
log.save()
|
||||||
# Remove group from user
|
# Remove group from user
|
||||||
user.groups.remove(group)
|
user.groups.remove(group)
|
||||||
logger.info("User %s removed user %s from group %s" % (request.user, user, group))
|
logger.info("User %s removed user %s from group %s" % (request.user, user, group))
|
||||||
@@ -133,12 +164,14 @@ def group_accept_request(request, group_request_id):
|
|||||||
try:
|
try:
|
||||||
group, created = Group.objects.get_or_create(name=group_request.group.name)
|
group, created = Group.objects.get_or_create(name=group_request.group.name)
|
||||||
|
|
||||||
if not GroupManager.joinable_group(group_request.group) or \
|
if not GroupManager.joinable_group(group_request.group, group_request.user.profile.state) or \
|
||||||
not GroupManager.can_manage_group(request.user, group_request.group):
|
not GroupManager.can_manage_group(request.user, group_request.group):
|
||||||
raise PermissionDenied
|
raise PermissionDenied
|
||||||
|
|
||||||
group_request.user.groups.add(group)
|
group_request.user.groups.add(group)
|
||||||
group_request.user.save()
|
group_request.user.save()
|
||||||
|
log = RequestLog(request_type=group_request.leave_request,group=group,request_info=group_request.__str__(),action=1,request_actor=request.user)
|
||||||
|
log.save()
|
||||||
group_request.delete()
|
group_request.delete()
|
||||||
logger.info("User %s accepted group request from user %s to group %s" % (
|
logger.info("User %s accepted group request from user %s to group %s" % (
|
||||||
request.user, group_request.user, group_request.group.name))
|
request.user, group_request.user, group_request.group.name))
|
||||||
@@ -172,6 +205,8 @@ def group_reject_request(request, group_request_id):
|
|||||||
if group_request:
|
if group_request:
|
||||||
logger.info("User %s rejected group request from user %s to group %s" % (
|
logger.info("User %s rejected group request from user %s to group %s" % (
|
||||||
request.user, group_request.user, group_request.group.name))
|
request.user, group_request.user, group_request.group.name))
|
||||||
|
log = RequestLog(request_type=group_request.leave_request,group=group_request.group,request_info=group_request.__str__(),action=0,request_actor=request.user)
|
||||||
|
log.save()
|
||||||
group_request.delete()
|
group_request.delete()
|
||||||
notify(group_request.user, "Group Application Rejected", level="danger",
|
notify(group_request.user, "Group Application Rejected", level="danger",
|
||||||
message="Your application to %s has been rejected." % group_request.group)
|
message="Your application to %s has been rejected." % group_request.group)
|
||||||
@@ -204,6 +239,8 @@ def group_leave_accept_request(request, group_request_id):
|
|||||||
group, created = Group.objects.get_or_create(name=group_request.group.name)
|
group, created = Group.objects.get_or_create(name=group_request.group.name)
|
||||||
group_request.user.groups.remove(group)
|
group_request.user.groups.remove(group)
|
||||||
group_request.user.save()
|
group_request.user.save()
|
||||||
|
log = RequestLog(request_type=group_request.leave_request,group=group_request.group,request_info=group_request.__str__(),action=1,request_actor=request.user)
|
||||||
|
log.save()
|
||||||
group_request.delete()
|
group_request.delete()
|
||||||
logger.info("User %s accepted group leave request from user %s to group %s" % (
|
logger.info("User %s accepted group leave request from user %s to group %s" % (
|
||||||
request.user, group_request.user, group_request.group.name))
|
request.user, group_request.user, group_request.group.name))
|
||||||
@@ -236,6 +273,8 @@ def group_leave_reject_request(request, group_request_id):
|
|||||||
raise PermissionDenied
|
raise PermissionDenied
|
||||||
|
|
||||||
if group_request:
|
if group_request:
|
||||||
|
log = RequestLog(request_type=group_request.leave_request,group=group_request.group,request_info=group_request.__str__(),action=0,request_actor=request.user)
|
||||||
|
log.save()
|
||||||
group_request.delete()
|
group_request.delete()
|
||||||
logger.info("User %s rejected group leave request from user %s for group %s" % (
|
logger.info("User %s rejected group leave request from user %s for group %s" % (
|
||||||
request.user, group_request.user, group_request.group.name))
|
request.user, group_request.user, group_request.group.name))
|
||||||
@@ -262,7 +301,7 @@ 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 = []
|
groups = []
|
||||||
|
|
||||||
group_query = GroupManager.get_joinable_groups()
|
group_query = GroupManager.get_joinable_groups(request.user.profile.state)
|
||||||
|
|
||||||
if not request.user.has_perm('groupmanagement.request_groups'):
|
if not request.user.has_perm('groupmanagement.request_groups'):
|
||||||
# Filter down to public groups only for non-members
|
# Filter down to public groups only for non-members
|
||||||
@@ -284,11 +323,18 @@ def groups_view(request):
|
|||||||
def group_request_add(request, group_id):
|
def group_request_add(request, group_id):
|
||||||
logger.debug("group_request_add called by user %s for group id %s" % (request.user, group_id))
|
logger.debug("group_request_add called by user %s for group id %s" % (request.user, group_id))
|
||||||
group = Group.objects.get(id=group_id)
|
group = Group.objects.get(id=group_id)
|
||||||
if not GroupManager.joinable_group(group):
|
state = request.user.profile.state
|
||||||
|
if not GroupManager.joinable_group(group, state):
|
||||||
logger.warning("User %s attempted to join group id %s but it is not a joinable group" %
|
logger.warning("User %s attempted to join group id %s but it is not a joinable 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 in request.user.groups.all():
|
||||||
|
# User is already a member of this group.
|
||||||
|
logger.warning("User %s attempted to join group id %s but they are already a member." %
|
||||||
|
(request.user, group_id))
|
||||||
|
messages.warning(request, "You are already a member of that group.")
|
||||||
|
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" %
|
||||||
@@ -299,6 +345,11 @@ def group_request_add(request, group_id):
|
|||||||
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))
|
||||||
request.user.groups.add(group)
|
request.user.groups.add(group)
|
||||||
return redirect("groupmanagement:groups")
|
return redirect("groupmanagement:groups")
|
||||||
|
req = GroupRequest.objects.filter(user=request.user, group=group)
|
||||||
|
if len(req) > 0:
|
||||||
|
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.")
|
||||||
|
return redirect("groupmanagement:groups")
|
||||||
grouprequest = GroupRequest()
|
grouprequest = GroupRequest()
|
||||||
grouprequest.status = _('Pending')
|
grouprequest.status = _('Pending')
|
||||||
grouprequest.group = group
|
grouprequest.group = group
|
||||||
@@ -314,7 +365,7 @@ def group_request_add(request, group_id):
|
|||||||
def group_request_leave(request, group_id):
|
def group_request_leave(request, group_id):
|
||||||
logger.debug("group_request_leave called by user %s for group id %s" % (request.user, group_id))
|
logger.debug("group_request_leave called by user %s for group id %s" % (request.user, group_id))
|
||||||
group = Group.objects.get(id=group_id)
|
group = Group.objects.get(id=group_id)
|
||||||
if not GroupManager.joinable_group(group):
|
if not GroupManager.check_internal_group(group):
|
||||||
logger.warning("User %s attempted to leave group id %s but it is not a joinable group" %
|
logger.warning("User %s attempted to leave group id %s but it is not a joinable group" %
|
||||||
(request.user, group_id))
|
(request.user, group_id))
|
||||||
messages.warning(request, _("You cannot leave that group"))
|
messages.warning(request, _("You cannot leave that group"))
|
||||||
@@ -328,6 +379,15 @@ def group_request_leave(request, group_id):
|
|||||||
logger.info("%s leaving %s as is an open group" % (request.user, group))
|
logger.info("%s leaving %s as is an open group" % (request.user, group))
|
||||||
request.user.groups.remove(group)
|
request.user.groups.remove(group)
|
||||||
return redirect("groupmanagement:groups")
|
return redirect("groupmanagement:groups")
|
||||||
|
req = GroupRequest.objects.filter(user=request.user, group=group)
|
||||||
|
if len(req) > 0:
|
||||||
|
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.")
|
||||||
|
return redirect("groupmanagement:groups")
|
||||||
|
if getattr(settings, 'AUTO_LEAVE', False):
|
||||||
|
logger.info("%s leaving joinable group %s due to auto_leave" % (request.user, group))
|
||||||
|
request.user.groups.remove(group)
|
||||||
|
return redirect('groupmanagement:groups')
|
||||||
grouprequest = GroupRequest()
|
grouprequest = GroupRequest()
|
||||||
grouprequest.status = _('Pending')
|
grouprequest.status = _('Pending')
|
||||||
grouprequest.group = group
|
grouprequest.group = group
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
from allianceauth.services.hooks import MenuItemHook, UrlHook
|
from allianceauth.services.hooks import MenuItemHook, UrlHook
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from allianceauth import hooks
|
from allianceauth import hooks
|
||||||
from allianceauth.hrapplications import urls
|
from allianceauth.hrapplications import urls
|
||||||
|
|
||||||
@@ -7,7 +7,7 @@ from allianceauth.hrapplications import urls
|
|||||||
class ApplicationsMenu(MenuItemHook):
|
class ApplicationsMenu(MenuItemHook):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
MenuItemHook.__init__(self,
|
MenuItemHook.__init__(self,
|
||||||
'Applications',
|
_('Applications'),
|
||||||
'fa fa-file-o fa-fw',
|
'fa fa-file-o fa-fw',
|
||||||
'hrapplications:index',
|
'hrapplications:index',
|
||||||
navactive=['hrapplications:'])
|
navactive=['hrapplications:'])
|
||||||
|
|||||||
BIN
allianceauth/locale/de/LC_MESSAGES/django.mo
Normal file
BIN
allianceauth/locale/de/LC_MESSAGES/django.mo
Normal file
Binary file not shown.
File diff suppressed because it is too large
Load Diff
BIN
allianceauth/locale/es/LC_MESSAGES/django.mo
Normal file
BIN
allianceauth/locale/es/LC_MESSAGES/django.mo
Normal file
Binary file not shown.
2043
allianceauth/locale/es/LC_MESSAGES/django.po
Normal file
2043
allianceauth/locale/es/LC_MESSAGES/django.po
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,12 +1,12 @@
|
|||||||
from allianceauth.services.hooks import MenuItemHook, UrlHook
|
from allianceauth.services.hooks import MenuItemHook, UrlHook
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from allianceauth import hooks
|
from allianceauth import hooks
|
||||||
from . import urls
|
from . import urls
|
||||||
|
|
||||||
|
|
||||||
class OpTimerboardMenu(MenuItemHook):
|
class OpTimerboardMenu(MenuItemHook):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
MenuItemHook.__init__(self, 'Fleet Operations',
|
MenuItemHook.__init__(self, _('Fleet Operations'),
|
||||||
'fa fa-exclamation fa-fw',
|
'fa fa-exclamation fa-fw',
|
||||||
'optimer:view',
|
'optimer:view',
|
||||||
navactive=['optimer:'])
|
navactive=['optimer:'])
|
||||||
|
|||||||
@@ -19,7 +19,8 @@
|
|||||||
<div class="col-lg-12 text-center row">
|
<div class="col-lg-12 text-center row">
|
||||||
<div class="label label-info text-left">
|
<div class="label label-info text-left">
|
||||||
<b>{% trans "Current Eve Time:" %} </b>
|
<b>{% trans "Current Eve Time:" %} </b>
|
||||||
</div><div class="label label-info text-left" id="current-time"></div>
|
</div>
|
||||||
|
<strong class="label label-info text-left" id="current-time"></strong>
|
||||||
<br />
|
<br />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -111,7 +112,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function updateClock() {
|
function updateClock() {
|
||||||
document.getElementById("current-time").innerHTML = "<b>" + moment.utc().format('LLLL') + "</b>";
|
document.getElementById("current-time").innerHTML = getCurrentEveTimeString();
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
{% endblock content %}
|
{% endblock content %}
|
||||||
|
|||||||
@@ -82,6 +82,7 @@ ugettext = lambda s: s
|
|||||||
LANGUAGES = (
|
LANGUAGES = (
|
||||||
('en', ugettext('English')),
|
('en', ugettext('English')),
|
||||||
('de', ugettext('German')),
|
('de', ugettext('German')),
|
||||||
|
('es', ugettext('Spanish')),
|
||||||
)
|
)
|
||||||
|
|
||||||
TEMPLATES = [
|
TEMPLATES = [
|
||||||
@@ -193,6 +194,8 @@ LOGIN_TOKEN_SCOPES = ['publicData']
|
|||||||
# number of days email verification links are valid for
|
# number of days email verification links are valid for
|
||||||
ACCOUNT_ACTIVATION_DAYS = 1
|
ACCOUNT_ACTIVATION_DAYS = 1
|
||||||
|
|
||||||
|
ESI_API_URL = 'https://esi.evetech.net/'
|
||||||
|
|
||||||
LOGGING = {
|
LOGGING = {
|
||||||
'version': 1,
|
'version': 1,
|
||||||
'disable_existing_loggers': False,
|
'disable_existing_loggers': False,
|
||||||
|
|||||||
@@ -219,22 +219,18 @@ class DiscordOAuthManager:
|
|||||||
@staticmethod
|
@staticmethod
|
||||||
@api_backoff
|
@api_backoff
|
||||||
def update_nickname(user_id, nickname):
|
def update_nickname(user_id, nickname):
|
||||||
try:
|
nickname = DiscordOAuthManager._sanitize_name(nickname)
|
||||||
nickname = DiscordOAuthManager._sanitize_name(nickname)
|
custom_headers = {'content-type': 'application/json', 'authorization': 'Bot ' + settings.DISCORD_BOT_TOKEN}
|
||||||
custom_headers = {'content-type': 'application/json', 'authorization': 'Bot ' + settings.DISCORD_BOT_TOKEN}
|
data = {'nick': nickname}
|
||||||
data = {'nick': nickname}
|
path = DISCORD_URL + "/guilds/" + str(settings.DISCORD_GUILD_ID) + "/members/" + str(user_id)
|
||||||
path = DISCORD_URL + "/guilds/" + str(settings.DISCORD_GUILD_ID) + "/members/" + str(user_id)
|
r = requests.patch(path, headers=custom_headers, json=data)
|
||||||
r = requests.patch(path, headers=custom_headers, json=data)
|
logger.debug("Got status code %s after setting nickname for Discord user ID %s (%s)" % (
|
||||||
logger.debug("Got status code %s after setting nickname for Discord user ID %s (%s)" % (
|
r.status_code, user_id, nickname))
|
||||||
r.status_code, user_id, nickname))
|
if r.status_code == 404:
|
||||||
if r.status_code == 404:
|
logger.warn("Discord user ID %s could not be found in server." % user_id)
|
||||||
logger.warn("Discord user ID %s could not be found in server." % user_id)
|
|
||||||
return True
|
|
||||||
r.raise_for_status()
|
|
||||||
return True
|
return True
|
||||||
except:
|
r.raise_for_status()
|
||||||
logger.exception("Failed to set nickname for Discord user ID %s (%s)" % (user_id, nickname))
|
return True
|
||||||
return False
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def delete_user(user_id):
|
def delete_user(user_id):
|
||||||
|
|||||||
@@ -57,5 +57,5 @@ class Migration(migrations.Migration):
|
|||||||
name='discorduser',
|
name='discorduser',
|
||||||
options={'permissions': (('access_discord', 'Can access the Discord service'),)},
|
options={'permissions': (('access_discord', 'Can access the Discord service'),)},
|
||||||
),
|
),
|
||||||
migrations.RunPython(migrate_service_enabled),
|
migrations.RunPython(migrate_service_enabled, migrations.RunPython.noop),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -355,11 +355,14 @@ class DiscourseManager:
|
|||||||
user_groups = DiscourseManager.__get_user_groups(username)
|
user_groups = DiscourseManager.__get_user_groups(username)
|
||||||
add_groups = [group_dict[x] for x in group_dict if not group_dict[x] in user_groups]
|
add_groups = [group_dict[x] for x in group_dict if not group_dict[x] in user_groups]
|
||||||
rem_groups = [x for x in user_groups if x not in inv_group_dict]
|
rem_groups = [x for x in user_groups if x not in inv_group_dict]
|
||||||
if add_groups or rem_groups:
|
if add_groups:
|
||||||
logger.info(
|
logger.info(
|
||||||
"Updating discourse user %s groups: adding %s, removing %s" % (username, add_groups, rem_groups))
|
"Updating discourse user %s groups: adding %s" % (username, add_groups))
|
||||||
for g in add_groups:
|
for g in add_groups:
|
||||||
DiscourseManager.__add_user_to_group(g, username)
|
DiscourseManager.__add_user_to_group(g, username)
|
||||||
|
if rem_groups:
|
||||||
|
logger.info(
|
||||||
|
"Updating discourse user %s groups: removing %s" % (username, rem_groups))
|
||||||
for g in rem_groups:
|
for g in rem_groups:
|
||||||
DiscourseManager.__remove_user_from_group(g, username)
|
DiscourseManager.__remove_user_from_group(g, username)
|
||||||
|
|
||||||
|
|||||||
@@ -58,5 +58,5 @@ class Migration(migrations.Migration):
|
|||||||
name='discourseuser',
|
name='discourseuser',
|
||||||
options={'permissions': (('access_discourse', 'Can access the Discourse service'),)},
|
options={'permissions': (('access_discourse', 'Can access the Discourse service'),)},
|
||||||
),
|
),
|
||||||
migrations.RunPython(migrate_service_enabled),
|
migrations.RunPython(migrate_service_enabled, migrations.RunPython.noop),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
|
||||||
<td class="text-center">Discourse</td>
|
<tr>
|
||||||
<td class="text-center">{{ char.character_name }}</td>
|
<td class="text-center">Discourse</td>
|
||||||
<td class="text-center"><a href="{{ DISCOURSE_URL }}">{{ DISCOURSE_URL }}</a></td>
|
<td class="text-center">{{ char.character_name }}</td>
|
||||||
<td class="text-center">
|
<td class="text-center"><a href="{{ DISCOURSE_URL }}">{{ DISCOURSE_URL }}</a></td>
|
||||||
<a title="Go To Forums" class="btn btn-success" href="{{ DISCOURSE_URL }}"><span class="glyphicon glyphicon-arrow-right"></span></a>
|
<td class="text-center">
|
||||||
</td>
|
<a title="Go To Forums" class="btn btn-success" href="{{ DISCOURSE_URL }}"><span class="glyphicon glyphicon-arrow-right"></span></a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|||||||
@@ -57,5 +57,5 @@ class Migration(migrations.Migration):
|
|||||||
name='ips4user',
|
name='ips4user',
|
||||||
options={'permissions': (('access_ips4', 'Can access the IPS4 service'),)},
|
options={'permissions': (('access_ips4', 'Can access the IPS4 service'),)},
|
||||||
),
|
),
|
||||||
migrations.RunPython(migrate_service_enabled),
|
migrations.RunPython(migrate_service_enabled, migrations.RunPython.noop),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -57,5 +57,5 @@ class Migration(migrations.Migration):
|
|||||||
name='marketuser',
|
name='marketuser',
|
||||||
options={'permissions': (('access_market', 'Can access the Evernus Market service'),)},
|
options={'permissions': (('access_market', 'Can access the Evernus Market service'),)},
|
||||||
),
|
),
|
||||||
migrations.RunPython(migrate_service_enabled),
|
migrations.RunPython(migrate_service_enabled, migrations.RunPython.noop),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -57,5 +57,5 @@ class Migration(migrations.Migration):
|
|||||||
name='mumbleuser',
|
name='mumbleuser',
|
||||||
options={'permissions': (('access_mumble', 'Can access the Mumble service'),)},
|
options={'permissions': (('access_mumble', 'Can access the Mumble service'),)},
|
||||||
),
|
),
|
||||||
migrations.RunPython(migrate_service_enabled),
|
migrations.RunPython(migrate_service_enabled, migrations.RunPython.noop),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -57,5 +57,5 @@ class Migration(migrations.Migration):
|
|||||||
name='openfireuser',
|
name='openfireuser',
|
||||||
options={'permissions': (('access_openfire', 'Can access the Openfire service'),)},
|
options={'permissions': (('access_openfire', 'Can access the Openfire service'),)},
|
||||||
),
|
),
|
||||||
migrations.RunPython(migrate_service_enabled),
|
migrations.RunPython(migrate_service_enabled, migrations.RunPython.noop),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -57,5 +57,5 @@ class Migration(migrations.Migration):
|
|||||||
name='phpbb3user',
|
name='phpbb3user',
|
||||||
options={'permissions': (('access_phpbb3', 'Can access the phpBB3 service'),)},
|
options={'permissions': (('access_phpbb3', 'Can access the phpBB3 service'),)},
|
||||||
),
|
),
|
||||||
migrations.RunPython(migrate_service_enabled),
|
migrations.RunPython(migrate_service_enabled, migrations.RunPython.noop),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -57,5 +57,5 @@ class Migration(migrations.Migration):
|
|||||||
name='smfuser',
|
name='smfuser',
|
||||||
options={'permissions': (('access_smf', 'Can access the SMF service'),)},
|
options={'permissions': (('access_smf', 'Can access the SMF service'),)},
|
||||||
),
|
),
|
||||||
migrations.RunPython(migrate_service_enabled),
|
migrations.RunPython(migrate_service_enabled, migrations.RunPython.noop),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -67,6 +67,8 @@ class Teamspeak3Manager:
|
|||||||
group_cache = self.server.send_command('servergrouplist')
|
group_cache = self.server.send_command('servergrouplist')
|
||||||
logger.debug("Received group cache from server: %s" % group_cache)
|
logger.debug("Received group cache from server: %s" % group_cache)
|
||||||
for group in group_cache:
|
for group in group_cache:
|
||||||
|
if group['keys']['type'] != '1':
|
||||||
|
continue
|
||||||
logger.debug("Checking group %s" % group)
|
logger.debug("Checking group %s" % group)
|
||||||
if group['keys']['name'] == groupname:
|
if group['keys']['name'] == groupname:
|
||||||
logger.debug("Found group %s, returning id %s" % (groupname, group['keys']['sgid']))
|
logger.debug("Found group %s, returning id %s" % (groupname, group['keys']['sgid']))
|
||||||
@@ -124,6 +126,8 @@ class Teamspeak3Manager:
|
|||||||
outlist = {}
|
outlist = {}
|
||||||
if group_cache:
|
if group_cache:
|
||||||
for group in group_cache:
|
for group in group_cache:
|
||||||
|
if group['keys']['type'] != '1':
|
||||||
|
continue
|
||||||
logger.debug("Assigning name/id dict: %s = %s" % (group['keys']['name'], group['keys']['sgid']))
|
logger.debug("Assigning name/id dict: %s = %s" % (group['keys']['name'], group['keys']['sgid']))
|
||||||
outlist[group['keys']['name']] = group['keys']['sgid']
|
outlist[group['keys']['name']] = group['keys']['sgid']
|
||||||
else:
|
else:
|
||||||
@@ -179,18 +183,19 @@ class Teamspeak3Manager:
|
|||||||
except:
|
except:
|
||||||
logger.exception("An unhandled exception has occured while syncing TS groups.")
|
logger.exception("An unhandled exception has occured while syncing TS groups.")
|
||||||
|
|
||||||
def add_user(self, username):
|
def add_user(self, user, fmt_name):
|
||||||
username_clean = self.__santatize_username(username[:30])
|
username_clean = self.__santatize_username(fmt_name[:30])
|
||||||
logger.debug("Adding user to TS3 server with cleaned username %s" % username_clean)
|
logger.debug("Adding user to TS3 server with cleaned username %s" % username_clean)
|
||||||
server_groups = self._group_list()
|
server_groups = self._group_list()
|
||||||
|
|
||||||
if 'Member' not in server_groups:
|
state = user.profile.state.name
|
||||||
self._create_group('Member')
|
if state not in server_groups:
|
||||||
|
self._create_group(state)
|
||||||
|
|
||||||
alliance_group_id = self._group_id_by_name('Member')
|
state_group_id = self._group_id_by_name(state)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
ret = self.server.send_command('tokenadd', {'tokentype': 0, 'tokenid1': alliance_group_id, 'tokenid2': 0,
|
ret = self.server.send_command('tokenadd', {'tokentype': 0, 'tokenid1': state_group_id, 'tokenid2': 0,
|
||||||
'tokendescription': username_clean,
|
'tokendescription': username_clean,
|
||||||
'tokencustomset': "ident=sso_uid value=%s" % username_clean})
|
'tokencustomset': "ident=sso_uid value=%s" % username_clean})
|
||||||
except TeamspeakError as e:
|
except TeamspeakError as e:
|
||||||
@@ -213,7 +218,7 @@ class Teamspeak3Manager:
|
|||||||
if isinstance(clients, dict):
|
if isinstance(clients, dict):
|
||||||
# Rewrap list
|
# Rewrap list
|
||||||
clients = [clients]
|
clients = [clients]
|
||||||
|
|
||||||
for client in clients:
|
for client in clients:
|
||||||
try:
|
try:
|
||||||
if client['keys']['client_database_id'] == user:
|
if client['keys']['client_database_id'] == user:
|
||||||
@@ -244,10 +249,10 @@ class Teamspeak3Manager:
|
|||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def generate_new_permissionkey(self, uid, username):
|
def generate_new_permissionkey(self, uid, user, username):
|
||||||
logger.debug("Re-issuing permission key for user id %s" % uid)
|
logger.debug("Re-issuing permission key for user id %s" % uid)
|
||||||
self.delete_user(uid)
|
self.delete_user(uid)
|
||||||
return self.add_user(username)
|
return self.add_user(user, username)
|
||||||
|
|
||||||
def update_groups(self, uid, ts_groups):
|
def update_groups(self, uid, ts_groups):
|
||||||
logger.debug("Updating uid %s TS3 groups %s" % (uid, ts_groups))
|
logger.debug("Updating uid %s TS3 groups %s" % (uid, ts_groups))
|
||||||
|
|||||||
@@ -57,5 +57,5 @@ class Migration(migrations.Migration):
|
|||||||
name='teamspeak3user',
|
name='teamspeak3user',
|
||||||
options={'permissions': (('access_teamspeak3', 'Can access the Teamspeak3 service'),)},
|
options={'permissions': (('access_teamspeak3', 'Can access the Teamspeak3 service'),)},
|
||||||
),
|
),
|
||||||
migrations.RunPython(migrate_service_enabled),
|
migrations.RunPython(migrate_service_enabled, migrations.RunPython.noop),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ def activate_teamspeak3(request):
|
|||||||
character = request.user.profile.main_character
|
character = request.user.profile.main_character
|
||||||
with Teamspeak3Manager() as ts3man:
|
with Teamspeak3Manager() as ts3man:
|
||||||
logger.debug("Adding TS3 user for user %s with main character %s" % (request.user, character))
|
logger.debug("Adding TS3 user for user %s with main character %s" % (request.user, character))
|
||||||
result = ts3man.add_user(Teamspeak3Tasks.get_username(request.user))
|
result = ts3man.add_user(request.user, Teamspeak3Tasks.get_username(request.user))
|
||||||
|
|
||||||
# if its empty we failed
|
# if its empty we failed
|
||||||
if result[0] is not "":
|
if result[0] is not "":
|
||||||
@@ -79,13 +79,12 @@ def reset_teamspeak3_perm(request):
|
|||||||
logger.debug("reset_teamspeak3_perm called by user %s" % request.user)
|
logger.debug("reset_teamspeak3_perm called by user %s" % request.user)
|
||||||
if not Teamspeak3Tasks.has_account(request.user):
|
if not Teamspeak3Tasks.has_account(request.user):
|
||||||
return redirect("services:services")
|
return redirect("services:services")
|
||||||
character = request.user.profile.main_character
|
|
||||||
logger.debug("Deleting TS3 user for user %s" % request.user)
|
logger.debug("Deleting TS3 user for user %s" % request.user)
|
||||||
with Teamspeak3Manager() as ts3man:
|
with Teamspeak3Manager() as ts3man:
|
||||||
ts3man.delete_user(request.user.teamspeak3.uid)
|
ts3man.delete_user(request.user.teamspeak3.uid)
|
||||||
|
|
||||||
logger.debug("Generating new permission key for user %s with main character %s" % (request.user, character))
|
logger.debug("Generating new permission key for user %s" % request.user)
|
||||||
result = ts3man.generate_new_permissionkey(request.user.teamspeak3.uid, character.character_name)
|
result = ts3man.generate_new_permissionkey(request.user.teamspeak3.uid, request.user, Teamspeak3Tasks.get_username(request.user))
|
||||||
|
|
||||||
# if blank we failed
|
# if blank we failed
|
||||||
if result[0] != "":
|
if result[0] != "":
|
||||||
|
|||||||
@@ -57,5 +57,5 @@ class Migration(migrations.Migration):
|
|||||||
name='xenforouser',
|
name='xenforouser',
|
||||||
options={'permissions': (('access_xenforo', 'Can access the XenForo service'),)},
|
options={'permissions': (('access_xenforo', 'Can access the XenForo service'),)},
|
||||||
),
|
),
|
||||||
migrations.RunPython(migrate_service_enabled),
|
migrations.RunPython(migrate_service_enabled, migrations.RunPython.noop),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
from allianceauth.services.hooks import MenuItemHook, UrlHook
|
from allianceauth.services.hooks import MenuItemHook, UrlHook
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from allianceauth import hooks
|
from allianceauth import hooks
|
||||||
from . import urls
|
from . import urls
|
||||||
|
|
||||||
|
|
||||||
class SrpMenu(MenuItemHook):
|
class SrpMenu(MenuItemHook):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
MenuItemHook.__init__(self, 'Ship Replacement',
|
MenuItemHook.__init__(self, _('Ship Replacement'),
|
||||||
'fa fa-money fa-fw',
|
'fa fa-money fa-fw',
|
||||||
'srp:management',
|
'srp:management',
|
||||||
navactive=['srp:'])
|
navactive=['srp:'])
|
||||||
|
|||||||
@@ -1,9 +1,15 @@
|
|||||||
from allianceauth import NAME
|
from allianceauth import NAME
|
||||||
|
from esi.clients import esi_client_factory
|
||||||
import requests
|
import requests
|
||||||
import logging
|
import logging
|
||||||
|
import os
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
SWAGGER_SPEC_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'swagger.json')
|
||||||
|
"""
|
||||||
|
Swagger Operations:
|
||||||
|
get_killmails_killmail_id_killmail_hash
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
class SRPManager:
|
class SRPManager:
|
||||||
@@ -26,12 +32,20 @@ class SRPManager:
|
|||||||
r = requests.get(url, headers=headers)
|
r = requests.get(url, headers=headers)
|
||||||
result = r.json()[0]
|
result = r.json()[0]
|
||||||
if result:
|
if result:
|
||||||
ship_type = result['victim']['ship_type_id']
|
killmail_id = result['killmail_id']
|
||||||
|
killmail_hash = result['zkb']['hash']
|
||||||
|
c = esi_client_factory(spec_file=SWAGGER_SPEC_PATH)
|
||||||
|
km = c.Killmails.get_killmails_killmail_id_killmail_hash(killmail_id=killmail_id,
|
||||||
|
killmail_hash=killmail_hash).result()
|
||||||
|
else:
|
||||||
|
raise ValueError("Invalid Kill ID")
|
||||||
|
if km:
|
||||||
|
ship_type = km['victim']['ship_type_id']
|
||||||
logger.debug("Ship type for kill ID %s is %s" % (kill_id, ship_type))
|
logger.debug("Ship type for kill ID %s is %s" % (kill_id, ship_type))
|
||||||
ship_value = result['zkb']['totalValue']
|
ship_value = result['zkb']['totalValue']
|
||||||
logger.debug("Total loss value for kill id %s is %s" % (kill_id, ship_value))
|
logger.debug("Total loss value for kill id %s is %s" % (kill_id, ship_value))
|
||||||
victim_id = result['victim']['character_id']
|
victim_id = km['victim']['character_id']
|
||||||
return ship_type, ship_value, victim_id
|
return ship_type, ship_value, victim_id
|
||||||
else:
|
else:
|
||||||
raise ValueError("Invalid Kill ID")
|
raise ValueError("Invalid Kill ID or Hash.")
|
||||||
|
|
||||||
|
|||||||
1
allianceauth/srp/swagger.json
Normal file
1
allianceauth/srp/swagger.json
Normal file
File diff suppressed because one or more lines are too long
@@ -17,6 +17,8 @@
|
|||||||
<a href="{% url 'srp:all' %}" class="btn btn-primary">
|
<a href="{% url 'srp:all' %}" class="btn btn-primary">
|
||||||
{% trans "View All" %}
|
{% trans "View All" %}
|
||||||
</a>
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
{% if perms.srp.add_srpfleetmain or perms.auth.srp_management %}
|
||||||
<a href="{% url 'srp:add' %}" class="btn btn-success">
|
<a href="{% url 'srp:add' %}" class="btn btn-success">
|
||||||
{% trans "Add SRP Fleet" %}
|
{% trans "Add SRP Fleet" %}
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ 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 ugettext_lazy as _
|
||||||
from django.db.models import Sum
|
from django.db.models import Sum
|
||||||
|
from allianceauth.authentication.decorators import permissions_required
|
||||||
from allianceauth.eveonline.providers import provider
|
from allianceauth.eveonline.providers import provider
|
||||||
from allianceauth.notifications import notify
|
from allianceauth.notifications import notify
|
||||||
from .form import SrpFleetMainForm
|
from .form import SrpFleetMainForm
|
||||||
@@ -59,7 +60,7 @@ def srp_fleet_view(request, fleet_id):
|
|||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@permission_required('auth.srp_management')
|
@permissions_required(('auth.srp_management', 'srp.add_srpfleetmain'))
|
||||||
def srp_fleet_add_view(request):
|
def srp_fleet_add_view(request):
|
||||||
logger.debug("srp_fleet_add_view called by user %s" % request.user)
|
logger.debug("srp_fleet_add_view called by user %s" % request.user)
|
||||||
completed = False
|
completed = False
|
||||||
|
|||||||
@@ -8,8 +8,16 @@ function getDurationString(duration) {
|
|||||||
if (duration.years()) {
|
if (duration.years()) {
|
||||||
out += duration.years() + 'y ';
|
out += duration.years() + 'y ';
|
||||||
}
|
}
|
||||||
|
if (duration.months()) {
|
||||||
|
out += duration.months() + 'm ';
|
||||||
|
}
|
||||||
if (duration.days()) {
|
if (duration.days()) {
|
||||||
out += duration.days() + 'd ';
|
out += duration.days() + 'd ';
|
||||||
}
|
}
|
||||||
return out + duration.hours() + "h " + duration.minutes() + "m " + duration.seconds() + "s";
|
return out + duration.hours() + "h " + duration.minutes() + "m " + duration.seconds() + "s";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function getCurrentEveTimeString() {
|
||||||
|
return moment().utc().format('dddd LL HH:mm:ss')
|
||||||
|
}
|
||||||
|
|||||||
@@ -13,14 +13,14 @@
|
|||||||
{% else %}
|
{% else %}
|
||||||
<span class="label label-danger">{% trans "Closed" %}</span>
|
<span class="label label-danger">{% trans "Closed" %}</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<a href="{{ notif.html_url }}" target="_blank">#{{ notif.number }} {{ notif.title }}</a>
|
<a href="{{ notif.web_url }}" target="_blank">#{{ notif.number }} {{ notif.title }}</a>
|
||||||
</li>
|
</li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div class="text-right" style="position:absolute;bottom:5px;right:5px;">
|
<div class="text-right" style="position:absolute;bottom:5px;right:5px;">
|
||||||
<a href="https://github.com/allianceauth/allianceauth/issues"><span class="label label-default">
|
<a href="https://gitlab.com/allianceauth/allianceauth/issues"><span class="label" style="background-color:#e65328;">
|
||||||
<i class="fa fa-github" aria-hidden="true"></i> Powered by Github</span>
|
<i class="fa fa-gitlab" aria-hidden="true"></i> Powered by GitLab</span>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -39,7 +39,7 @@
|
|||||||
<li class="list-group-item list-group-item-{% if latest_major %}success{% else %}warning{% endif %}">
|
<li class="list-group-item list-group-item-{% if latest_major %}success{% else %}warning{% endif %}">
|
||||||
<h4 class="list-group-item-heading">{% trans "Latest Major" %}</h4>
|
<h4 class="list-group-item-heading">{% trans "Latest Major" %}</h4>
|
||||||
<p class="list-group-item-text">
|
<p class="list-group-item-text">
|
||||||
<a href="{{ latest_major_url }}" style="color:#000"><i class="fa fa-github" aria-hidden="true"></i>
|
<a href="https://gitlab.com/allianceauth/allianceauth/tags" style="color:#000"><i class="fa fa-gitlab" aria-hidden="true"></i>
|
||||||
{{ latest_major_version }}
|
{{ latest_major_version }}
|
||||||
</a>
|
</a>
|
||||||
{% if not latest_major %}<br>{% trans "Update available" %}{% endif %}
|
{% if not latest_major %}<br>{% trans "Update available" %}{% endif %}
|
||||||
@@ -48,7 +48,7 @@
|
|||||||
<li class="list-group-item list-group-item-{% if latest_minor %}success{% else %}warning{% endif %}">
|
<li class="list-group-item list-group-item-{% if latest_minor %}success{% else %}warning{% endif %}">
|
||||||
<h4 class="list-group-item-heading">{% trans "Latest Minor" %}</h4>
|
<h4 class="list-group-item-heading">{% trans "Latest Minor" %}</h4>
|
||||||
<p class="list-group-item-text">
|
<p class="list-group-item-text">
|
||||||
<a href="{{ latest_minor_url }}" style="color:#000"><i class="fa fa-github" aria-hidden="true"></i>
|
<a href="https://gitlab.com/allianceauth/allianceauth/tags" style="color:#000"><i class="fa fa-gitlab" aria-hidden="true"></i>
|
||||||
{{ latest_minor_version }}
|
{{ latest_minor_version }}
|
||||||
</a>
|
</a>
|
||||||
{% if not latest_minor %}<br>{% trans "Update available" %}{% endif %}
|
{% if not latest_minor %}<br>{% trans "Update available" %}{% endif %}
|
||||||
@@ -57,7 +57,7 @@
|
|||||||
<li class="list-group-item list-group-item-{% if latest_patch %}success{% else %}danger{% endif %}">
|
<li class="list-group-item list-group-item-{% if latest_patch %}success{% else %}danger{% endif %}">
|
||||||
<h4 class="list-group-item-heading">{% trans "Latest Patch" %}</h4>
|
<h4 class="list-group-item-heading">{% trans "Latest Patch" %}</h4>
|
||||||
<p class="list-group-item-text">
|
<p class="list-group-item-text">
|
||||||
<a href="{{ latest_patch_url }}" style="color:#000"><i class="fa fa-github" aria-hidden="true"></i>
|
<a href="https://gitlab.com/allianceauth/allianceauth/tags" style="color:#000"><i class="fa fa-gitlab" aria-hidden="true"></i>
|
||||||
{{ latest_patch_version }}
|
{{ latest_patch_version }}
|
||||||
</a>
|
</a>
|
||||||
{% if not latest_patch %}<br>{% trans "Update available" %}{% endif %}
|
{% if not latest_patch %}<br>{% trans "Update available" %}{% endif %}
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
{% extends "allianceauth/base.html" %}
|
{% extends "allianceauth/base.html" %}
|
||||||
|
{% load i18n %}
|
||||||
|
|
||||||
{% block page_title %}Help{% endblock page_title %}
|
{% block page_title %}{% trans "Help" %}{% endblock page_title %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="col-lg-12">
|
<div class="col-lg-12">
|
||||||
|
|
||||||
<h1 class="page-header text-center">Help</h1>
|
<h1 class="page-header text-center">{% trans "Help" %}</h1>
|
||||||
|
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<div class="embed-responsive embed-responsive-16by9">
|
<div class="embed-responsive embed-responsive-16by9">
|
||||||
|
|||||||
@@ -7,12 +7,12 @@
|
|||||||
<li>
|
<li>
|
||||||
<a class="{% navactive request 'authentication:dashboard' %}"
|
<a class="{% navactive request 'authentication:dashboard' %}"
|
||||||
href="{% url 'authentication:dashboard' %}">
|
href="{% url 'authentication:dashboard' %}">
|
||||||
<i class="fa fa-dashboard fa-fw"></i>{% trans " Dashboard" %}
|
<i class="fa fa-dashboard fa-fw"></i> {% trans "Dashboard" %}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a class="{% navactive request 'groupmanagement:groups' %}" href="{% url 'groupmanagement:groups' %}">
|
<a class="{% navactive request 'groupmanagement:groups' %}" href="{% url 'groupmanagement:groups' %}">
|
||||||
<i class="fa fa-cogs fa-fw fa-sitemap"></i>{% trans " Groups" %}
|
<i class="fa fa-cogs fa-fw fa-sitemap"></i> {% trans "Groups" %}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
@@ -20,7 +20,7 @@
|
|||||||
<li>
|
<li>
|
||||||
<a class="{% navactive request 'groupmanagement:management groupmanagement:membership groupmanagement:membership_list' %}"
|
<a class="{% navactive request 'groupmanagement:management groupmanagement:membership groupmanagement:membership_list' %}"
|
||||||
href="{% url 'groupmanagement:management' %}">
|
href="{% url 'groupmanagement:management' %}">
|
||||||
<i class="fa fa-lock fa-sitemap fa-fw"></i>{% trans " Group Management" %}
|
<i class="fa fa-lock fa-sitemap fa-fw"></i> {% trans "Group Management" %}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@@ -30,7 +30,7 @@
|
|||||||
<li>
|
<li>
|
||||||
<a class="{% navactive request 'authentication:help' %}"
|
<a class="{% navactive request 'authentication:help' %}"
|
||||||
href="{% url 'authentication:help' %}">
|
href="{% url 'authentication:help' %}">
|
||||||
<i class="fa fa-question fa-fw"></i>{% trans " Help" %}
|
<i class="fa fa-question fa-fw"></i> {% trans "Help" %}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.17.1/moment.min.js"></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.22.1/moment.min.js"></script>
|
||||||
{% if locale and LANGUAGE_CODE != 'en' %}
|
{% if locale and LANGUAGE_CODE != 'en' %}
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.17.1/locale/{{ LANGUAGE_CODE }}.js"></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.22.1/locale/{{ LANGUAGE_CODE }}.js"></script>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|||||||
@@ -17,16 +17,16 @@ NOTIFICATION_CACHE_TIME = 300 # 5 minutes
|
|||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
def get_github_tags():
|
def get_git_tags():
|
||||||
request = requests.get('https://api.github.com/repos/allianceauth/allianceauth/releases')
|
request = requests.get('https://gitlab.com/api/v4/projects/allianceauth%2Fallianceauth/repository/tags')
|
||||||
request.raise_for_status()
|
request.raise_for_status()
|
||||||
return request.json()
|
return request.json()
|
||||||
|
|
||||||
|
|
||||||
def get_github_notification_issues():
|
def get_notification_issues():
|
||||||
# notification
|
# notification
|
||||||
request = requests.get(
|
request = requests.get(
|
||||||
'https://api.github.com/repos/allianceauth/allianceauth/issues?labels=announcement&state=all')
|
'https://gitlab.com/api/v4/projects/allianceauth%2Fallianceauth/issues?labels=announcement')
|
||||||
request.raise_for_status()
|
request.raise_for_status()
|
||||||
return request.json()
|
return request.json()
|
||||||
|
|
||||||
@@ -68,10 +68,10 @@ def get_notifications():
|
|||||||
'notifications': list(),
|
'notifications': list(),
|
||||||
}
|
}
|
||||||
try:
|
try:
|
||||||
notifications = cache.get_or_set('github_notification_issues', get_github_notification_issues,
|
notifications = cache.get_or_set('gitlab_notification_issues', get_notification_issues,
|
||||||
NOTIFICATION_CACHE_TIME)
|
NOTIFICATION_CACHE_TIME)
|
||||||
# Limit notifications to those posted by repo owners and members
|
# Limit notifications to those posted by repo owners and members
|
||||||
response['notifications'] += [n for n in notifications if n['author_association'] in ['OWNER', 'MEMBER']][:5]
|
response['notifications'] += notifications[:5]
|
||||||
except requests.RequestException:
|
except requests.RequestException:
|
||||||
logger.exception('Error while getting github notifications')
|
logger.exception('Error while getting github notifications')
|
||||||
return response
|
return response
|
||||||
@@ -85,7 +85,7 @@ def get_version_info():
|
|||||||
'current_version': __version__,
|
'current_version': __version__,
|
||||||
}
|
}
|
||||||
try:
|
try:
|
||||||
tags = cache.get_or_set('github_release_tags', get_github_tags, TAG_CACHE_TIME)
|
tags = cache.get_or_set('git_release_tags', get_git_tags, TAG_CACHE_TIME)
|
||||||
current_ver = semver.Version.coerce(__version__)
|
current_ver = semver.Version.coerce(__version__)
|
||||||
|
|
||||||
# Set them all to the current version to start
|
# Set them all to the current version to start
|
||||||
@@ -102,7 +102,7 @@ def get_version_info():
|
|||||||
})
|
})
|
||||||
|
|
||||||
for tag in tags:
|
for tag in tags:
|
||||||
tag_name = tag.get('tag_name')
|
tag_name = tag.get('name')
|
||||||
if tag_name[0] == 'v':
|
if tag_name[0] == 'v':
|
||||||
# Strip 'v' off front of verison if it exists
|
# Strip 'v' off front of verison if it exists
|
||||||
tag_name = tag_name[1:]
|
tag_name = tag_name[1:]
|
||||||
@@ -114,24 +114,21 @@ def get_version_info():
|
|||||||
if latest_major is None or tag_ver > latest_major:
|
if latest_major is None or tag_ver > latest_major:
|
||||||
latest_major = tag_ver
|
latest_major = tag_ver
|
||||||
response['latest_major_version'] = tag_name
|
response['latest_major_version'] = tag_name
|
||||||
response['latest_major_url'] = tag['html_url']
|
|
||||||
if tag_ver.major > current_ver.major:
|
if tag_ver.major > current_ver.major:
|
||||||
response['latest_major'] = False
|
response['latest_major'] = False
|
||||||
elif tag_ver.major == current_ver.major:
|
elif tag_ver.major == current_ver.major:
|
||||||
if latest_minor is None or tag_ver > latest_minor:
|
if latest_minor is None or tag_ver > latest_minor:
|
||||||
latest_minor = tag_ver
|
latest_minor = tag_ver
|
||||||
response['latest_minor_version'] = tag_name
|
response['latest_minor_version'] = tag_name
|
||||||
response['latest_minor_url'] = tag['html_url']
|
|
||||||
if tag_ver.minor > current_ver.minor:
|
if tag_ver.minor > current_ver.minor:
|
||||||
response['latest_minor'] = False
|
response['latest_minor'] = False
|
||||||
elif tag_ver.minor == current_ver.minor:
|
elif tag_ver.minor == current_ver.minor:
|
||||||
if latest_patch is None or tag_ver > latest_patch:
|
if latest_patch is None or tag_ver > latest_patch:
|
||||||
latest_patch = tag_ver
|
latest_patch = tag_ver
|
||||||
response['latest_patch_version'] = tag_name
|
response['latest_patch_version'] = tag_name
|
||||||
response['latest_patch_url'] = tag['html_url']
|
|
||||||
if tag_ver.patch > current_ver.patch:
|
if tag_ver.patch > current_ver.patch:
|
||||||
response['latest_patch'] = False
|
response['latest_patch'] = False
|
||||||
|
|
||||||
except requests.RequestException:
|
except requests.RequestException:
|
||||||
logger.exception('Error while getting github release tags')
|
logger.exception('Error while getting gitlab release tags')
|
||||||
return response
|
return response
|
||||||
|
|||||||
@@ -18,7 +18,8 @@
|
|||||||
<div class="col-lg-12 text-center">
|
<div class="col-lg-12 text-center">
|
||||||
<div class="label label-info text-left">
|
<div class="label label-info text-left">
|
||||||
<b>{% trans "Current Eve Time:" %} </b>
|
<b>{% trans "Current Eve Time:" %} </b>
|
||||||
</div><div class="label label-info text-left" id="current-time"></div>
|
</div>
|
||||||
|
<strong class="label label-info text-left" id="current-time"></strong>
|
||||||
</div>
|
</div>
|
||||||
{% if corp_timers %}
|
{% if corp_timers %}
|
||||||
<h4><b>{% trans "Corp Timers" %}</b></h4>
|
<h4><b>{% trans "Corp Timers" %}</b></h4>
|
||||||
@@ -555,7 +556,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function updateClock() {
|
function updateClock() {
|
||||||
document.getElementById("current-time").innerHTML = "<b>" + moment().format('LLLL') + "</b>";
|
document.getElementById("current-time").innerHTML = getCurrentEveTimeString();
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
{% endblock content %}
|
{% endblock content %}
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ Ubuntu:
|
|||||||
|
|
||||||
CentOS:
|
CentOS:
|
||||||
|
|
||||||
yum install mariadb-server mariadb-devel mariadb
|
yum install mariadb-server mariadb-devel mariadb-shared mariadb
|
||||||
|
|
||||||
```eval_rst
|
```eval_rst
|
||||||
.. note::
|
.. note::
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ Mumble ships with a configuration file that needs customization. By default it
|
|||||||
REQUIRED: To enable the ICE authenticator, edit the following:
|
REQUIRED: To enable the ICE authenticator, edit the following:
|
||||||
|
|
||||||
- `icesecretwrite=MY_CLEVER_PASSWORD`, obviously choosing a secure password
|
- `icesecretwrite=MY_CLEVER_PASSWORD`, obviously choosing a secure password
|
||||||
|
- ensure the line containing `Ice="tcp -h 127.0.0.1 -p 6502"` is uncommented
|
||||||
|
|
||||||
By default mumble operates on SQLite which is fine, but slower than a dedicated MySQL server. To customize the database, edit the following:
|
By default mumble operates on SQLite which is fine, but slower than a dedicated MySQL server. To customize the database, edit the following:
|
||||||
|
|
||||||
@@ -46,7 +47,7 @@ By default mumble operates on SQLite which is fine, but slower than a dedicated
|
|||||||
|
|
||||||
To name your root channel, uncomment and set `registerName=` to whatever cool name you want
|
To name your root channel, uncomment and set `registerName=` to whatever cool name you want
|
||||||
|
|
||||||
Save and close the file (control + O, control + X).
|
Save and close the file.
|
||||||
|
|
||||||
To get Mumble superuser account credentials, run the following:
|
To get Mumble superuser account credentials, run the following:
|
||||||
|
|
||||||
@@ -80,7 +81,21 @@ Test your configuration by starting it: `python authenticator.py`
|
|||||||
|
|
||||||
## Running the Authenticator
|
## Running the Authenticator
|
||||||
|
|
||||||
The authenticator needs to be running 24/7 to validate users on Mumble. You should check the [supervisor docs](../auth/supervisor.md) on how to achieve this.
|
The authenticator needs to be running 24/7 to validate users on Mumble. This can be achieved by adding a section to your auth project's supervisor config file like the following example:
|
||||||
|
|
||||||
|
```
|
||||||
|
[program:authenticator]
|
||||||
|
command=/path/to/venv/bin/python authenticator.py
|
||||||
|
directory=/path/to/authenticator/directory/
|
||||||
|
user=allianceserver
|
||||||
|
stdout_logfile=/path/to/authenticator/directory/authenticator.log
|
||||||
|
stderr_logfile=/path/to/authenticator/directory/authenticator.log
|
||||||
|
autostart=true
|
||||||
|
autorestart=true
|
||||||
|
startsecs=10
|
||||||
|
priority=998
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
Note that groups will only be created on Mumble automatically when a user joins who is in the group.
|
Note that groups will only be created on Mumble automatically when a user joins who is in the group.
|
||||||
|
|
||||||
|
|||||||
4
setup.py
4
setup.py
@@ -16,12 +16,12 @@ install_requires = [
|
|||||||
'celery>=4.0.2',
|
'celery>=4.0.2',
|
||||||
'celery_once',
|
'celery_once',
|
||||||
|
|
||||||
'django>=1.11',
|
'django>=1.11,<=2.0.8',
|
||||||
'django-bootstrap-form',
|
'django-bootstrap-form',
|
||||||
'django-registration==2.4',
|
'django-registration==2.4',
|
||||||
'django-sortedm2m',
|
'django-sortedm2m',
|
||||||
'django-redis-cache>=1.7.1',
|
'django-redis-cache>=1.7.1',
|
||||||
'django-celery-beat',
|
'django-celery-beat<=1.1.1',
|
||||||
|
|
||||||
'openfire-restapi',
|
'openfire-restapi',
|
||||||
'sleekxmpp',
|
'sleekxmpp',
|
||||||
|
|||||||
4
tox.ini
4
tox.ini
@@ -17,4 +17,6 @@ deps=
|
|||||||
py37: https://github.com/yaml/pyyaml/zipball/master#egg=pyyaml
|
py37: https://github.com/yaml/pyyaml/zipball/master#egg=pyyaml
|
||||||
py37: https://github.com/celery/kombu/zipball/master#egg=kombu
|
py37: https://github.com/celery/kombu/zipball/master#egg=kombu
|
||||||
install_command = pip install -e ".[testing]" -U {opts} {packages}
|
install_command = pip install -e ".[testing]" -U {opts} {packages}
|
||||||
commands=coverage run runtests.py -v 2
|
commands =
|
||||||
|
coverage run runtests.py -v 2
|
||||||
|
coverage report -m
|
||||||
|
|||||||
Reference in New Issue
Block a user