mirror of
https://gitlab.com/allianceauth/allianceauth.git
synced 2026-02-04 14:16:21 +01:00
Compare commits
124 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
aecc94bdb3 | ||
|
|
fcb7f2905a | ||
|
|
34c7169ca3 | ||
|
|
6e450061f4 | ||
|
|
fc3d7e9f43 | ||
|
|
514db4f9a2 | ||
|
|
23a8b65ce2 | ||
|
|
f8e6662bc8 | ||
|
|
89be2456fb | ||
|
|
bfd3451717 | ||
|
|
0b759d6a32 | ||
|
|
65e05084e6 | ||
|
|
f25a4ed386 | ||
|
|
b2a1d41829 | ||
|
|
2741a92d31 | ||
|
|
3570ce86d7 | ||
|
|
d809902d1e | ||
|
|
ec4232c00a | ||
|
|
dec793bfac | ||
|
|
fe3fe0527a | ||
|
|
a8855e86ed | ||
|
|
179d1c38e6 | ||
|
|
287da73a4f | ||
|
|
e9ed917888 | ||
|
|
70d842c971 | ||
|
|
bcda228e05 | ||
|
|
000dafc5e6 | ||
|
|
4ea824fe71 | ||
|
|
f72f539516 | ||
|
|
1b192a184f | ||
|
|
0edf896b4c | ||
|
|
7dec4deb70 | ||
|
|
d511221899 | ||
|
|
d2b7de5221 | ||
|
|
79c5be02e2 | ||
|
|
09df37438d | ||
|
|
8561e4c6fd | ||
|
|
976cb4d988 | ||
|
|
20f7d5103c | ||
|
|
d049ec2832 | ||
|
|
00fe2a527e | ||
|
|
f53ec3b43e | ||
|
|
4d0417f114 | ||
|
|
00903b64db | ||
|
|
a3038cad00 | ||
|
|
ef99f1afac | ||
|
|
cc00d4bd04 | ||
|
|
250f26ff6f | ||
|
|
62b786ca4a | ||
|
|
9cfb47e658 | ||
|
|
ccef27b637 | ||
|
|
8dee61fd39 | ||
|
|
ae64bd0e19 | ||
|
|
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 |
5
.gitignore
vendored
5
.gitignore
vendored
@@ -42,7 +42,6 @@ nosetests.xml
|
||||
coverage.xml
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
*.pot
|
||||
|
||||
# Django stuff:
|
||||
@@ -63,3 +62,7 @@ celerybeat-schedule
|
||||
|
||||
#pycharm
|
||||
.idea/*
|
||||
/nbproject/
|
||||
|
||||
#gitlab configs
|
||||
.gitlab/
|
||||
|
||||
33
.gitlab-ci.yml
Normal file
33
.gitlab-ci.yml
Normal file
@@ -0,0 +1,33 @@
|
||||
# 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-dj20:
|
||||
<<: *job_definition
|
||||
image: python:3.6-stretch
|
||||
script:
|
||||
- export TOXENV=py36-dj20
|
||||
- tox
|
||||
14
.gitlab/issue_templates/Bug.md
Normal file
14
.gitlab/issue_templates/Bug.md
Normal file
@@ -0,0 +1,14 @@
|
||||
# Bug
|
||||
|
||||
- I have searched [issues](https://gitlab.com/allianceauth/allianceauth/issues?scope=all&utf8=%E2%9C%93&state=all) (Y/N):
|
||||
- What Version of Alliance Auth:
|
||||
- What Operating System:
|
||||
- Version of other components relevant to issue eg. Service, Database:
|
||||
|
||||
Please include a brief description of your issue here.
|
||||
|
||||
Please include steps to reproduce the issue
|
||||
|
||||
Please include any tracebacks or logs
|
||||
|
||||
Please include the results of the command `pip list`
|
||||
7
.gitlab/issue_templates/Feature Request.md
Normal file
7
.gitlab/issue_templates/Feature Request.md
Normal file
@@ -0,0 +1,7 @@
|
||||
# Feature Request
|
||||
|
||||
- Describe the feature are you requesting.
|
||||
|
||||
- Is this a Service (external integration), a Module (Alliance Auth extension) or an enhancement to an existing service/module.
|
||||
|
||||
- Describe why its useful to you or others.
|
||||
21
README.md
21
README.md
@@ -1,28 +1,31 @@
|
||||
Alliance Auth
|
||||
============
|
||||
|
||||
[](https://gitter.im/R4stl1n/allianceauth?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
[](https://discord.gg/fjnHAmk)
|
||||
[](http://allianceauth.readthedocs.io/?badge=latest)
|
||||
[](https://travis-ci.org/allianceauth/allianceauth)
|
||||
[](https://coveralls.io/github/allianceauth/allianceauth?branch=master)
|
||||
[](https://gitlab.com/allianceauth/allianceauth/commits/master)
|
||||
[](https://gitlab.com/allianceauth/allianceauth/commits/master)
|
||||
|
||||
|
||||
|
||||
An auth system for EVE Online to help in-game organizations manage online service access.
|
||||
|
||||
[Read the docs here.](http://allianceauth.rtfd.io)
|
||||
|
||||
[Get help on gitter](https://gitter.im/R4stl1n/allianceauth) or submit an Issue.
|
||||
[Get help on Discord](https://discord.gg/fjnHAmk) or submit an Issue.
|
||||
|
||||
|
||||
Active Developers:
|
||||
|
||||
- [Adarnof](https://github.com/adarnof/)
|
||||
- [Basraah](https://github.com/basraah/)
|
||||
- [Adarnof](https://gitlab.com/adarnof/)
|
||||
- [Basraah](https://gitlab.com/basraah/)
|
||||
- [Ariel Rin](https://gitlab.com/soratidus999/)
|
||||
- [Col Crunch](https://gitlab.com/colcrunch/)
|
||||
|
||||
Beta Testers / Bug Fixers:
|
||||
|
||||
- [ghoti](https://github.com/ghoti/)
|
||||
- [mmolitor87](https://github.com/mmolitor87/)
|
||||
- [ghoti](https://gitlab.com/ChainsawMcGinny/)
|
||||
- [mmolitor87](https://gitlab.com/mmolitor87/)
|
||||
- [TargetZ3R0](https://github.com/TargetZ3R0)
|
||||
- [kaezon](https://github.com/kaezon/)
|
||||
- [orbitroom](https://github.com/orbitroom/)
|
||||
@@ -31,4 +34,4 @@ Beta Testers / Bug Fixers:
|
||||
Special thanks to [Nikdoof](https://github.com/nikdoof/), as his [auth](https://github.com/nikdoof/test-auth) was the foundation for the original work on this project.
|
||||
|
||||
### Contributing
|
||||
Make sure you have signed the [License Agreement](https://developers.eveonline.com/resource/license-agreement) by logging in at [https://developers.eveonline.com](https://developers.eveonline.com) before submitting any pull requests.
|
||||
Make sure you have signed the [License Agreement](https://developers.eveonline.com/resource/license-agreement) by logging in at [https://developers.eveonline.com](https://developers.eveonline.com) before submitting any pull requests.
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
# This will make sure the app is always imported when
|
||||
# Django starts so that shared_task will use this app.
|
||||
|
||||
__version__ = '2.0.0'
|
||||
__version__ = '2.2.1'
|
||||
NAME = 'Alliance Auth v%s' % __version__
|
||||
default_app_config = 'allianceauth.apps.AllianceAuthConfig'
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ class StateBackend(ModelBackend):
|
||||
user_obj._perm_cache.update(self.get_state_permissions(user_obj))
|
||||
return user_obj._perm_cache
|
||||
|
||||
def authenticate(self, token=None):
|
||||
def authenticate(self, request=None, token=None, **credentials):
|
||||
if not token:
|
||||
return None
|
||||
try:
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
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 django.shortcuts import redirect
|
||||
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.'))
|
||||
return redirect('authentication:dashboard')
|
||||
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')
|
||||
|
||||
try:
|
||||
g = Group.objects.get(name=member_state_name)
|
||||
g, _ = Group.objects.get_or_create(name=member_state_name)
|
||||
# move permissions back
|
||||
state = State.objects.get(name=member_state_name)
|
||||
[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
|
||||
for profile in state.userprofile_set.all().select_related('user'):
|
||||
profile.user.groups.add(g.pk)
|
||||
except (Group.DoesNotExist, State.DoesNotExist):
|
||||
except State.DoesNotExist:
|
||||
pass
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ def create_blue_state(apps, schema_editor):
|
||||
# move group permissions to state
|
||||
g = Group.objects.get(name=blue_state_name)
|
||||
[s.permissions.add(p.pk) for p in g.permissions.all()]
|
||||
g.permissions.clear()
|
||||
g.delete()
|
||||
except Group.DoesNotExist:
|
||||
pass
|
||||
|
||||
@@ -84,7 +84,7 @@ def create_blue_group(apps, schema_editor):
|
||||
blue_state_name = getattr(settings, 'DEFAULT_BLUE_GROUP', 'Blue')
|
||||
|
||||
try:
|
||||
g = Group.objects.get(name=blue_state_name)
|
||||
g, _ = Group.objects.get_or_create(name=blue_state_name)
|
||||
# move permissions back
|
||||
state = State.objects.get(name=blue_state_name)
|
||||
[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
|
||||
for profile in state.userprofile_set.all().select_related('user'):
|
||||
profile.user.groups.add(g.pk)
|
||||
except (Group.DoesNotExist, State.DoesNotExist):
|
||||
except State.DoesNotExist:
|
||||
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()]
|
||||
|
||||
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:
|
||||
# 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)
|
||||
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'):
|
||||
# prepare empty profiles
|
||||
state = State.objects.get(name='Guest')
|
||||
UserProfile.objects.create(user=auth.user, state=state)
|
||||
UserProfile.objects.create(user=auth.user, state=guest_state)
|
||||
|
||||
|
||||
def recreate_authservicesinfo(apps, schema_editor):
|
||||
@@ -149,6 +158,14 @@ def recreate_authservicesinfo(apps, schema_editor):
|
||||
UserProfile = apps.get_model('authentication', 'UserProfile')
|
||||
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
|
||||
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
|
||||
for profile in UserProfile.objects.exclude(state__name='Guest').filter(
|
||||
state__name__in=['Member', 'Blue']).select_related('user', 'state'):
|
||||
AuthServicesInfo.objects.update_or_create(user=profile.user, defaults={'state': profile.state.name})
|
||||
state__name__in=[member_state_name, blue_state_name]).select_related('user', 'state'):
|
||||
AuthServicesInfo.objects.update_or_create(user=profile.user, defaults={'state': states[profile.state.name]})
|
||||
|
||||
|
||||
def disable_passwords(apps, schema_editor):
|
||||
|
||||
@@ -103,12 +103,16 @@ def record_character_ownership(sender, instance, created, *args, **kwargs):
|
||||
|
||||
@receiver(pre_delete, sender=CharacterOwnership)
|
||||
def validate_main_character(sender, instance, *args, **kwargs):
|
||||
if instance.user.profile.main_character == instance.character:
|
||||
logger.info("Ownership of a main character {0} has been revoked. Resetting {1} main character.".format(
|
||||
instance.character, instance.user))
|
||||
# clear main character as user no longer owns them
|
||||
instance.user.profile.main_character = None
|
||||
instance.user.profile.save()
|
||||
try:
|
||||
if instance.user.profile.main_character == instance.character:
|
||||
logger.info("Ownership of a main character {0} has been revoked. Resetting {1} main character.".format(
|
||||
instance.character, instance.user))
|
||||
# clear main character as user no longer owns them
|
||||
instance.user.profile.main_character = None
|
||||
instance.user.profile.save()
|
||||
except UserProfile.DoesNotExist:
|
||||
# a user is being deleted
|
||||
pass
|
||||
|
||||
|
||||
@receiver(post_delete, sender=Token)
|
||||
|
||||
@@ -119,7 +119,7 @@ class BackendTestCase(TestCase):
|
||||
def test_authenticate_character_record(self):
|
||||
t = Token(character_id=self.unclaimed_character.character_id, character_name=self.unclaimed_character.character_name, character_owner_hash='4')
|
||||
record = OwnershipRecord.objects.create(user=self.old_user, character=self.unclaimed_character, owner_hash='4')
|
||||
user = StateBackend().authenticate(t)
|
||||
user = StateBackend().authenticate(token=t)
|
||||
self.assertEqual(user, self.old_user)
|
||||
self.assertTrue(CharacterOwnership.objects.filter(owner_hash='4', user=self.old_user).exists())
|
||||
self.assertTrue(user.profile.main_character)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
from allianceauth.services.hooks import MenuItemHook, UrlHook
|
||||
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from allianceauth import hooks
|
||||
from allianceauth.corputils import urls
|
||||
|
||||
@@ -7,7 +7,7 @@ from allianceauth.corputils import urls
|
||||
class CorpStats(MenuItemHook):
|
||||
def __init__(self):
|
||||
MenuItemHook.__init__(self,
|
||||
'Corporation Stats',
|
||||
_('Corporation Stats'),
|
||||
'fa fa-share-alt fa-fw',
|
||||
'corputils:view',
|
||||
navactive=['corputils:'])
|
||||
|
||||
@@ -16,10 +16,16 @@ class CorpStatsQuerySet(models.QuerySet):
|
||||
assert char
|
||||
# build all accepted queries
|
||||
queries = [models.Q(token__user=user)]
|
||||
if user.has_perm('corputils.view_corp_corpstats'):
|
||||
queries.append(models.Q(corp__corporation_id=char.corporation_id))
|
||||
if user.has_perm('corputils.view_alliance_corpstats'):
|
||||
queries.append(models.Q(corp__alliance__alliance_id=char.alliance_id))
|
||||
if char.alliance_id is not None:
|
||||
queries.append(models.Q(corp__alliance__alliance_id=char.alliance_id))
|
||||
else:
|
||||
queries.append(models.Q(corp__corporation_id=char.corporation_id))
|
||||
if user.has_perm('corputils.view_corp_corpstats'):
|
||||
if user.has_perm('corputils.view_alliance_corpstats'):
|
||||
pass
|
||||
else:
|
||||
queries.append(models.Q(corp__corporation_id=char.corporation_id))
|
||||
if user.has_perm('corputils.view_state_corpstats'):
|
||||
queries.append(models.Q(corp__in=user.profile.state.member_corporations.all()))
|
||||
queries.append(models.Q(corp__alliance__in=user.profile.state.member_alliances.all()))
|
||||
|
||||
@@ -12,6 +12,16 @@ from allianceauth.notifications import notify
|
||||
from allianceauth.corputils.managers import CorpStatsManager
|
||||
|
||||
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__)
|
||||
|
||||
@@ -47,11 +57,11 @@ class CorpStats(models.Model):
|
||||
# the swagger spec doesn't have a maxItems count
|
||||
# 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_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_list = {}
|
||||
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
|
||||
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
|
||||
class="ra-avatar" src="{{ corpstats.corp.logo_url_128 }}"></td>
|
||||
{% 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>
|
||||
{% endif %}
|
||||
</tr>
|
||||
@@ -202,4 +202,4 @@
|
||||
});
|
||||
|
||||
});
|
||||
{% endblock %}
|
||||
{% endblock %}
|
||||
|
||||
@@ -86,7 +86,7 @@ class CorpStatsUpdateTestCase(TestCase):
|
||||
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.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.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)
|
||||
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.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.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
|
||||
|
||||
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):
|
||||
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
|
||||
@@ -62,7 +68,7 @@ def corpstats_view(request, corp_id=None):
|
||||
corpstats = get_object_or_404(CorpStats, corp=corp)
|
||||
|
||||
# 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
|
||||
if corpstats and corpstats not in available:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
from django.contrib import admin
|
||||
from django.db import models
|
||||
from .models import AutogroupsConfig
|
||||
from .models import AutogroupsConfig, ManagedCorpGroup, ManagedAllianceGroup
|
||||
|
||||
import logging
|
||||
|
||||
@@ -37,3 +37,6 @@ class AutogroupsConfigAdmin(admin.ModelAdmin):
|
||||
|
||||
|
||||
admin.site.register(AutogroupsConfig, AutogroupsConfigAdmin)
|
||||
admin.site.register(ManagedCorpGroup)
|
||||
admin.site.register(ManagedAllianceGroup)
|
||||
|
||||
|
||||
@@ -179,15 +179,13 @@ class AutogroupsConfig(models.Model):
|
||||
@transaction.atomic
|
||||
def create_alliance_group(self, alliance: EveAllianceInfo) -> Group:
|
||||
group, created = Group.objects.get_or_create(name=self.get_alliance_group_name(alliance))
|
||||
if created:
|
||||
ManagedAllianceGroup.objects.create(group=group, config=self, alliance=alliance)
|
||||
ManagedAllianceGroup.objects.get_or_create(group=group, config=self, alliance=alliance)
|
||||
return group
|
||||
|
||||
@transaction.atomic
|
||||
def create_corp_group(self, corp: EveCorporationInfo) -> Group:
|
||||
group, created = Group.objects.get_or_create(name=self.get_corp_group_name(corp))
|
||||
if created:
|
||||
ManagedCorpGroup.objects.create(group=group, config=self, corp=corp)
|
||||
ManagedCorpGroup.objects.get_or_create(group=group, config=self, corp=corp)
|
||||
return group
|
||||
|
||||
def delete_alliance_managed_groups(self):
|
||||
@@ -240,6 +238,8 @@ class ManagedGroup(models.Model):
|
||||
class Meta:
|
||||
abstract = True
|
||||
|
||||
def __str__(self):
|
||||
return "Managed Group: %s" % self.group.name
|
||||
|
||||
class ManagedCorpGroup(ManagedGroup):
|
||||
corp = models.ForeignKey(EveCorporationInfo, on_delete=models.CASCADE)
|
||||
|
||||
@@ -4,6 +4,16 @@ import logging
|
||||
import os
|
||||
|
||||
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__)
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,12 +1,12 @@
|
||||
from . import urls
|
||||
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from allianceauth import hooks
|
||||
from allianceauth.services.hooks import MenuItemHook, UrlHook
|
||||
|
||||
|
||||
@hooks.register('menu_item_hook')
|
||||
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:'])
|
||||
|
||||
|
||||
|
||||
@@ -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)
|
||||
fatlink = models.ForeignKey(Fatlink, on_delete=models.CASCADE)
|
||||
system = models.CharField(max_length=30)
|
||||
shiptype = models.CharField(max_length=30)
|
||||
shiptype = models.CharField(max_length=100)
|
||||
station = models.CharField(max_length=125)
|
||||
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
|
||||
|
||||
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__)
|
||||
|
||||
@@ -112,7 +122,7 @@ def fatlink_statistics_corp_view(request, corpid, year=None, month=None):
|
||||
start_of_next_month = first_day_of_next_month(year, month)
|
||||
start_of_previous_month = first_day_of_previous_month(year, month)
|
||||
fat_stats = {}
|
||||
corp_members = CharacterOwnership.objects.filter(character__corporation_id=corpid).values('user_id').distinct()
|
||||
corp_members = CharacterOwnership.objects.filter(character__corporation_id=corpid).order_by('user_id').values('user_id').distinct()
|
||||
|
||||
for member in corp_members:
|
||||
try:
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div class="col-lg-6">
|
||||
<div class="table-responsive">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-condensed table-hover table-striped">
|
||||
<tr>
|
||||
<th class="col-md-1"></th>
|
||||
@@ -26,7 +26,7 @@
|
||||
{% for char_name, user_id in member_list %}
|
||||
<tr>
|
||||
<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>
|
||||
<p>{{ user_id.char_name }}</p>
|
||||
|
||||
@@ -8,12 +8,12 @@
|
||||
{% block content %}
|
||||
<div class="col-lg-12">
|
||||
{% include "fleetup/menu.html" %}
|
||||
<div class="panel">
|
||||
<div>
|
||||
{% for a, j in doctrine.items %}
|
||||
{% regroup j.Data|dictsort:"Role" by Role as role_list %}
|
||||
|
||||
{% for Role in role_list %}
|
||||
|
||||
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title"><b>{{ Role.grouper }}</b></h3>
|
||||
@@ -50,7 +50,7 @@
|
||||
{% load humanize %}{{ item.EstPrice|intword }}
|
||||
</td>
|
||||
<td>
|
||||
{% for categories in item.Categories %}
|
||||
{% for categories in item.Categories %}
|
||||
{{ categories }},
|
||||
{% endfor %}
|
||||
</td>
|
||||
|
||||
@@ -8,12 +8,12 @@
|
||||
{% block content %}
|
||||
<div class="col-lg-12">
|
||||
{% include "fleetup/menu.html" %}
|
||||
<div class="panel">
|
||||
<div>
|
||||
{% if doctrines_list %}
|
||||
{% for a, j in doctrines_list.items %}
|
||||
{% regroup j|dictsort:"FolderName" by FolderName as folder_list %}
|
||||
{% for FolderName in folder_list %}
|
||||
<div class="col-lg-8">
|
||||
<div>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title"><b>{{ FolderName.grouper }}</b></h3>
|
||||
@@ -29,11 +29,11 @@
|
||||
<th class="col-lg-2">Note</th>-->
|
||||
</tr>
|
||||
{% for item in FolderName.list %}
|
||||
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<a href="{% url 'fleetup:doctrine' item.DoctrineId %}"><img src="https://image.eveonline.com/InventoryType/{{ item.IconId }}_32.png"></a>
|
||||
</td>
|
||||
</td>
|
||||
<td>
|
||||
{{ item.Name }}
|
||||
</td>
|
||||
|
||||
@@ -8,9 +8,9 @@
|
||||
{% block content %}
|
||||
<div class="col-lg-12">
|
||||
{% include "fleetup/menu.html" %}
|
||||
<div class="tab-content">
|
||||
<div class="tab-content row">
|
||||
<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 %}
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
@@ -18,22 +18,24 @@
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
{% for doctrin in y.Doctrines %}
|
||||
<h4>{{ doctrin.Name }}</h4>
|
||||
<div class="col-lg-12">
|
||||
<p>{% trans "Role in doctrine:" %} {{ doctrin.Role }}</p>
|
||||
</div>
|
||||
<div class="col-lg-4">
|
||||
<p>{% trans "Priority:" %}</p>
|
||||
</div>
|
||||
<div class="col-lg-8">
|
||||
<div class="progress">
|
||||
<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 class="clearfix">
|
||||
<h4>{{ doctrin.Name }}</h4>
|
||||
<div class="col-lg-12">
|
||||
<p>{% trans "Role in doctrine:" %} {{ doctrin.Role }}</p>
|
||||
</div>
|
||||
<div class="col-lg-4">
|
||||
<p>{% trans "Priority:" %}</p>
|
||||
</div>
|
||||
<div class="col-lg-8">
|
||||
<div class="progress">
|
||||
<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 class="pull-right">
|
||||
<a class="btn btn-primary" href="{% url 'fleetup:doctrine' doctrin.DoctrineId %}">{% trans "See doctrine" %}</a>
|
||||
<div class="pull-right">
|
||||
<a class="btn btn-primary" href="{% url 'fleetup:doctrine' doctrin.DoctrineId %}">{% trans "See doctrine" %}</a>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
@@ -56,10 +58,10 @@
|
||||
<div class="panel-body">
|
||||
<div class="list-group">
|
||||
{% for arbit, orbit in doctrines_list.items %}
|
||||
|
||||
|
||||
{% for fitting in orbit.Data %}
|
||||
<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>
|
||||
<p class="list-group-item-heading">{{ fitting.Role }} - {{ fitting.ShipType }}</p>
|
||||
</a>
|
||||
@@ -107,8 +109,8 @@
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-lg-3">
|
||||
|
||||
<div class="col-lg-4">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">{% trans "EFT/Export" %}</h3>
|
||||
|
||||
@@ -20,11 +20,11 @@
|
||||
<th class="col-md-2">{% trans "Categories" %}</th>
|
||||
</tr>
|
||||
{% for id, fittings in fitting_list %}
|
||||
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<a href="{% url 'fleetup:fitting' fittings.fitting_id %}"><img src="https://image.eveonline.com/InventoryType/{{ fittings.icon_id }}_32.png"></a>
|
||||
</td>
|
||||
</td>
|
||||
<td>
|
||||
{{ fittings.name }}
|
||||
</td>
|
||||
@@ -38,12 +38,12 @@
|
||||
{% load humanize %}{{ fittings.estimated|intword }}
|
||||
</td>
|
||||
<td>
|
||||
{% for categories in fittings.categories %}
|
||||
{% for categories in fittings.categories %}
|
||||
{{ categories }},
|
||||
{% endfor %}
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
|
||||
{% endfor %}
|
||||
</table>
|
||||
{% else %}
|
||||
|
||||
@@ -8,15 +8,15 @@
|
||||
{% block content %}
|
||||
<div class="col-lg-12">
|
||||
{% include "fleetup/menu.html" %}
|
||||
<div class="panel">
|
||||
<div>
|
||||
<ul class="nav nav-tabs">
|
||||
<li class="active"><a data-toggle="tab" href="#operations">{% trans "Operations" %}</a></li>
|
||||
<li><a data-toggle="tab" href="#timers">{% trans "Timers" %}</a></li>
|
||||
</ul>
|
||||
|
||||
<div class="tab-content">
|
||||
<div class="tab-content row">
|
||||
<div id="operations" class="tab-pane fade in active">
|
||||
<div class="col-lg-7">
|
||||
<div class="col-lg-8">
|
||||
{% if operations_list %}
|
||||
{% for subject, start in operations_list %}
|
||||
<div class="panel panel-default">
|
||||
@@ -31,7 +31,7 @@
|
||||
</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.end|date:"l d M H:i" }} <span class="label label-success">{% trans "Eve Time" %}</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
@@ -39,13 +39,12 @@
|
||||
<span id="localtime{{ start.operation_id }}"></span> <span class='label label-success'>Local time</span><br>
|
||||
<div id="countdown{{ start.operation_id }}"></div>
|
||||
</td>
|
||||
|
||||
|
||||
<td class="col-md-6"></td>
|
||||
</tr>
|
||||
</table>
|
||||
<p>{{ start.details }}</p>
|
||||
|
||||
<div class="col-lg-12">
|
||||
</table>
|
||||
{{ start.details|linebreaks }}
|
||||
|
||||
<table class="table table-condensed table-striped">
|
||||
<tr>
|
||||
<th class="col-md-4">{% trans "Location" %}</th>
|
||||
@@ -60,11 +59,11 @@
|
||||
<td>
|
||||
{% if start.doctrine %}
|
||||
{% for doctrine in start.doctrine %}
|
||||
|
||||
|
||||
<a href="{% url 'fleetup:doctrine' doctrine.Id %}" class="label label-success">{{ doctrine.Name }}</a>
|
||||
|
||||
|
||||
{% endfor %}
|
||||
|
||||
|
||||
{% else %}
|
||||
<span class="label label-danger">{% trans "TBA" %}</span>
|
||||
{% endif %}
|
||||
@@ -81,7 +80,6 @@
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
@@ -89,7 +87,7 @@
|
||||
<h3>{% trans "There seems to be no Operations in the near future." %}</h3>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="col-lg-3">
|
||||
<div class="col-lg-4">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h2 class="panel-title">{% trans "Current Eve Time:" %}</h2>
|
||||
@@ -158,7 +156,7 @@
|
||||
<td>
|
||||
{{ type.owner }}
|
||||
</td>
|
||||
<td>
|
||||
<td>
|
||||
{{ type.notes }}
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -8,8 +8,8 @@ from .models import GroupRequest
|
||||
|
||||
class AuthGroupInlineAdmin(admin.StackedInline):
|
||||
model = AuthGroup
|
||||
filter_horizontal = ('group_leaders',)
|
||||
fields = ('description', 'group_leaders', 'internal', 'hidden', 'open', 'public')
|
||||
filter_horizontal = ('group_leaders', 'states',)
|
||||
fields = ('description', 'group_leaders', 'states', 'internal', 'hidden', 'open', 'public')
|
||||
verbose_name_plural = 'Auth Settings'
|
||||
verbose_name = ''
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
from django.contrib.auth.models import Group
|
||||
from django.db.models import Q
|
||||
|
||||
|
||||
class GroupManager:
|
||||
@@ -6,7 +7,12 @@ class GroupManager:
|
||||
pass
|
||||
|
||||
@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)
|
||||
|
||||
@staticmethod
|
||||
@@ -14,13 +20,35 @@ class GroupManager:
|
||||
return Group.objects.select_related('authgroup').filter(authgroup__group_leaders__in=[user])
|
||||
|
||||
@staticmethod
|
||||
def joinable_group(group):
|
||||
def joinable_group(group, state):
|
||||
"""
|
||||
Check if a group is a user joinable group, i.e.
|
||||
not an internal group for Corp, Alliance, Members etc
|
||||
Check if a group is a user/state joinable group, i.e.
|
||||
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 state: allianceauth.authentication.State object
|
||||
: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
|
||||
|
||||
@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'),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,19 @@
|
||||
# Generated by Django 2.0.8 on 2018-12-07 08:56
|
||||
|
||||
import datetime
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('groupmanagement', '0010_authgroup_states'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='requestlog',
|
||||
name='date',
|
||||
field=models.DateTimeField(default=datetime.datetime(2018, 12, 7, 8, 56, 33, 846342)),
|
||||
),
|
||||
]
|
||||
@@ -3,6 +3,8 @@ from django.contrib.auth.models import User
|
||||
from django.db import models
|
||||
from django.db.models.signals import post_save
|
||||
from django.dispatch import receiver
|
||||
from allianceauth.authentication.models import State
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
class GroupRequest(models.Model):
|
||||
@@ -23,6 +25,38 @@ class GroupRequest(models.Model):
|
||||
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)
|
||||
date = models.DateTimeField(auto_now_add=datetime.utcnow())
|
||||
|
||||
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):
|
||||
"""
|
||||
Extends Django Group model with a one-to-one field
|
||||
@@ -65,6 +99,10 @@ class AuthGroup(models.Model):
|
||||
"specifically. Use the auth.group_management permission to allow "
|
||||
"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.")
|
||||
|
||||
def __str__(self):
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
{% extends "allianceauth/base.html" %}
|
||||
{% load staticfiles %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block page_title %}{{ group }} {% trans "Audit Log" %}{% endblock page_title %}
|
||||
|
||||
{% block content %}
|
||||
<div class="col-lg-12">
|
||||
<br>
|
||||
{% include 'groupmanagement/menu.html' %}
|
||||
<div>
|
||||
<h3>{{ group }} Audit Log</h3>
|
||||
<p> All times displayed are EVE/UTC.</p>
|
||||
{% if entries %}
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped" id="log-entries">
|
||||
<thead>
|
||||
<th class="text-center" scope="col">{% trans "Date/Time" %}</th>
|
||||
<th class="text-center" scope="col">{% trans "Requestor" %}</th>
|
||||
<th class="text-center" scope="col">{% trans "Main Character" %}</th>
|
||||
<th class="text-center" scope="col">{% trans "Group" %}</th>
|
||||
<th class="text-center" scope="col">{% trans "Type" %}</th>
|
||||
<th class="text-center" scope="col">{% trans "Action" %}</th>
|
||||
<th class="text-center" scope="col">{% trans "Actor" %}</th>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for entry in entries %}
|
||||
<tr>
|
||||
<td class="text-center">{{ entry.date }}</td>
|
||||
<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>
|
||||
{% if entry.request_type is None %}
|
||||
<td class="text-center"> Removed</td>
|
||||
{% else %}
|
||||
<td class="text-center">{{ entry.action_to_str }}</td>
|
||||
{% endif %}
|
||||
<td class="text-center">{{ entry.request_actor }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="alert alert-warning text-center">{% trans "No entries found for this group." %}</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% block extra_javascript %}
|
||||
{% include 'bundles/datatables-js.html' %}
|
||||
{% endblock %}
|
||||
{% block extra_css %}
|
||||
{% include 'bundles/datatables-css.html' %}
|
||||
{% endblock %}
|
||||
{% block extra_script %}
|
||||
$(document).ready(function(){
|
||||
$('#log-entries').DataTable();
|
||||
});
|
||||
{% endblock %}
|
||||
|
||||
@@ -41,6 +41,9 @@
|
||||
title="{% trans "View Members" %}">
|
||||
<i class="glyphicon glyphicon-eye-open"></i>
|
||||
</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>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
|
||||
@@ -19,7 +19,7 @@ url
|
||||
{% for g in groups %}
|
||||
<tr>
|
||||
<td class="text-center">{{ g.group.name }}</td>
|
||||
<td class="text-center">{{ g.group.authgroup.description }}</td>
|
||||
<td class="text-center">{{ g.group.authgroup.description|urlize }}</td>
|
||||
<td class="text-center">
|
||||
{% if g.group in user.groups.all %}
|
||||
{% if not g.request %}
|
||||
@@ -32,9 +32,15 @@ url
|
||||
</button>
|
||||
{% endif %}
|
||||
{% elif not g.request %}
|
||||
<a href="{% url 'groupmanagement:request_add' g.group.id %}" class="btn btn-success">
|
||||
{% trans "Request" %}
|
||||
</a>
|
||||
{% if g.group.authgroup.open %}
|
||||
<a href="{% url 'groupmanagement:request_add' g.group.id %}" class="btn btn-success">
|
||||
{% trans "Join" %}
|
||||
</a>
|
||||
{% else %}
|
||||
<a href="{% url 'groupmanagement:request_add' g.group.id %}" class="btn btn-primary">
|
||||
{% trans "Request" %}
|
||||
</a>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<button type="button" class="btn btn-primary" disabled>
|
||||
{{ g.request.status }}
|
||||
|
||||
@@ -12,6 +12,7 @@ urlpatterns = [
|
||||
name='membership'),
|
||||
url(r'^membership/(\w+)/$', views.group_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,
|
||||
name='membership_remove'),
|
||||
url(r'^request_add/(\w+)', views.group_request_add,
|
||||
|
||||
@@ -5,15 +5,18 @@ from django.contrib.auth.decorators import login_required
|
||||
from django.contrib.auth.decorators import user_passes_test
|
||||
from django.contrib.auth.models import Group
|
||||
from django.core.exceptions import ObjectDoesNotExist, PermissionDenied
|
||||
from django.core.paginator import Paginator, EmptyPage
|
||||
from django.db.models import Count
|
||||
from django.http import Http404
|
||||
from django.shortcuts import render, redirect, get_object_or_404
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from .managers import GroupManager
|
||||
from .models import GroupRequest
|
||||
from .models import GroupRequest, RequestLog
|
||||
|
||||
from allianceauth.notifications import notify
|
||||
|
||||
from django.conf import settings
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@@ -53,7 +56,7 @@ def group_membership(request):
|
||||
# Get all open and closed groups
|
||||
if GroupManager.has_management_permission(request.user):
|
||||
# Full access
|
||||
groups = GroupManager.get_joinable_groups()
|
||||
groups = GroupManager.get_all_non_internal_groups()
|
||||
else:
|
||||
# Group leader specific
|
||||
groups = GroupManager.get_group_leaders_groups(request.user)
|
||||
@@ -65,6 +68,31 @@ def group_membership(request):
|
||||
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")
|
||||
render_items = {'group': group.name}
|
||||
entries = RequestLog.objects.filter(group=group).order_by('-date')
|
||||
render_items['entries'] = entries
|
||||
|
||||
return render(request, 'groupmanagement/audit.html', context=render_items)
|
||||
|
||||
|
||||
|
||||
|
||||
@login_required
|
||||
@user_passes_test(GroupManager.can_manage_groups)
|
||||
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
|
||||
# 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" %
|
||||
(request.user, group_id))
|
||||
raise PermissionDenied
|
||||
@@ -105,13 +133,16 @@ def group_membership_remove(request, group_id, user_id):
|
||||
try:
|
||||
# Check its a joinable group i.e. not corp or internal
|
||||
# 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,
|
||||
group_id))
|
||||
raise PermissionDenied
|
||||
|
||||
try:
|
||||
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
|
||||
user.groups.remove(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:
|
||||
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):
|
||||
raise PermissionDenied
|
||||
|
||||
group_request.user.groups.add(group)
|
||||
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()
|
||||
logger.info("User %s accepted group request from user %s to group %s" % (
|
||||
request.user, group_request.user, group_request.group.name))
|
||||
@@ -172,6 +205,8 @@ def group_reject_request(request, group_request_id):
|
||||
if group_request:
|
||||
logger.info("User %s rejected group request from user %s to group %s" % (
|
||||
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()
|
||||
notify(group_request.user, "Group Application Rejected", level="danger",
|
||||
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_request.user.groups.remove(group)
|
||||
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()
|
||||
logger.info("User %s accepted group leave request from user %s to group %s" % (
|
||||
request.user, group_request.user, group_request.group.name))
|
||||
@@ -236,6 +273,8 @@ def group_leave_reject_request(request, group_request_id):
|
||||
raise PermissionDenied
|
||||
|
||||
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()
|
||||
logger.info("User %s rejected group leave request from user %s for group %s" % (
|
||||
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)
|
||||
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'):
|
||||
# Filter down to public groups only for non-members
|
||||
@@ -284,11 +323,18 @@ def groups_view(request):
|
||||
def group_request_add(request, 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)
|
||||
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" %
|
||||
(request.user, group_id))
|
||||
messages.warning(request, _("You cannot join that group"))
|
||||
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:
|
||||
# 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" %
|
||||
@@ -299,6 +345,11 @@ def group_request_add(request, group_id):
|
||||
logger.info("%s joining %s as is an open group" % (request.user, group))
|
||||
request.user.groups.add(group)
|
||||
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.status = _('Pending')
|
||||
grouprequest.group = group
|
||||
@@ -314,7 +365,7 @@ def group_request_add(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))
|
||||
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" %
|
||||
(request.user, group_id))
|
||||
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))
|
||||
request.user.groups.remove(group)
|
||||
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.status = _('Pending')
|
||||
grouprequest.group = group
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
from allianceauth.services.hooks import MenuItemHook, UrlHook
|
||||
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from allianceauth import hooks
|
||||
from allianceauth.hrapplications import urls
|
||||
|
||||
@@ -7,7 +7,7 @@ from allianceauth.hrapplications import urls
|
||||
class ApplicationsMenu(MenuItemHook):
|
||||
def __init__(self):
|
||||
MenuItemHook.__init__(self,
|
||||
'Applications',
|
||||
_('Applications'),
|
||||
'fa fa-file-o fa-fw',
|
||||
'hrapplications:index',
|
||||
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 django.utils.translation import ugettext_lazy as _
|
||||
from allianceauth import hooks
|
||||
from . import urls
|
||||
|
||||
|
||||
class OpTimerboardMenu(MenuItemHook):
|
||||
def __init__(self):
|
||||
MenuItemHook.__init__(self, 'Fleet Operations',
|
||||
MenuItemHook.__init__(self, _('Fleet Operations'),
|
||||
'fa fa-exclamation fa-fw',
|
||||
'optimer:view',
|
||||
navactive=['optimer:'])
|
||||
|
||||
@@ -19,7 +19,8 @@
|
||||
<div class="col-lg-12 text-center row">
|
||||
<div class="label label-info text-left">
|
||||
<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 />
|
||||
</div>
|
||||
|
||||
@@ -111,7 +112,7 @@
|
||||
}
|
||||
|
||||
function updateClock() {
|
||||
document.getElementById("current-time").innerHTML = "<b>" + moment.utc().format('LLLL') + "</b>";
|
||||
document.getElementById("current-time").innerHTML = getCurrentEveTimeString();
|
||||
}
|
||||
</script>
|
||||
{% endblock content %}
|
||||
|
||||
@@ -82,6 +82,7 @@ ugettext = lambda s: s
|
||||
LANGUAGES = (
|
||||
('en', ugettext('English')),
|
||||
('de', ugettext('German')),
|
||||
('es', ugettext('Spanish')),
|
||||
)
|
||||
|
||||
TEMPLATES = [
|
||||
@@ -193,6 +194,8 @@ LOGIN_TOKEN_SCOPES = ['publicData']
|
||||
# number of days email verification links are valid for
|
||||
ACCOUNT_ACTIVATION_DAYS = 1
|
||||
|
||||
ESI_API_URL = 'https://esi.evetech.net/'
|
||||
|
||||
LOGGING = {
|
||||
'version': 1,
|
||||
'disable_existing_loggers': False,
|
||||
|
||||
@@ -30,6 +30,7 @@ DATABASES['default'] = {
|
||||
'PASSWORD': '',
|
||||
'HOST': '127.0.0.1',
|
||||
'PORT': '3306',
|
||||
'OPTIONS': {'charset': 'utf8mb4'},
|
||||
}
|
||||
|
||||
# Register an application at https://developers.eveonline.com for Authentication
|
||||
|
||||
@@ -219,22 +219,18 @@ class DiscordOAuthManager:
|
||||
@staticmethod
|
||||
@api_backoff
|
||||
def update_nickname(user_id, nickname):
|
||||
try:
|
||||
nickname = DiscordOAuthManager._sanitize_name(nickname)
|
||||
custom_headers = {'content-type': 'application/json', 'authorization': 'Bot ' + settings.DISCORD_BOT_TOKEN}
|
||||
data = {'nick': nickname}
|
||||
path = DISCORD_URL + "/guilds/" + str(settings.DISCORD_GUILD_ID) + "/members/" + str(user_id)
|
||||
r = requests.patch(path, headers=custom_headers, json=data)
|
||||
logger.debug("Got status code %s after setting nickname for Discord user ID %s (%s)" % (
|
||||
r.status_code, user_id, nickname))
|
||||
if r.status_code == 404:
|
||||
logger.warn("Discord user ID %s could not be found in server." % user_id)
|
||||
return True
|
||||
r.raise_for_status()
|
||||
nickname = DiscordOAuthManager._sanitize_name(nickname)
|
||||
custom_headers = {'content-type': 'application/json', 'authorization': 'Bot ' + settings.DISCORD_BOT_TOKEN}
|
||||
data = {'nick': nickname}
|
||||
path = DISCORD_URL + "/guilds/" + str(settings.DISCORD_GUILD_ID) + "/members/" + str(user_id)
|
||||
r = requests.patch(path, headers=custom_headers, json=data)
|
||||
logger.debug("Got status code %s after setting nickname for Discord user ID %s (%s)" % (
|
||||
r.status_code, user_id, nickname))
|
||||
if r.status_code == 404:
|
||||
logger.warn("Discord user ID %s could not be found in server." % user_id)
|
||||
return True
|
||||
except:
|
||||
logger.exception("Failed to set nickname for Discord user ID %s (%s)" % (user_id, nickname))
|
||||
return False
|
||||
r.raise_for_status()
|
||||
return True
|
||||
|
||||
@staticmethod
|
||||
def delete_user(user_id):
|
||||
|
||||
@@ -57,5 +57,5 @@ class Migration(migrations.Migration):
|
||||
name='discorduser',
|
||||
options={'permissions': (('access_discord', 'Can access the Discord service'),)},
|
||||
),
|
||||
migrations.RunPython(migrate_service_enabled),
|
||||
migrations.RunPython(migrate_service_enabled, migrations.RunPython.noop),
|
||||
]
|
||||
|
||||
@@ -235,7 +235,7 @@ class DiscourseManager:
|
||||
@staticmethod
|
||||
def __add_user_to_group(g_id, username):
|
||||
endpoint = ENDPOINTS['groups']['add_user']
|
||||
DiscourseManager.__exc(endpoint, g_id, usernames=[username])
|
||||
DiscourseManager.__exc(endpoint, g_id, usernames=username)
|
||||
|
||||
@staticmethod
|
||||
def __remove_user_from_group(g_id, username):
|
||||
@@ -355,11 +355,14 @@ class DiscourseManager:
|
||||
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]
|
||||
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(
|
||||
"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:
|
||||
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:
|
||||
DiscourseManager.__remove_user_from_group(g, username)
|
||||
|
||||
|
||||
@@ -58,5 +58,5 @@ class Migration(migrations.Migration):
|
||||
name='discourseuser',
|
||||
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 %}
|
||||
|
||||
<td class="text-center">Discourse</td>
|
||||
<td class="text-center">{{ char.character_name }}</td>
|
||||
<td class="text-center"><a href="{{ DISCOURSE_URL }}">{{ DISCOURSE_URL }}</a></td>
|
||||
<td class="text-center">
|
||||
<a title="Go To Forums" class="btn btn-success" href="{{ DISCOURSE_URL }}"><span class="glyphicon glyphicon-arrow-right"></span></a>
|
||||
</td>
|
||||
<tr>
|
||||
<td class="text-center">Discourse</td>
|
||||
<td class="text-center">{{ char.character_name }}</td>
|
||||
<td class="text-center"><a href="{{ DISCOURSE_URL }}">{{ DISCOURSE_URL }}</a></td>
|
||||
<td class="text-center">
|
||||
<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',
|
||||
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',
|
||||
options={'permissions': (('access_market', 'Can access the Evernus Market service'),)},
|
||||
),
|
||||
migrations.RunPython(migrate_service_enabled),
|
||||
migrations.RunPython(migrate_service_enabled, migrations.RunPython.noop),
|
||||
]
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import logging
|
||||
import urllib
|
||||
|
||||
from django.conf import settings
|
||||
from django.template.loader import render_to_string
|
||||
@@ -61,7 +62,7 @@ class MumbleService(ServicesHook):
|
||||
'service_name': self.title,
|
||||
'urls': urls,
|
||||
'service_url': self.service_url,
|
||||
'connect_url': request.user.mumble.username + '@' + self.service_url if MumbleTasks.has_account(request.user) else self.service_url,
|
||||
'connect_url': urllib.parse.quote(request.user.mumble.username, safe="") + '@' + self.service_url if MumbleTasks.has_account(request.user) else self.service_url,
|
||||
'username': request.user.mumble.username if MumbleTasks.has_account(request.user) else '',
|
||||
}, request=request)
|
||||
|
||||
|
||||
@@ -57,5 +57,5 @@ class Migration(migrations.Migration):
|
||||
name='mumbleuser',
|
||||
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',
|
||||
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',
|
||||
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',
|
||||
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')
|
||||
logger.debug("Received group cache from server: %s" % group_cache)
|
||||
for group in group_cache:
|
||||
if group['keys']['type'] != '1':
|
||||
continue
|
||||
logger.debug("Checking group %s" % group)
|
||||
if group['keys']['name'] == groupname:
|
||||
logger.debug("Found group %s, returning id %s" % (groupname, group['keys']['sgid']))
|
||||
@@ -124,6 +126,8 @@ class Teamspeak3Manager:
|
||||
outlist = {}
|
||||
if 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']))
|
||||
outlist[group['keys']['name']] = group['keys']['sgid']
|
||||
else:
|
||||
@@ -179,18 +183,19 @@ class Teamspeak3Manager:
|
||||
except:
|
||||
logger.exception("An unhandled exception has occured while syncing TS groups.")
|
||||
|
||||
def add_user(self, username):
|
||||
username_clean = self.__santatize_username(username[:30])
|
||||
def add_user(self, user, fmt_name):
|
||||
username_clean = self.__santatize_username(fmt_name[:30])
|
||||
logger.debug("Adding user to TS3 server with cleaned username %s" % username_clean)
|
||||
server_groups = self._group_list()
|
||||
|
||||
if 'Member' not in server_groups:
|
||||
self._create_group('Member')
|
||||
state = user.profile.state.name
|
||||
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:
|
||||
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,
|
||||
'tokencustomset': "ident=sso_uid value=%s" % username_clean})
|
||||
except TeamspeakError as e:
|
||||
@@ -213,7 +218,7 @@ class Teamspeak3Manager:
|
||||
if isinstance(clients, dict):
|
||||
# Rewrap list
|
||||
clients = [clients]
|
||||
|
||||
|
||||
for client in clients:
|
||||
try:
|
||||
if client['keys']['client_database_id'] == user:
|
||||
@@ -244,10 +249,10 @@ class Teamspeak3Manager:
|
||||
|
||||
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)
|
||||
self.delete_user(uid)
|
||||
return self.add_user(username)
|
||||
return self.add_user(user, username)
|
||||
|
||||
def update_groups(self, uid, ts_groups):
|
||||
logger.debug("Updating uid %s TS3 groups %s" % (uid, ts_groups))
|
||||
|
||||
@@ -57,5 +57,5 @@ class Migration(migrations.Migration):
|
||||
name='teamspeak3user',
|
||||
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
|
||||
with Teamspeak3Manager() as ts3man:
|
||||
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 result[0] is not "":
|
||||
@@ -79,13 +79,12 @@ def reset_teamspeak3_perm(request):
|
||||
logger.debug("reset_teamspeak3_perm called by user %s" % request.user)
|
||||
if not Teamspeak3Tasks.has_account(request.user):
|
||||
return redirect("services:services")
|
||||
character = request.user.profile.main_character
|
||||
logger.debug("Deleting TS3 user for user %s" % request.user)
|
||||
with Teamspeak3Manager() as ts3man:
|
||||
ts3man.delete_user(request.user.teamspeak3.uid)
|
||||
|
||||
logger.debug("Generating new permission key for user %s with main character %s" % (request.user, character))
|
||||
result = ts3man.generate_new_permissionkey(request.user.teamspeak3.uid, character.character_name)
|
||||
logger.debug("Generating new permission key for user %s" % request.user)
|
||||
result = ts3man.generate_new_permissionkey(request.user.teamspeak3.uid, request.user, Teamspeak3Tasks.get_username(request.user))
|
||||
|
||||
# if blank we failed
|
||||
if result[0] != "":
|
||||
|
||||
@@ -57,5 +57,5 @@ class Migration(migrations.Migration):
|
||||
name='xenforouser',
|
||||
options={'permissions': (('access_xenforo', 'Can access the XenForo service'),)},
|
||||
),
|
||||
migrations.RunPython(migrate_service_enabled),
|
||||
migrations.RunPython(migrate_service_enabled, migrations.RunPython.noop),
|
||||
]
|
||||
|
||||
@@ -4,8 +4,8 @@ from celery import shared_task
|
||||
from django.contrib.auth.models import User
|
||||
from .hooks import ServicesHook
|
||||
from celery_once import QueueOnce as BaseTask, AlreadyQueued
|
||||
from celery_once.helpers import now_unix
|
||||
from django.core.cache import cache
|
||||
from time import time
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -22,7 +22,7 @@ class DjangoBackend:
|
||||
|
||||
@staticmethod
|
||||
def raise_or_lock(key, timeout):
|
||||
now = now_unix()
|
||||
now = int(time())
|
||||
result = cache.get(key)
|
||||
if result:
|
||||
remaining = int(result) - now
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
from allianceauth.services.hooks import MenuItemHook, UrlHook
|
||||
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from allianceauth import hooks
|
||||
from . import urls
|
||||
|
||||
|
||||
class SrpMenu(MenuItemHook):
|
||||
def __init__(self):
|
||||
MenuItemHook.__init__(self, 'Ship Replacement',
|
||||
MenuItemHook.__init__(self, _('Ship Replacement'),
|
||||
'fa fa-money fa-fw',
|
||||
'srp:management',
|
||||
navactive=['srp:'])
|
||||
|
||||
@@ -1,9 +1,15 @@
|
||||
from allianceauth import NAME
|
||||
|
||||
from esi.clients import esi_client_factory
|
||||
import requests
|
||||
import logging
|
||||
import os
|
||||
|
||||
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:
|
||||
@@ -18,7 +24,7 @@ class SRPManager:
|
||||
|
||||
@staticmethod
|
||||
def get_kill_data(kill_id):
|
||||
url = ("https://www.zkillboard.com/api/killID/%s/" % kill_id)
|
||||
url = ("https://zkillboard.com/api/killID/%s/" % kill_id)
|
||||
headers = {
|
||||
'User-Agent': NAME,
|
||||
'Content-Type': 'application/json',
|
||||
@@ -26,12 +32,20 @@ class SRPManager:
|
||||
r = requests.get(url, headers=headers)
|
||||
result = r.json()[0]
|
||||
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))
|
||||
ship_value = result['zkb']['totalValue']
|
||||
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
|
||||
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">
|
||||
{% trans "View All" %}
|
||||
</a>
|
||||
{% endif %}
|
||||
{% if perms.srp.add_srpfleetmain or perms.auth.srp_management %}
|
||||
<a href="{% url 'srp:add' %}" class="btn btn-success">
|
||||
{% trans "Add SRP Fleet" %}
|
||||
</a>
|
||||
|
||||
@@ -10,6 +10,7 @@ from django.shortcuts import render, redirect, get_object_or_404
|
||||
from django.utils import timezone
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.db.models import Sum
|
||||
from allianceauth.authentication.decorators import permissions_required
|
||||
from allianceauth.eveonline.providers import provider
|
||||
from allianceauth.notifications import notify
|
||||
from .form import SrpFleetMainForm
|
||||
@@ -59,7 +60,7 @@ def srp_fleet_view(request, fleet_id):
|
||||
|
||||
|
||||
@login_required
|
||||
@permission_required('auth.srp_management')
|
||||
@permissions_required(('auth.srp_management', 'srp.add_srpfleetmain'))
|
||||
def srp_fleet_add_view(request):
|
||||
logger.debug("srp_fleet_add_view called by user %s" % request.user)
|
||||
completed = False
|
||||
|
||||
@@ -8,8 +8,16 @@ function getDurationString(duration) {
|
||||
if (duration.years()) {
|
||||
out += duration.years() + 'y ';
|
||||
}
|
||||
if (duration.months()) {
|
||||
out += duration.months() + 'm ';
|
||||
}
|
||||
if (duration.days()) {
|
||||
out += duration.days() + 'd ';
|
||||
}
|
||||
return out + duration.hours() + "h " + duration.minutes() + "m " + duration.seconds() + "s";
|
||||
}
|
||||
|
||||
|
||||
function getCurrentEveTimeString() {
|
||||
return moment().utc().format('dddd LL HH:mm:ss')
|
||||
}
|
||||
|
||||
@@ -8,19 +8,19 @@
|
||||
<ul class="list-group">
|
||||
{% for notif in notifications %}
|
||||
<li class="list-group-item">
|
||||
{% if notif.state == 'open' %}
|
||||
{% if notif.state == 'opened' %}
|
||||
<span class="label label-success">{% trans "Open" %}</span>
|
||||
{% else %}
|
||||
<span class="label label-danger">{% trans "Closed" %}</span>
|
||||
{% endif %}
|
||||
<a href="{{ notif.html_url }}" target="_blank">#{{ notif.number }} {{ notif.title }}</a>
|
||||
<a href="{{ notif.web_url }}" target="_blank">#{{ notif.iid }} {{ notif.title }}</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
<div class="text-right" style="position:absolute;bottom:5px;right:5px;">
|
||||
<a href="https://github.com/allianceauth/allianceauth/issues"><span class="label label-default">
|
||||
<i class="fa fa-github" aria-hidden="true"></i> Powered by Github</span>
|
||||
<a href="https://gitlab.com/allianceauth/allianceauth/issues"><span class="label" style="background-color:#e65328;">
|
||||
<i class="fa fa-gitlab" aria-hidden="true"></i> Powered by GitLab</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
@@ -39,7 +39,7 @@
|
||||
<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>
|
||||
<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 }}
|
||||
</a>
|
||||
{% 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 %}">
|
||||
<h4 class="list-group-item-heading">{% trans "Latest Minor" %}</h4>
|
||||
<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 }}
|
||||
</a>
|
||||
{% 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 %}">
|
||||
<h4 class="list-group-item-heading">{% trans "Latest Patch" %}</h4>
|
||||
<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 }}
|
||||
</a>
|
||||
{% if not latest_patch %}<br>{% trans "Update available" %}{% endif %}
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
{% extends "allianceauth/base.html" %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block page_title %}Help{% endblock page_title %}
|
||||
{% block page_title %}{% trans "Help" %}{% endblock page_title %}
|
||||
|
||||
{% block content %}
|
||||
<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="embed-responsive embed-responsive-16by9">
|
||||
|
||||
@@ -7,12 +7,12 @@
|
||||
<li>
|
||||
<a class="{% navactive request '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>
|
||||
</li>
|
||||
<li>
|
||||
<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>
|
||||
</li>
|
||||
|
||||
@@ -20,19 +20,21 @@
|
||||
<li>
|
||||
<a class="{% navactive request 'groupmanagement:management groupmanagement:membership groupmanagement:membership_list' %}"
|
||||
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>
|
||||
</li>
|
||||
{% endif %}
|
||||
|
||||
{% menu_items %}
|
||||
|
||||
<li>
|
||||
<a class="{% navactive request 'authentication:help' %}"
|
||||
href="{% url 'authentication:help' %}">
|
||||
<i class="fa fa-question fa-fw"></i>{% trans " Help" %}
|
||||
</a>
|
||||
</li>
|
||||
{% if user.is_superuser %}
|
||||
<li>
|
||||
<a class="{% navactive request 'authentication:help' %}"
|
||||
href="{% url 'authentication:help' %}">
|
||||
<i class="fa fa-question fa-fw"></i> {% trans "Help" %}
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -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' %}
|
||||
<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 %}
|
||||
|
||||
@@ -17,16 +17,16 @@ NOTIFICATION_CACHE_TIME = 300 # 5 minutes
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def get_github_tags():
|
||||
request = requests.get('https://api.github.com/repos/allianceauth/allianceauth/releases')
|
||||
def get_git_tags():
|
||||
request = requests.get('https://gitlab.com/api/v4/projects/allianceauth%2Fallianceauth/repository/tags')
|
||||
request.raise_for_status()
|
||||
return request.json()
|
||||
|
||||
|
||||
def get_github_notification_issues():
|
||||
def get_notification_issues():
|
||||
# notification
|
||||
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()
|
||||
return request.json()
|
||||
|
||||
@@ -68,12 +68,12 @@ def get_notifications():
|
||||
'notifications': list(),
|
||||
}
|
||||
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)
|
||||
# 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:
|
||||
logger.exception('Error while getting github notifications')
|
||||
logger.exception('Error while getting gitlab notifications')
|
||||
return response
|
||||
|
||||
|
||||
@@ -85,7 +85,7 @@ def get_version_info():
|
||||
'current_version': __version__,
|
||||
}
|
||||
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__)
|
||||
|
||||
# Set them all to the current version to start
|
||||
@@ -102,7 +102,7 @@ def get_version_info():
|
||||
})
|
||||
|
||||
for tag in tags:
|
||||
tag_name = tag.get('tag_name')
|
||||
tag_name = tag.get('name')
|
||||
if tag_name[0] == 'v':
|
||||
# Strip 'v' off front of verison if it exists
|
||||
tag_name = tag_name[1:]
|
||||
@@ -114,24 +114,21 @@ def get_version_info():
|
||||
if latest_major is None or tag_ver > latest_major:
|
||||
latest_major = tag_ver
|
||||
response['latest_major_version'] = tag_name
|
||||
response['latest_major_url'] = tag['html_url']
|
||||
if tag_ver.major > current_ver.major:
|
||||
response['latest_major'] = False
|
||||
elif tag_ver.major == current_ver.major:
|
||||
if latest_minor is None or tag_ver > latest_minor:
|
||||
latest_minor = tag_ver
|
||||
response['latest_minor_version'] = tag_name
|
||||
response['latest_minor_url'] = tag['html_url']
|
||||
if tag_ver.minor > current_ver.minor:
|
||||
response['latest_minor'] = False
|
||||
elif tag_ver.minor == current_ver.minor:
|
||||
if latest_patch is None or tag_ver > latest_patch:
|
||||
latest_patch = tag_ver
|
||||
response['latest_patch_version'] = tag_name
|
||||
response['latest_patch_url'] = tag['html_url']
|
||||
if tag_ver.patch > current_ver.patch:
|
||||
response['latest_patch'] = False
|
||||
|
||||
except requests.RequestException:
|
||||
logger.exception('Error while getting github release tags')
|
||||
logger.exception('Error while getting gitlab release tags')
|
||||
return response
|
||||
|
||||
@@ -34,19 +34,21 @@ class TimerForm(forms.ModelForm):
|
||||
|
||||
structure_choices = [('POCO', 'POCO'),
|
||||
('I-HUB', 'I-HUB'),
|
||||
('TCU', 'TCU'),
|
||||
('POS[S]', 'POS[S]'),
|
||||
('POS[M]', 'POS[M]'),
|
||||
('POS[L]', 'POS[L]'),
|
||||
('Citadel[M]', 'Citadel[M]'),
|
||||
('Citadel[L]', 'Citadel[L]'),
|
||||
('Citadel[XL]', 'Citadel[XL]'),
|
||||
('Engineering Complex[M]', 'Engineering Complex[M]'),
|
||||
('Engineering Complex[L]', 'Engineering Complex[L]'),
|
||||
('Engineering Complex[XL]', 'Engineering Complex[XL]'),
|
||||
('Refinery[M]', 'Refinery[M]'),
|
||||
('Refinery[L]', 'Refinery[L]'),
|
||||
('Station', 'Station'),
|
||||
('TCU', 'TCU'),
|
||||
('Astrahus', 'Astrahus'),
|
||||
('Fortizar', 'Fortizar'),
|
||||
('Keepstar', 'Keepstar'),
|
||||
('Raitaru', 'Raitaru'),
|
||||
('Azbel', 'Azbel'),
|
||||
('Sotiyo', 'Sotiyo'),
|
||||
('Athanor', 'Athanor'),
|
||||
('Tatara', 'Tatara'),
|
||||
('Pharolux Cyno Beacon', 'Pharolux Cyno Beacon'),
|
||||
('Tenebrex Cyno Jammer', 'Tenebrex Cyno Jammer'),
|
||||
('Ansiblex Jump Gate', 'Ansiblex Jump Gate'),
|
||||
('Moon Mining Cycle', 'Moon Mining Cycle'),
|
||||
(_('Other'), _('Other'))]
|
||||
objective_choices = [('Friendly', _('Friendly')),
|
||||
|
||||
@@ -18,7 +18,8 @@
|
||||
<div class="col-lg-12 text-center">
|
||||
<div class="label label-info text-left">
|
||||
<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>
|
||||
{% if corp_timers %}
|
||||
<h4><b>{% trans "Corp Timers" %}</b></h4>
|
||||
@@ -36,118 +37,128 @@
|
||||
{% endif %}
|
||||
</tr>
|
||||
{% for timer in corp_timers %}
|
||||
{% ifequal timer.important True %}
|
||||
{% if timer.important == True %}
|
||||
<tr class="danger">
|
||||
{% else %}
|
||||
<tr class="info">
|
||||
{% endifequal %}
|
||||
{% endif %}
|
||||
<td style="width:150px" class="text-center">{{ timer.details }}</td>
|
||||
<td class="text-center">
|
||||
{% ifequal timer.objective "Hostile" %}
|
||||
{% if timer.objective == "Hostile" %}
|
||||
<div class="label label-danger">
|
||||
{% trans "Hostile" %}
|
||||
</div>
|
||||
{% endifequal %}
|
||||
{% ifequal timer.objective "Friendly" %}
|
||||
{% endif %}
|
||||
{% if timer.objective == "Friendly" %}
|
||||
<div class="label label-primary">
|
||||
{% trans "Friendly" %}
|
||||
</div>
|
||||
{% endifequal %}
|
||||
{% ifequal timer.objective "Neutral" %}
|
||||
{% endif %}
|
||||
{% if timer.objective == "Neutral" %}
|
||||
<div class="label label-default">
|
||||
{% trans "Neutral" %}
|
||||
</div>
|
||||
{% endifequal %}
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="text-center"><a
|
||||
href="http://evemaps.dotlan.net/system/{{ timer.system }}">{{ timer.system }} {{ timer.planet_moon }} </a>
|
||||
</td>
|
||||
<td class="text-center">
|
||||
{% ifequal timer.structure "I-HUB" %}
|
||||
{% if timer.structure == "POCO" %}
|
||||
<div class="label label-info">
|
||||
POCO
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if timer.structure == "I-HUB" %}
|
||||
<div class="label label-warning">
|
||||
I-HUB
|
||||
</div>
|
||||
{% endifequal %}
|
||||
{% ifequal timer.structure "POCO" %}
|
||||
<div class="label label-success">
|
||||
POCO
|
||||
</div>
|
||||
{% endifequal %}
|
||||
{% ifequal timer.structure "POS[S]" %}
|
||||
<div class="label label-info">
|
||||
POS [S]
|
||||
</div>
|
||||
{% endifequal %}
|
||||
{% ifequal timer.structure "POS[M]" %}
|
||||
<div class="label label-info">
|
||||
POS [M]
|
||||
</div>
|
||||
{% endifequal %}
|
||||
{% ifequal timer.structure "POS[L]" %}
|
||||
<div class="label label-info">
|
||||
POS [L]
|
||||
</div>
|
||||
{% endifequal %}
|
||||
{% ifequal timer.structure "Citadel[M]" %}
|
||||
<div class="label label-danger">
|
||||
Citadel [M]
|
||||
</div>
|
||||
{% endifequal %}
|
||||
{% ifequal timer.structure "Citadel[L]" %}
|
||||
<div class="label label-danger">
|
||||
Citadel [L]
|
||||
</div>
|
||||
{% endifequal %}
|
||||
{% ifequal timer.structure "Citadel[XL]" %}
|
||||
<div class="label label-danger">
|
||||
Citadel [XL]
|
||||
</div>
|
||||
{% endifequal %}
|
||||
{% ifequal timer.structure "Engineering Complex[M]" %}
|
||||
<div class="label label-warning">
|
||||
Engineering Complex [M]
|
||||
</div>
|
||||
{% endifequal %}
|
||||
{% ifequal timer.structure "Engineering Complex[L]" %}
|
||||
<div class="label label-warning">
|
||||
Engineering Complex [L]
|
||||
</div>
|
||||
{% endifequal %}
|
||||
{% ifequal timer.structure "Engineering Complex[XL]" %}
|
||||
<div class="label label-warning">
|
||||
Engineering Complex [XL]
|
||||
</div>
|
||||
{% endifequal %}
|
||||
{% ifequal timer.structure "Station" %}
|
||||
<div class="label label-danger">
|
||||
Station
|
||||
</div>
|
||||
{% endifequal %}
|
||||
{% ifequal timer.structure "TCU" %}
|
||||
{% endif %}
|
||||
{% if timer.structure == "TCU" %}
|
||||
<div class="label label-danger">
|
||||
TCU
|
||||
</div>
|
||||
{% endifequal %}
|
||||
{% ifequal timer.structure "Refinery[M]" %}
|
||||
<div class="label label-warning">
|
||||
Refinery [M]
|
||||
{% endif %}
|
||||
{% if timer.structure == "POS[S]" %}
|
||||
<div class="label label-info">
|
||||
POS [S]
|
||||
</div>
|
||||
{% endifequal %}
|
||||
{% ifequal timer.structure "Refinery[L]" %}
|
||||
<div class="label label-warning">
|
||||
Refinery [L]
|
||||
{% endif %}
|
||||
{% if timer.structure == "POS[M]" %}
|
||||
<div class="label label-info">
|
||||
POS [M]
|
||||
</div>
|
||||
{% endifequal %}
|
||||
{% ifequal timer.structure "Moon Mining Cycle" %}
|
||||
{% endif %}
|
||||
{% if timer.structure == "POS[L]" %}
|
||||
<div class="label label-info">
|
||||
POS [L]
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if timer.structure == "Citadel[M]" or timer.structure == "Astrahus" %}
|
||||
<div class="label label-danger">
|
||||
Astrahus
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if timer.structure == "Citadel[L]" or timer.structure == "Fortizar" %}
|
||||
<div class="label label-danger">
|
||||
Fortizar
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if timer.structure == "Citadel[XL]" or timer.structure == "Keepstar" %}
|
||||
<div class="label label-danger">
|
||||
Keepstar
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if timer.structure == "Engineering Complex[M]" or timer.structure == "Raitaru" %}
|
||||
<div class="label label-warning">
|
||||
Raitaru
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if timer.structure == "Engineering Complex[L]" or timer.structure == "Azbel" %}
|
||||
<div class="label label-warning">
|
||||
Azbel
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if timer.structure == "Engineering Complex[XL]" or timer.structure == "Sotiyo" %}
|
||||
<div class="label label-warning">
|
||||
Sotiyo
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if timer.structure == "Refinery[M]" or timer.structure == "Athanor" %}
|
||||
<div class="label label-warning">
|
||||
Athanor
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if timer.structure == "Refinery[L]" or timer.structure == "Tatara"%}
|
||||
<div class="label label-warning">
|
||||
Tatara
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if timer.structure == "Cyno Beacon" or timer.structure == "Pharolux Cyno Beacon" %}
|
||||
<div class="label label-warning">
|
||||
Cyno Beacon
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if timer.structure == "Cyno Jammer" or timer.structure == "Tenebrex Cyno Jammer" %}
|
||||
<div class="label label-warning">
|
||||
Tenebrex Cyno Jammer
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if timer.structure == "Jump Gate" or timer.structure == "Ansiblex Jump Gate" %}
|
||||
<div class="label label-warning">
|
||||
Ansiblex Jump Gate
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if timer.structure == "Moon Mining Cycle" %}
|
||||
<div class="label label-success">
|
||||
Moon Mining Cycle
|
||||
</div>
|
||||
{% endifequal %}
|
||||
{% ifequal timer.structure "Other" %}
|
||||
{% endif %}
|
||||
{% if timer.structure == "Other" %}
|
||||
<div class="label label-default">
|
||||
Other
|
||||
</div>
|
||||
{% endifequal %}
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="text-center" nowrap>{{ timer.eve_time | date:"Y-m-d H:i" }}</td>
|
||||
<td class="text-center" nowrap>
|
||||
@@ -185,118 +196,128 @@
|
||||
{% endif %}
|
||||
</tr>
|
||||
{% for timer in future_timers %}
|
||||
{% ifequal timer.important True %}
|
||||
{% if timer.important == True %}
|
||||
<tr class="danger">
|
||||
{% else %}
|
||||
<tr class="info">
|
||||
{% endifequal %}
|
||||
{% endif %}
|
||||
<td style="width:150px" class="text-center">{{ timer.details }}</td>
|
||||
<td class="text-center">
|
||||
{% ifequal timer.objective "Hostile" %}
|
||||
{% if timer.objective == "Hostile" %}
|
||||
<div class="label label-danger">
|
||||
{% trans "Hostile" %}
|
||||
</div>
|
||||
{% endifequal %}
|
||||
{% ifequal timer.objective "Friendly" %}
|
||||
{% endif %}
|
||||
{% if timer.objective == "Friendly" %}
|
||||
<div class="label label-primary">
|
||||
{% trans "Friendly" %}
|
||||
</div>
|
||||
{% endifequal %}
|
||||
{% ifequal timer.objective "Neutral" %}
|
||||
{% endif %}
|
||||
{% if timer.objective == "Neutral" %}
|
||||
<div class="label label-default">
|
||||
{% trans "Neutral" %}
|
||||
</div>
|
||||
{% endifequal %}
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="text-center">
|
||||
<a href="http://evemaps.dotlan.net/system/{{ timer.system }}">{{ timer.system }} {{ timer.planet_moon }}</a>
|
||||
</td>
|
||||
<td class="text-center">
|
||||
{% ifequal timer.structure "I-HUB" %}
|
||||
<div class="label label-warning">
|
||||
I-HUB
|
||||
</div>
|
||||
{% endifequal %}
|
||||
{% ifequal timer.structure "POCO" %}
|
||||
<div class="label label-success">
|
||||
POCO
|
||||
</div>
|
||||
{% endifequal %}
|
||||
{% ifequal timer.structure "POS[S]" %}
|
||||
<div class="label label-info">
|
||||
POS [S]
|
||||
</div>
|
||||
{% endifequal %}
|
||||
{% ifequal timer.structure "POS[M]" %}
|
||||
<div class="label label-info">
|
||||
POS [M]
|
||||
</div>
|
||||
{% endifequal %}
|
||||
{% ifequal timer.structure "POS[L]" %}
|
||||
<div class="label label-info">
|
||||
POS [L]
|
||||
</div>
|
||||
{% endifequal %}
|
||||
{% ifequal timer.structure "Citadel[M]" %}
|
||||
<div class="label label-danger">
|
||||
Citadel [M]
|
||||
</div>
|
||||
{% endifequal %}
|
||||
{% ifequal timer.structure "Citadel[L]" %}
|
||||
<div class="label label-danger">
|
||||
Citadel [L]
|
||||
</div>
|
||||
{% endifequal %}
|
||||
{% ifequal timer.structure "Citadel[XL]" %}
|
||||
<div class="label label-danger">
|
||||
Citadel [XL]
|
||||
</div>
|
||||
{% endifequal %}
|
||||
{% ifequal timer.structure "Engineering Complex[M]" %}
|
||||
<div class="label label-warning">
|
||||
Engineering Complex [M]
|
||||
</div>
|
||||
{% endifequal %}
|
||||
{% ifequal timer.structure "Engineering Complex[L]" %}
|
||||
<div class="label label-warning">
|
||||
Engineering Complex [L]
|
||||
</div>
|
||||
{% endifequal %}
|
||||
{% ifequal timer.structure "Engineering Complex[XL]" %}
|
||||
<div class="label label-warning">
|
||||
Engineering Complex [XL]
|
||||
</div>
|
||||
{% endifequal %}
|
||||
{% ifequal timer.structure "Station" %}
|
||||
<div class="label label-danger">
|
||||
Station
|
||||
</div>
|
||||
{% endifequal %}
|
||||
{% ifequal timer.structure "TCU" %}
|
||||
<div class="label label-danger">
|
||||
TCU
|
||||
</div>
|
||||
{% endifequal %}
|
||||
{% ifequal timer.structure "Refinery[M]" %}
|
||||
<div class="label label-warning">
|
||||
Refinery [M]
|
||||
</div>
|
||||
{% endifequal %}
|
||||
{% ifequal timer.structure "Refinery[L]" %}
|
||||
<div class="label label-warning">
|
||||
Refinery [L]
|
||||
</div>
|
||||
{% endifequal %}
|
||||
{% ifequal timer.structure "Moon Mining Cycle" %}
|
||||
<div class="label label-success">
|
||||
Moon Mining Cycle
|
||||
</div>
|
||||
{% endifequal %}
|
||||
{% ifequal timer.structure "Other" %}
|
||||
<div class="label label-default">
|
||||
Other
|
||||
</div>
|
||||
{% endifequal %}
|
||||
{% if timer.structure == "POCO" %}
|
||||
<div class="label label-info">
|
||||
POCO
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if timer.structure == "I-HUB" %}
|
||||
<div class="label label-warning">
|
||||
I-HUB
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if timer.structure == "TCU" %}
|
||||
<div class="label label-danger">
|
||||
TCU
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if timer.structure == "POS[S]" %}
|
||||
<div class="label label-info">
|
||||
POS [S]
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if timer.structure == "POS[M]" %}
|
||||
<div class="label label-info">
|
||||
POS [M]
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if timer.structure == "POS[L]" %}
|
||||
<div class="label label-info">
|
||||
POS [L]
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if timer.structure == "Citadel[M]" or timer.structure == "Astrahus" %}
|
||||
<div class="label label-danger">
|
||||
Astrahus
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if timer.structure == "Citadel[L]" or timer.structure == "Fortizar" %}
|
||||
<div class="label label-danger">
|
||||
Fortizar
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if timer.structure == "Citadel[XL]" or timer.structure == "Keepstar" %}
|
||||
<div class="label label-danger">
|
||||
Keepstar
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if timer.structure == "Engineering Complex[M]" or timer.structure == "Raitaru" %}
|
||||
<div class="label label-warning">
|
||||
Raitaru
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if timer.structure == "Engineering Complex[L]" or timer.structure == "Azbel" %}
|
||||
<div class="label label-warning">
|
||||
Azbel
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if timer.structure == "Engineering Complex[XL]" or timer.structure == "Sotiyo" %}
|
||||
<div class="label label-warning">
|
||||
Sotiyo
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if timer.structure == "Refinery[M]" or timer.structure == "Athanor" %}
|
||||
<div class="label label-warning">
|
||||
Athanor
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if timer.structure == "Refinery[L]" or timer.structure == "Tatara" %}
|
||||
<div class="label label-warning">
|
||||
Tatara
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if timer.structure == "Cyno Beacon" or timer.structure == "Pharolux Cyno Beacon" %}
|
||||
<div class="label label-warning">
|
||||
Pharolux Cyno Beacon
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if timer.structure == "Cyno Jammer" or timer.structure == "Tenebrex Cyno Jammer" %}
|
||||
<div class="label label-warning">
|
||||
Tenebrex Cyno Jammer
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if timer.structure == "Jump Gate" or timer.structure == "Ansiblex Jump Gate" %}
|
||||
<div class="label label-warning">
|
||||
Ansiblex Jump Gate
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if timer.structure == "Moon Mining Cycle" %}
|
||||
<div class="label label-success">
|
||||
Moon Mining Cycle
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if timer.structure == "Other" %}
|
||||
<div class="label label-default">
|
||||
Other
|
||||
</div>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="text-center" nowrap>{{ timer.eve_time | date:"Y-m-d H:i" }}</td>
|
||||
<td class="text-center" nowrap>
|
||||
@@ -336,118 +357,128 @@
|
||||
{% endif %}
|
||||
</tr>
|
||||
{% for timer in past_timers %}
|
||||
{% ifequal timer.important True %}
|
||||
{% if timer.important == True %}
|
||||
<tr class="danger">
|
||||
{% else %}
|
||||
<tr class="info">
|
||||
{% endifequal %}
|
||||
{% endif %}
|
||||
<td style="width:150px" class="text-center">{{ timer.details }}</td>
|
||||
<td class="text-center">
|
||||
{% ifequal timer.objective "Hostile" %}
|
||||
{% if timer.objective == "Hostile" %}
|
||||
<div class="label label-danger">
|
||||
{% trans "Hostile" %}
|
||||
</div>
|
||||
{% endifequal %}
|
||||
{% ifequal timer.objective "Friendly" %}
|
||||
{% endif %}
|
||||
{% if timer.objective == "Friendly" %}
|
||||
<div class="label label-primary">
|
||||
{% trans "Friendly" %}
|
||||
</div>
|
||||
{% endifequal %}
|
||||
{% ifequal timer.objective "Neutral" %}
|
||||
{% endif %}
|
||||
{% if timer.objective == "Neutral" %}
|
||||
<div class="label label-default">
|
||||
{% trans "Neutral" %}
|
||||
</div>
|
||||
{% endifequal %}
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="text-center">
|
||||
<a href="http://evemaps.dotlan.net/system/{{ timer.system }}">{{ timer.system }} {{ timer.planet_moon }}</a>
|
||||
</td>
|
||||
<td class="text-center">
|
||||
{% ifequal timer.structure "I-HUB" %}
|
||||
<div class="label label-warning">
|
||||
I-HUB
|
||||
</div>
|
||||
{% endifequal %}
|
||||
{% ifequal timer.structure "POCO" %}
|
||||
<div class="label label-success">
|
||||
POCO
|
||||
</div>
|
||||
{% endifequal %}
|
||||
{% ifequal timer.structure "POS[S]" %}
|
||||
<div class="label label-info">
|
||||
POS [S]
|
||||
</div>
|
||||
{% endifequal %}
|
||||
{% ifequal timer.structure "POS[M]" %}
|
||||
<div class="label label-info">
|
||||
POS [M]
|
||||
</div>
|
||||
{% endifequal %}
|
||||
{% ifequal timer.structure "POS[L]" %}
|
||||
<div class="label label-info">
|
||||
POS [L]
|
||||
</div>
|
||||
{% endifequal %}
|
||||
{% ifequal timer.structure "Citadel[M]" %}
|
||||
<div class="label label-danger">
|
||||
Citadel [M]
|
||||
</div>
|
||||
{% endifequal %}
|
||||
{% ifequal timer.structure "Citadel[L]" %}
|
||||
<div class="label label-danger">
|
||||
Citadel [L]
|
||||
</div>
|
||||
{% endifequal %}
|
||||
{% ifequal timer.structure "Citadel[XL]" %}
|
||||
<div class="label label-danger">
|
||||
Citadel [XL]
|
||||
</div>
|
||||
{% endifequal %}
|
||||
{% ifequal timer.structure "Engineering Complex[M]" %}
|
||||
<div class="label label-warning">
|
||||
Engineering Complex [M]
|
||||
</div>
|
||||
{% endifequal %}
|
||||
{% ifequal timer.structure "Engineering Complex[L]" %}
|
||||
<div class="label label-warning">
|
||||
Engineering Complex [L]
|
||||
</div>
|
||||
{% endifequal %}
|
||||
{% ifequal timer.structure "Engineering Complex[XL]" %}
|
||||
<div class="label label-warning">
|
||||
Engineering Complex [XL]
|
||||
</div>
|
||||
{% endifequal %}
|
||||
{% ifequal timer.structure "Station" %}
|
||||
<div class="label label-danger">
|
||||
Station
|
||||
</div>
|
||||
{% endifequal %}
|
||||
{% ifequal timer.structure "TCU" %}
|
||||
<div class="label label-danger">
|
||||
TCU
|
||||
</div>
|
||||
{% endifequal %}
|
||||
{% ifequal timer.structure "Refinery[M]" %}
|
||||
<div class="label label-warning">
|
||||
Refinery [M]
|
||||
</div>
|
||||
{% endifequal %}
|
||||
{% ifequal timer.structure "Refinery[L]" %}
|
||||
<div class="label label-warning">
|
||||
Refinery [L]
|
||||
</div>
|
||||
{% endifequal %}
|
||||
{% ifequal timer.structure "Moon Mining Cycle" %}
|
||||
<div class="label label-success">
|
||||
Moon Mining Cycle
|
||||
</div>
|
||||
{% endifequal %}
|
||||
{% ifequal timer.structure "Other" %}
|
||||
<div class="label label-default">
|
||||
Other
|
||||
</div>
|
||||
{% endifequal %}
|
||||
{% if timer.structure == "POCO" %}
|
||||
<div class="label label-info">
|
||||
POCO
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if timer.structure == "I-HUB" %}
|
||||
<div class="label label-warning">
|
||||
I-HUB
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if timer.structure == "TCU" %}
|
||||
<div class="label label-danger">
|
||||
TCU
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if timer.structure == "POS[S]" %}
|
||||
<div class="label label-info">
|
||||
POS [S]
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if timer.structure == "POS[M]" %}
|
||||
<div class="label label-info">
|
||||
POS [M]
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if timer.structure == "POS[L]" %}
|
||||
<div class="label label-info">
|
||||
POS [L]
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if timer.structure == "Citadel[M]" or timer.structure == "Astrahus" %}
|
||||
<div class="label label-danger">
|
||||
Astrahus
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if timer.structure == "Citadel[L]" or timer.structure == "Fortizar" %}
|
||||
<div class="label label-danger">
|
||||
Fortizar
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if timer.structure == "Citadel[XL]" or timer.structure == "Keepstar" %}
|
||||
<div class="label label-danger">
|
||||
Keepstar
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if timer.structure == "Engineering Complex[M]" or timer.structure == "Raitaru" %}
|
||||
<div class="label label-warning">
|
||||
Raitaru
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if timer.structure == "Engineering Complex[L]" or timer.structure == "Azbel" %}
|
||||
<div class="label label-warning">
|
||||
Azbel
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if timer.structure == "Engineering Complex[XL]" or timer.structure == "Sotiyo" %}
|
||||
<div class="label label-warning">
|
||||
Sotiyo
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if timer.structure == "Refinery[M]" or timer.structure == "Athanor" %}
|
||||
<div class="label label-warning">
|
||||
Athanor
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if timer.structure == "Refinery[L]" or timer.structure == "Tatara" %}
|
||||
<div class="label label-warning">
|
||||
Tatara
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if timer.structure == "Cyno Beacon" or timer.structure == "Pharolux Cyno Beacon" %}
|
||||
<div class="label label-warning">
|
||||
Pharolux Cyno Beacon
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if timer.structure == "Cyno Jammer" or timer.structure == "Tenebrex Cyno Jammer" %}
|
||||
<div class="label label-warning">
|
||||
Tenebrex Cyno Jammer
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if timer.structure == "Jump Gate" or timer.structure == "Ansiblex Jump Gate" %}
|
||||
<div class="label label-warning">
|
||||
Ansiblex Jump Gate
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if timer.structure == "Moon Mining Cycle" %}
|
||||
<div class="label label-success">
|
||||
Moon Mining Cycle
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if timer.structure == "Other" %}
|
||||
<div class="label label-default">
|
||||
Other
|
||||
</div>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="text-center" nowrap>{{ timer.eve_time | date:"Y-m-d H:i" }}</td>
|
||||
<td class="text-center" nowrap>
|
||||
@@ -555,7 +586,7 @@
|
||||
}
|
||||
|
||||
function updateClock() {
|
||||
document.getElementById("current-time").innerHTML = "<b>" + moment().format('LLLL') + "</b>";
|
||||
document.getElementById("current-time").innerHTML = getCurrentEveTimeString();
|
||||
}
|
||||
</script>
|
||||
{% endblock content %}
|
||||
|
||||
BIN
docs/_static/images/features/group_audit_log.png
vendored
Normal file
BIN
docs/_static/images/features/group_audit_log.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 31 KiB |
@@ -66,6 +66,17 @@ Clicking on the blue eye will take you to the group member management screen. He
|
||||
|
||||

|
||||
|
||||
### Group Audit Log
|
||||
Whenever a user Joins, Leaves, or is Removed from a group, this is logged. To find the audit log for a given group, click the light-blue button to the right of the Group Member Management (blue eye) button.
|
||||
|
||||
These logs contain the Date and Time the action was taken (in EVE/UTC), the user which submitted the request being acted upon (requestor), the user's main character, the type of request (join, leave or removed), the action taken (accept, reject or remove), and the user that took the action (actor).
|
||||
|
||||

|
||||
|
||||
```eval_rst
|
||||
.. note::
|
||||
There is no tracking for "Open" groups as members are able to freely join/leave these groups.
|
||||
```
|
||||
|
||||
## Group Leaders
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
```eval_rst
|
||||
.. tip::
|
||||
If you are uncomfortable with Linux permissions follow the steps below as the root user.
|
||||
If you are uncomfortable with Linux permissions follow the steps below as the root user.
|
||||
```
|
||||
|
||||
## Dependencies
|
||||
@@ -12,7 +12,7 @@ Alliance Auth can be installed on any operating system. Dependencies are provide
|
||||
```eval_rst
|
||||
.. hint::
|
||||
CentOS: A few packages are included in a non-default repository. Add it and update the package lists. ::
|
||||
|
||||
|
||||
yum -y install https://centos7.iuscommunity.org/ius-release.rpm
|
||||
yum update
|
||||
```
|
||||
@@ -39,7 +39,7 @@ Ubuntu:
|
||||
|
||||
CentOS:
|
||||
|
||||
yum install mariadb-server mariadb-devel mariadb
|
||||
yum install mariadb-server mariadb-devel mariadb-shared mariadb
|
||||
|
||||
```eval_rst
|
||||
.. note::
|
||||
@@ -61,7 +61,7 @@ CentOS:
|
||||
```eval_rst
|
||||
.. important::
|
||||
CentOS: Make sure Redis is running before continuing. ::
|
||||
|
||||
|
||||
systemctl enable redis.service
|
||||
systemctl start redis.service
|
||||
```
|
||||
@@ -71,9 +71,22 @@ CentOS:
|
||||
Alliance Auth needs a MySQL user account and database. Open an SQL shell with `mysql -u root -p` and create them as follows, replacing `PASSWORD` with an actual secure password:
|
||||
|
||||
CREATE USER 'allianceserver'@'localhost' IDENTIFIED BY 'PASSWORD';
|
||||
CREATE DATABASE alliance_auth CHARACTER SET utf8;
|
||||
CREATE DATABASE alliance_auth CHARACTER SET utf8mb4;
|
||||
GRANT ALL PRIVILEGES ON alliance_auth . * TO 'allianceserver'@'localhost';
|
||||
|
||||
Add timezone tables to your mysql installation:
|
||||
|
||||
mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql -u root -p mysql
|
||||
|
||||
```eval_rst
|
||||
.. note::
|
||||
You may see errors when you add the timezone tables. To make sure that they were correctly added run the following commands and check for the ``time_zone`` tables::
|
||||
|
||||
mysql -u root -p
|
||||
use mysql;
|
||||
show tables;
|
||||
```
|
||||
|
||||
Close the SQL shell and secure your database server with the `mysql_secure_installation` command.
|
||||
|
||||
## Auth Install
|
||||
@@ -106,7 +119,7 @@ Create a Python virtual environment and put it somewhere convenient (e.g. `/home
|
||||
A virtual environment provides support for creating a lightweight "copy" of Python with their own site directories. Each virtual environment has its own Python binary (allowing creation of environments with various Python versions) and can have its own independent set of installed Python packages in its site directories. You can read more about virtual environments on the Python_ docs.
|
||||
.. _Python: https://docs.python.org/3/library/venv.html
|
||||
```
|
||||
|
||||
|
||||
Activate the virtualenv using `source /home/allianceserver/venv/auth/bin/activate`. Note the `/bin/activate` on the end of the path.
|
||||
|
||||
```eval_rst
|
||||
@@ -131,7 +144,7 @@ Django needs to install models to the database before it can start.
|
||||
python /home/allianceserver/myauth/manage.py migrate
|
||||
|
||||
Now we need to round up all the static files required to render templates. Make a directory to serve them from and populate it.
|
||||
|
||||
|
||||
mkdir -p /var/www/myauth/static
|
||||
python /home/allianceserver/myauth/manage.py collectstatic
|
||||
|
||||
@@ -182,7 +195,7 @@ You can check the status of the processes with `supervisorctl status`. Logs from
|
||||
```eval_rst
|
||||
.. note::
|
||||
Any time the code or your settings change you'll need to restart Gunicorn and Celery. ::
|
||||
|
||||
|
||||
supervisorctl restart myauth:
|
||||
```
|
||||
|
||||
@@ -202,10 +215,10 @@ If you intend to use this account as your personal auth account you need to add
|
||||
|
||||
## Updating
|
||||
|
||||
Periodically [new releases](https://github.com/allianceauth/allianceauth/releases/) are issued with bug fixes and new features. To update your install, simply activate your virtual environment and update with `pip install --upgrade allianceauth`. Be sure to read the release notes which will highlight changes.
|
||||
Periodically [new releases](https://gitlab.com/allianceauth/allianceauth/tags) are issued with bug fixes and new features. To update your install, simply activate your virtual environment and update with `pip install --upgrade allianceauth`. Be sure to read the release notes which will highlight changes.
|
||||
|
||||
Some releases come with changes to settings: update your project's settings with `allianceauth update /home/allianceserver/myauth`.
|
||||
|
||||
Some releases come with new or changed models. Update your database to reflect this with `python /home/allianceserver/myauth/manage.py migrate`.
|
||||
|
||||
|
||||
Always restart Celery and Gunicorn after updating.
|
||||
|
||||
@@ -56,7 +56,7 @@ Put comma-separated IDs into the brackets and the migration will create states w
|
||||
|
||||
If you used member/blue group names other than the standard "Member" and "Blue" you can enter settings to have the member/blue states created through this migration take these names.
|
||||
- `DEFAULT_AUTH_GROUP = ""` the desired name of the "Member" state
|
||||
- `DEFAULT_BLUE_GROUP = ""` the desired name of the "Blue" state
|
||||
- `DEFAULT_BLUE_GROUP = ""` the desired name of the "Blue" state
|
||||
|
||||
Any permissions assigned to these groups will be copied to the state replacing them. Because these groups are no longer managed they pose a security risk and so are deleted at the end of the migration automatically.
|
||||
|
||||
@@ -82,4 +82,4 @@ A similar process can be used to ensure users who may have lost service permissi
|
||||
|
||||
## Help
|
||||
|
||||
If something goes wrong during the migration reach out for help on [Gitter](https://gitter.im/R4stl1n/allianceauth) or open an [issue](https://github.com/allianceauth/allianceauth/issues).
|
||||
If something goes wrong during the migration reach out for help on [Gitter](https://gitter.im/R4stl1n/allianceauth) or open an [issue](https://gitlab.com/allianceauth/allianceauth/issues).
|
||||
|
||||
@@ -1,161 +1,7 @@
|
||||
# Alliance Market
|
||||
|
||||
## Dependencies
|
||||
Alliance Market requires PHP installed in your web server. Apache has `mod_php`, NGINX requires `php-fpm`.
|
||||
## Deprecation
|
||||
|
||||
## Prepare Your Settings
|
||||
In your auth project's settings file, do the following:
|
||||
- Add `'allianceauth.services.modules.market',` to your `INSTALLED_APPS` list
|
||||
- Append the following to the bottom of the settings file
|
||||
Alliance Market relies on the now non-functional XML API.
|
||||
|
||||
|
||||
# Alliance Market
|
||||
MARKET_URL = ''
|
||||
DATABASES['market'] = {
|
||||
'ENGINE': 'django.db.backends.mysql',
|
||||
'NAME': 'alliance_market',
|
||||
'USER': 'allianceserver-market',
|
||||
'PASSWORD': 'password',
|
||||
'HOST': '127.0.0.1',
|
||||
'PORT': '3306',
|
||||
}
|
||||
|
||||
## Setup Alliance Market
|
||||
Alliance Market needs a database. Create one in MySQL/MariaDB. Default name is `alliance_market`:
|
||||
|
||||
mysql -u root -p
|
||||
create database alliance_market;
|
||||
grant all privileges on alliance_market . * to 'allianceserver'@'localhost';
|
||||
exit;
|
||||
|
||||
Install required packages to clone the repository:
|
||||
|
||||
apt-get install mercurial meld
|
||||
|
||||
Change to the web folder:
|
||||
|
||||
cd /var/www
|
||||
|
||||
Now clone the repository
|
||||
|
||||
hg clone https://bitbucket.org/krojew/evernus-alliance-market
|
||||
|
||||
Make cache and log directories
|
||||
|
||||
mkdir evernus-alliance-market/app/cache
|
||||
mkdir evernus-alliance-market/app/logs
|
||||
chmod -R 777 evernus-alliance-market/app/cache
|
||||
chmod -R 777 evernus-alliance-market/app/logs
|
||||
|
||||
Change ownership to apache
|
||||
|
||||
chown -R www-data:www-data evernus-alliance-market
|
||||
|
||||
Enter directory
|
||||
|
||||
cd evernus-alliance-market
|
||||
|
||||
Set environment variable
|
||||
|
||||
export SYMFONY_ENV=prod
|
||||
|
||||
Copy configuration
|
||||
|
||||
cp app/config/parameters.yml.dist app/config/parameters.yml
|
||||
|
||||
Edit, changing the following:
|
||||
- `database_name` to `alliance_market`
|
||||
- `database_user` to your MySQL user (usually `allianceserver`)
|
||||
- `database_password` to your MySQL user password
|
||||
- email settings, eg Gmail/Mailgun etc.
|
||||
|
||||
Edit `app/config/config.yml` and add the following:
|
||||
|
||||
services:
|
||||
fos_user.doctrine_registry:
|
||||
alias: doctrine
|
||||
|
||||
Install composer [as per these instructions.](https://getcomposer.org/download/)
|
||||
|
||||
Update dependencies.
|
||||
|
||||
php composer.phar update --optimize-autoloader
|
||||
|
||||
Prepare the cache:
|
||||
|
||||
php app/console cache:clear --env=prod --no-debug
|
||||
|
||||
|
||||
Dump assets:
|
||||
|
||||
php app/console assetic:dump --env=prod --no-debug
|
||||
|
||||
|
||||
Create DB entries
|
||||
|
||||
php app/console doctrine:schema:update --force
|
||||
|
||||
Install SDE:
|
||||
|
||||
php app/console evernus:update:sde
|
||||
|
||||
Configure your web server to serve alliance market.
|
||||
|
||||
A minimal Apache config might look like:
|
||||
|
||||
<VirtualHost *:80>
|
||||
ServerName market.example.com
|
||||
DocumentRoot /var/www/evernus-alliance-market/web
|
||||
<Directory "/var/www/evernus-alliance-market/web/">
|
||||
DirectoryIndex app.php
|
||||
Require all granted
|
||||
AllowOverride all
|
||||
</Directory>
|
||||
</VirtualHost>
|
||||
|
||||
A minimal Nginx config might look like:
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
server_name market.example.com;
|
||||
root /var/www/evernus-alliance-market/web;
|
||||
index app.php;
|
||||
access_log /var/logs/market.access.log;
|
||||
|
||||
# strip app.php/ prefix if it is present
|
||||
rewrite ^/app\.php/?(.*)$ /$1 permanent;
|
||||
|
||||
location / {
|
||||
index app.php;
|
||||
try_files $uri @rewriteapp;
|
||||
}
|
||||
|
||||
location @rewriteapp {
|
||||
rewrite ^(.*)$ /app.php/$1 last;
|
||||
}
|
||||
|
||||
# pass the PHP scripts to FastCGI server from upstream phpfcgi
|
||||
location ~ ^/(app|app_dev|config)\.php(/|$) {
|
||||
fastcgi_pass 127.0.0.1:9000;
|
||||
fastcgi_split_path_info ^(.+\.php)(/.*)$;
|
||||
include fastcgi_params;
|
||||
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
||||
fastcgi_param HTTPS off;
|
||||
}
|
||||
|
||||
location ~ /\.ht {
|
||||
deny all;
|
||||
}
|
||||
}
|
||||
|
||||
Once again, set cache permissions:
|
||||
|
||||
chown -R www-data:www-data app/
|
||||
|
||||
Add a user account through auth, then make it a superuser:
|
||||
|
||||
php app/console fos:user:promote your_username --super
|
||||
|
||||
Now edit your auth project's settings file and fill in the web URL to your market as well as the database details.
|
||||
|
||||
Finally run migrations and restart Gunicorn and Celery.
|
||||
Please remove this service data with `python manage.py migrate appname zero` and then remove from your `INSTALLED_APPS` list.
|
||||
|
||||
@@ -22,7 +22,7 @@ Now two packages need to be installed:
|
||||
|
||||
apt-get install python-software-properties mumble-server
|
||||
|
||||
Download the appropriate authenticator release from [the authenticator repository](https://github.com/allianceauth/mumble-authenticator) and install the python dependencies for it:
|
||||
Download the appropriate authenticator release from [the authenticator repository](https://gitlab.com/allianceauth/mumble-authenticator) and install the python dependencies for it:
|
||||
|
||||
pip install -r requirements.txt
|
||||
|
||||
@@ -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:
|
||||
|
||||
- `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:
|
||||
|
||||
@@ -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
|
||||
|
||||
Save and close the file (control + O, control + X).
|
||||
Save and close the file.
|
||||
|
||||
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
|
||||
|
||||
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.
|
||||
|
||||
|
||||
@@ -58,7 +58,7 @@ Nginx: `chown -R nginx:nginx /var/www/forums`
|
||||
|
||||
```eval_rst
|
||||
.. tip::
|
||||
Nginx: Some distributions use the ``www-data:www-data`` user:group instead of ``nginx:nginx``. If you run into problems with permissions try it instead.
|
||||
Nginx: Some distributions use the ``www-data:www-data`` user:group instead of ``nginx:nginx``. If you run into problems with permissions try it instead.
|
||||
..
|
||||
```
|
||||
|
||||
@@ -103,7 +103,7 @@ A minimal Nginx config file might look like:
|
||||
}
|
||||
}
|
||||
|
||||
Enter your forum's web address as the `PHPBB3_URL` setting in your auth project's settings file.
|
||||
Enter your forum's web address as the `PHPBB3_URL` setting in your auth project's settings file.
|
||||
|
||||
### Web Install
|
||||
Navigate to your forums web address where you will be presented with an installer.
|
||||
@@ -144,5 +144,15 @@ You can allow members to overwrite the portrait with a custom image if desired.
|
||||
|
||||

|
||||
|
||||
## Setting the default theme
|
||||
|
||||
Users generated via Alliance Auth do not have a default theme set. You will need to set this on the phpbb_users table in SQL
|
||||
|
||||
mysql -u root -p
|
||||
use alliance_forum;
|
||||
alter table phpbb_users change user_style user_style int not null default 1
|
||||
|
||||
If you would like to use a theme that is NOT prosilver or theme "1". You will need to deactivate prosilver, this will then fall over to the set forum wide default.
|
||||
|
||||
### Prepare Auth
|
||||
Once settings have been configured, run migrations and restart Gunicorn and Celery.
|
||||
|
||||
@@ -2,17 +2,17 @@
|
||||
|
||||
## Something broken? Stuck on an issue? Can't get it set up?
|
||||
|
||||
Start by checking the [issues](https://github.com/allianceauth/allianceauth/issues?q=is%3Aissue) - especially closed ones.
|
||||
Start by checking the [issues](https://gitlab.com/allianceauth/allianceauth/issues?scope=all&utf8=%E2%9C%93&state=all&search=my+issue) - especially closed ones.
|
||||
|
||||
No answer?
|
||||
- open an [issue](https://github.com/allianceauth/allianceauth/issues)
|
||||
- open an [issue](https://gitlab.com/allianceauth/allianceauth/issues)
|
||||
- harass us on [gitter](https://gitter.im/R4stl1n/allianceauth)
|
||||
|
||||
|
||||
## Logging
|
||||
|
||||
In its default configuration your auth project logs INFO and above messages to myauth/log/allianceauth.log. If you're encountering issues it's a good idea to view DEBUG messages as these greatly assist the troubleshooting process. These are printed to the console with manually starting the webserver via `python manage.py runserver`.
|
||||
|
||||
To record DEBUG messages in the log file, alter a setting in your auth project's settings file: `LOGGING['handlers']['log_file']['level'] = 'DEBUG'`. After restarting gunicorn and celery your log file will record all logging messages.
|
||||
To record DEBUG messages in the log file, alter a setting in your auth project's settings file: `LOGGING['handlers']['log_file']['level'] = 'DEBUG'`. After restarting gunicorn and celery your log file will record all logging messages.
|
||||
|
||||
## Common Problems
|
||||
|
||||
|
||||
13
setup.py
13
setup.py
@@ -12,21 +12,22 @@ install_requires = [
|
||||
'requests-oauthlib',
|
||||
'semantic_version',
|
||||
|
||||
'redis',
|
||||
'celery>=4.0.2',
|
||||
'redis<=2.10.6',
|
||||
'celery>=4.0.2,<4.3.0',
|
||||
'celery_once',
|
||||
|
||||
'django>=1.11',
|
||||
'django>=2.0',
|
||||
'django-bootstrap-form',
|
||||
'django-registration==2.4',
|
||||
'django-sortedm2m',
|
||||
'django-redis-cache>=1.7.1',
|
||||
'django-celery-beat',
|
||||
'django-redis-cache==1.8.1',
|
||||
'django-celery-beat<=1.1.1',
|
||||
|
||||
'openfire-restapi',
|
||||
'sleekxmpp',
|
||||
|
||||
'adarnauth-esi>=1.4.10,<2.0',
|
||||
'kombu<=4.3.0',
|
||||
]
|
||||
|
||||
testing_extras = [
|
||||
@@ -50,7 +51,7 @@ setup(
|
||||
python_requires='~=3.4',
|
||||
license='GPLv2',
|
||||
packages=['allianceauth'],
|
||||
url='https://github.com/allianceauth/allianceauth',
|
||||
url='https://gitlab.com/allianceauth/allianceauth',
|
||||
zip_safe=False,
|
||||
include_package_data=True,
|
||||
entry_points="""
|
||||
|
||||
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/celery/kombu/zipball/master#egg=kombu
|
||||
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