Compare commits

...

13 Commits

Author SHA1 Message Date
Adarnof
6d6a3a3d6b Allow viewing corpstats added by the user.
Order corpstats by corp name.
2018-05-10 14:25:57 -04:00
colcrunch
5006246cf1 Build TS perm key using State Information (#1044)
Build permkey with state group id
Pass user object to add_user instead of just username

Fixes #1043
2018-05-09 20:39:14 -04:00
Basraah
6187fb9b86 Timer JS fixes (#1054)
Add months to duration output
Update momentjs
Move EVE time generation function to shared source

Fixes timerboard showing EVE time as local time.
Changed to show 24 hour time.
2018-05-09 20:31:02 -04:00
Adarnof
86f57ccd56 Allow reversing service migrations.
This is probably the wrong way as we should really take care of removing the permission we added, but I don't see a reason anyone would need to migrate back that far as auth wouldn't work anymore without XML api (and even so newer installs don't have the settings referenced so permissions are not automagically added by the migration). So noop is bad but acceptable to me.

Thanks @mmolitor87
2018-05-08 10:06:58 -04:00
colcrunch
854096bac7 fix alliancelogo on corp stats page 2018-05-07 23:26:37 -04:00
Adarnof
9d2b3bb157 Include compiled messages.
It doesn't work without these if DEBUG is False. And users can't compile them outside the allianceauth source directory.

When editing translations, compile with: django-admin compilemessages --settings=allianceauth.project_template.project_name.settings.base
2018-05-02 21:42:26 -04:00
Adarnof
22bda62e59 Spanish translations courtesy of @frank1210
Fixed a few problems with translating the menu links - they had leading spaces.
2018-05-02 20:49:21 -04:00
Adarnof
7212a7a328 Example supervisor config for authenticator. Ensure ICE is active in config. 2018-05-01 16:40:37 -04:00
Adarnof
f6b1b7b6bb Do not check mains when user has no profile.
This can occur when a user is being deleted: Django deletes the UserProfile, followed by the CharacterOwnerships which triggers the main check. As the user doesn't have a profile it explodes.

Thanks @Slevinator
2018-04-30 17:29:06 -04:00
Adarnof
53a9d72c4a Correct reversing states back to groups. 2018-04-30 17:24:31 -04:00
Adarnof
ca10fbcde5 Translate Member/Blue to custom state names.
Closes #1037
2018-04-25 17:20:28 -04:00
randomic
b4d33e5dfc Fix retry logic being suppressed by try block (#1035) 2018-04-24 11:53:13 -04:00
Adarnof
37bed989f1 Requires mariadb-shared for mysqlclient on centos.
Thanks @rlayne
2018-04-22 12:50:22 -04:00
37 changed files with 2195 additions and 119 deletions

1
.gitignore vendored
View File

@@ -42,7 +42,6 @@ nosetests.xml
coverage.xml coverage.xml
# Translations # Translations
*.mo
*.pot *.pot
# Django stuff: # Django stuff:

View File

@@ -1,7 +1,7 @@
# This will make sure the app is always imported when # This will make sure the app is always imported when
# Django starts so that shared_task will use this app. # Django starts so that shared_task will use this app.
__version__ = '2.0.0' __version__ = '2.0.2'
NAME = 'Alliance Auth v%s' % __version__ NAME = 'Alliance Auth v%s' % __version__
default_app_config = 'allianceauth.apps.AllianceAuthConfig' default_app_config = 'allianceauth.apps.AllianceAuthConfig'

View File

@@ -43,7 +43,7 @@ def create_member_group(apps, schema_editor):
member_state_name = getattr(settings, 'DEFAULT_AUTH_GROUP', 'Member') member_state_name = getattr(settings, 'DEFAULT_AUTH_GROUP', 'Member')
try: try:
g = Group.objects.get(name=member_state_name) g, _ = Group.objects.get_or_create(name=member_state_name)
# move permissions back # move permissions back
state = State.objects.get(name=member_state_name) state = State.objects.get(name=member_state_name)
[g.permissions.add(p.pk) for p in state.permissions.all()] [g.permissions.add(p.pk) for p in state.permissions.all()]
@@ -51,7 +51,7 @@ def create_member_group(apps, schema_editor):
# move users back # move users back
for profile in state.userprofile_set.all().select_related('user'): for profile in state.userprofile_set.all().select_related('user'):
profile.user.groups.add(g.pk) profile.user.groups.add(g.pk)
except (Group.DoesNotExist, State.DoesNotExist): except State.DoesNotExist:
pass pass
@@ -67,7 +67,7 @@ def create_blue_state(apps, schema_editor):
# move group permissions to state # move group permissions to state
g = Group.objects.get(name=blue_state_name) g = Group.objects.get(name=blue_state_name)
[s.permissions.add(p.pk) for p in g.permissions.all()] [s.permissions.add(p.pk) for p in g.permissions.all()]
g.permissions.clear() g.delete()
except Group.DoesNotExist: except Group.DoesNotExist:
pass pass
@@ -84,7 +84,7 @@ def create_blue_group(apps, schema_editor):
blue_state_name = getattr(settings, 'DEFAULT_BLUE_GROUP', 'Blue') blue_state_name = getattr(settings, 'DEFAULT_BLUE_GROUP', 'Blue')
try: try:
g = Group.objects.get(name=blue_state_name) g, _ = Group.objects.get_or_create(name=blue_state_name)
# move permissions back # move permissions back
state = State.objects.get(name=blue_state_name) state = State.objects.get(name=blue_state_name)
[g.permissions.add(p.pk) for p in state.permissions.all()] [g.permissions.add(p.pk) for p in state.permissions.all()]
@@ -92,7 +92,7 @@ def create_blue_group(apps, schema_editor):
# move users back # move users back
for profile in state.userprofile_set.all().select_related('user'): for profile in state.userprofile_set.all().select_related('user'):
profile.user.groups.add(g.pk) profile.user.groups.add(g.pk)
except (Group.DoesNotExist, State.DoesNotExist): except State.DoesNotExist:
pass pass
@@ -133,15 +133,24 @@ def create_profiles(apps, schema_editor):
auth['n'] == 1 and EveCharacter.objects.filter(character_id=auth['main_char_id']).exists()] auth['n'] == 1 and EveCharacter.objects.filter(character_id=auth['main_char_id']).exists()]
auths = AuthServicesInfo.objects.filter(main_char_id__in=unique_mains).select_related('user') auths = AuthServicesInfo.objects.filter(main_char_id__in=unique_mains).select_related('user')
blue_state_name = getattr(settings, 'DEFAULT_BLUE_GROUP', 'Blue')
member_state_name = getattr(settings, 'DEFAULT_AUTH_GROUP', 'Member')
states = {
'Member': State.objects.get(name=member_state_name),
'Blue': State.objects.get(name=blue_state_name),
}
guest_state = State.objects.get(name='Guest')
for auth in auths: for auth in auths:
# carry states and mains forward # carry states and mains forward
state = State.objects.get(name=auth.state if auth.state else 'Guest') state = states.get(auth.state, guest_state)
char = EveCharacter.objects.get(character_id=auth.main_char_id) char = EveCharacter.objects.get(character_id=auth.main_char_id)
UserProfile.objects.create(user=auth.user, state=state, main_character=char) UserProfile.objects.create(user=auth.user, state=state, main_character=char)
for auth in AuthServicesInfo.objects.exclude(main_char_id__in=unique_mains).select_related('user'): for auth in AuthServicesInfo.objects.exclude(main_char_id__in=unique_mains).select_related('user'):
# prepare empty profiles # prepare empty profiles
state = State.objects.get(name='Guest') UserProfile.objects.create(user=auth.user, state=guest_state)
UserProfile.objects.create(user=auth.user, state=state)
def recreate_authservicesinfo(apps, schema_editor): def recreate_authservicesinfo(apps, schema_editor):
@@ -149,6 +158,14 @@ def recreate_authservicesinfo(apps, schema_editor):
UserProfile = apps.get_model('authentication', 'UserProfile') UserProfile = apps.get_model('authentication', 'UserProfile')
User = apps.get_model('auth', 'User') User = apps.get_model('auth', 'User')
blue_state_name = getattr(settings, 'DEFAULT_BLUE_GROUP', 'Blue')
member_state_name = getattr(settings, 'DEFAULT_AUTH_GROUP', 'Member')
states = {
member_state_name: 'Member',
blue_state_name: 'Blue',
}
# recreate all missing AuthServicesInfo models # recreate all missing AuthServicesInfo models
AuthServicesInfo.objects.bulk_create([AuthServicesInfo(user_id=u.pk) for u in User.objects.all()]) AuthServicesInfo.objects.bulk_create([AuthServicesInfo(user_id=u.pk) for u in User.objects.all()])
@@ -159,8 +176,8 @@ def recreate_authservicesinfo(apps, schema_editor):
# repopulate states we understand # repopulate states we understand
for profile in UserProfile.objects.exclude(state__name='Guest').filter( for profile in UserProfile.objects.exclude(state__name='Guest').filter(
state__name__in=['Member', 'Blue']).select_related('user', 'state'): state__name__in=[member_state_name, blue_state_name]).select_related('user', 'state'):
AuthServicesInfo.objects.update_or_create(user=profile.user, defaults={'state': profile.state.name}) AuthServicesInfo.objects.update_or_create(user=profile.user, defaults={'state': states[profile.state.name]})
def disable_passwords(apps, schema_editor): def disable_passwords(apps, schema_editor):

View File

@@ -103,12 +103,16 @@ def record_character_ownership(sender, instance, created, *args, **kwargs):
@receiver(pre_delete, sender=CharacterOwnership) @receiver(pre_delete, sender=CharacterOwnership)
def validate_main_character(sender, instance, *args, **kwargs): def validate_main_character(sender, instance, *args, **kwargs):
if instance.user.profile.main_character == instance.character: try:
logger.info("Ownership of a main character {0} has been revoked. Resetting {1} main character.".format( if instance.user.profile.main_character == instance.character:
instance.character, instance.user)) logger.info("Ownership of a main character {0} has been revoked. Resetting {1} main character.".format(
# clear main character as user no longer owns them instance.character, instance.user))
instance.user.profile.main_character = None # clear main character as user no longer owns them
instance.user.profile.save() instance.user.profile.main_character = None
instance.user.profile.save()
except UserProfile.DoesNotExist:
# a user is being deleted
pass
@receiver(post_delete, sender=Token) @receiver(post_delete, sender=Token)

View File

@@ -1,5 +1,5 @@
from allianceauth.services.hooks import MenuItemHook, UrlHook from allianceauth.services.hooks import MenuItemHook, UrlHook
from django.utils.translation import ugettext_lazy as _
from allianceauth import hooks from allianceauth import hooks
from allianceauth.corputils import urls from allianceauth.corputils import urls
@@ -7,7 +7,7 @@ from allianceauth.corputils import urls
class CorpStats(MenuItemHook): class CorpStats(MenuItemHook):
def __init__(self): def __init__(self):
MenuItemHook.__init__(self, MenuItemHook.__init__(self,
'Corporation Stats', _('Corporation Stats'),
'fa fa-share-alt fa-fw', 'fa fa-share-alt fa-fw',
'corputils:view', 'corputils:view',
navactive=['corputils:']) navactive=['corputils:'])

View File

@@ -11,7 +11,7 @@
{% if corpstats.corp.alliance %}{% else %}col-lg-offset-3{% endif %}"><img {% if corpstats.corp.alliance %}{% else %}col-lg-offset-3{% endif %}"><img
class="ra-avatar" src="{{ corpstats.corp.logo_url_128 }}"></td> class="ra-avatar" src="{{ corpstats.corp.logo_url_128 }}"></td>
{% if corpstats.corp.alliance %} {% if corpstats.corp.alliance %}
<td class="text-center col-lg-6"><img class="ra-avatar" src="{{ corpstats.alliance.logo_url_128 }}"> <td class="text-center col-lg-6"><img class="ra-avatar" src="{{ corpstats.corp.alliance.logo_url_128 }}">
</td> </td>
{% endif %} {% endif %}
</tr> </tr>
@@ -202,4 +202,4 @@
}); });
}); });
{% endblock %} {% endblock %}

View File

@@ -17,7 +17,8 @@ SWAGGER_SPEC_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'sw
def access_corpstats_test(user): def access_corpstats_test(user):
return user.has_perm('corputils.view_corp_corpstats') or user.has_perm( return user.has_perm('corputils.view_corp_corpstats') or user.has_perm(
'corputils.view_alliance_corpstats') or user.has_perm('corputils.view_state_corpstats') 'corputils.view_alliance_corpstats') or user.has_perm('corputils.view_state_corpstats') or user.has_perm(
'corputils.add_corpstats')
@login_required @login_required
@@ -62,7 +63,7 @@ def corpstats_view(request, corp_id=None):
corpstats = get_object_or_404(CorpStats, corp=corp) corpstats = get_object_or_404(CorpStats, corp=corp)
# get available models # get available models
available = CorpStats.objects.visible_to(request.user) available = CorpStats.objects.visible_to(request.user).order_by('corp__corporation_name')
# ensure we can see the requested model # ensure we can see the requested model
if corpstats and corpstats not in available: if corpstats and corpstats not in available:

View File

@@ -1,12 +1,12 @@
from . import urls from . import urls
from django.utils.translation import ugettext_lazy as _
from allianceauth import hooks from allianceauth import hooks
from allianceauth.services.hooks import MenuItemHook, UrlHook from allianceauth.services.hooks import MenuItemHook, UrlHook
@hooks.register('menu_item_hook') @hooks.register('menu_item_hook')
def register_menu(): def register_menu():
return MenuItemHook('Fleet Activity Tracking', 'fa fa-users fa-lightbulb-o fa-fw', 'fatlink:view', return MenuItemHook(_('Fleet Activity Tracking'), 'fa fa-users fa-lightbulb-o fa-fw', 'fatlink:view',
navactive=['fatlink:']) navactive=['fatlink:'])

View File

@@ -1,5 +1,5 @@
from allianceauth.services.hooks import MenuItemHook, UrlHook from allianceauth.services.hooks import MenuItemHook, UrlHook
from django.utils.translation import ugettext_lazy as _
from allianceauth import hooks from allianceauth import hooks
from allianceauth.hrapplications import urls from allianceauth.hrapplications import urls
@@ -7,7 +7,7 @@ from allianceauth.hrapplications import urls
class ApplicationsMenu(MenuItemHook): class ApplicationsMenu(MenuItemHook):
def __init__(self): def __init__(self):
MenuItemHook.__init__(self, MenuItemHook.__init__(self,
'Applications', _('Applications'),
'fa fa-file-o fa-fw', 'fa fa-file-o fa-fw',
'hrapplications:index', 'hrapplications:index',
navactive=['hrapplications:']) navactive=['hrapplications:'])

Binary file not shown.

View File

@@ -1096,52 +1096,57 @@ msgid "Main Navigation"
msgstr "Haupmenü" msgstr "Haupmenü"
#: stock/templates/registered/base.html:106 #: stock/templates/registered/base.html:106
msgid " Dashboard" #: stock/templates/registered/dashboard.html:5
msgstr " Dashboard" #: stock/templates/registered/dashboard.html:9
msgid "Dashboard"
msgstr "Dashboard"
#: stock/templates/registered/base.html:113 #: stock/templates/registered/base.html:113
msgid " Groups" #: stock/templates/registered/dashboard.html:52
msgstr " Gruppen" msgid "Groups"
msgstr "Gruppen"
#: stock/templates/registered/base.html:120 #: stock/templates/registered/base.html:120
msgid " Help" msgid "Help"
msgstr " Hilfe" msgstr "Hilfe"
#: stock/templates/registered/base.html:126 #: stock/templates/registered/base.html:126
msgid "Aux Navigation" msgid "Aux Navigation"
msgstr "Zusatz Navigation" msgstr "Zusatz Navigation"
#: stock/templates/registered/base.html:131 #: stock/templates/registered/base.html:131
msgid " Services" msgid "Services"
msgstr " Dienste" msgstr "Dienste"
#: stock/templates/registered/base.html:140 #: stock/templates/registered/base.html:140
msgid " Applications" msgid "Applications"
msgstr " Bewerbungen" msgstr "Bewerbungen"
#: stock/templates/registered/base.html:148 #: stock/templates/registered/base.html:148
msgid " Corporation Stats" msgid "Corporation Stats"
msgstr " Korporationsstatistiken" msgstr "Korporationsstatistiken"
#: stock/templates/registered/base.html:156 #: stock/templates/registered/base.html:156
msgid " Group Management" #: stock/templates/registered/groupmanagementmenu.html:14
msgstr " Gruppenverwaltung" msgid "Group Management"
msgstr "Gruppenverwaltung"
#: stock/templates/registered/base.html:174 #: stock/templates/registered/base.html:174
msgid " Fleet Operations" msgid "Fleet Operations"
msgstr " Flottenoperationen" msgstr "Flottenoperationen"
#: stock/templates/registered/base.html:181 #: stock/templates/registered/base.html:181
msgid " Structure Timers" #: stock/templates/registered/timermanagement.html:13
msgstr " Strukturen Timer" msgid "Structure Timers"
msgstr "Strukturen Timer"
#: stock/templates/registered/base.html:188 #: stock/templates/registered/base.html:188
msgid " Fleet Activity Tracking" msgid "Fleet Activity Tracking"
msgstr " Flottenaktivitäts-Tracking" msgstr "Flottenaktivitäts-Tracking"
#: stock/templates/registered/base.html:194 #: stock/templates/registered/base.html:194
msgid " Ship Replacement" msgid "Ship Replacement"
msgstr " Schiffs erstattung" msgstr "Schiffs erstattung"
#: stock/templates/registered/base.html:200 #: stock/templates/registered/base.html:200
msgid "Util" msgid "Util"
@@ -1156,7 +1161,7 @@ msgid "Change Password"
msgstr "Passwort ändern" msgstr "Passwort ändern"
#: stock/templates/registered/base.html:211 #: stock/templates/registered/base.html:211
msgid " Fleet Broadcast Formatter" msgid "Fleet Broadcast Formatter"
msgstr "Flottenübertragungen Formatierer " msgstr "Flottenübertragungen Formatierer "
#: stock/templates/public/login.html:57 #: stock/templates/public/login.html:57
@@ -1293,11 +1298,6 @@ msgstr "Corporation: "
msgid "Corporation Ticker: " msgid "Corporation Ticker: "
msgstr "Corporation Ticker: " msgstr "Corporation Ticker: "
#: stock/templates/registered/dashboard.html:5
#: stock/templates/registered/dashboard.html:9
msgid "Dashboard"
msgstr "Dashboard"
#: stock/templates/registered/dashboard.html:38 #: stock/templates/registered/dashboard.html:38
msgid "Missing main character model." msgid "Missing main character model."
msgstr "Hauptcharakter model fehlt" msgstr "Hauptcharakter model fehlt"
@@ -1310,10 +1310,6 @@ msgstr "API Key hinzufügen"
msgid "Change Main" msgid "Change Main"
msgstr "Hauptcharakter ändern" msgstr "Hauptcharakter ändern"
#: stock/templates/registered/dashboard.html:52
msgid "Groups"
msgstr "Gruppen"
#: stock/templates/registered/dashboard.html:71 #: stock/templates/registered/dashboard.html:71
msgid "API Key requires EVE SSO verification" msgid "API Key requires EVE SSO verification"
msgstr "API Key benötigt EVE SSO bestätigung" msgstr "API Key benötigt EVE SSO bestätigung"
@@ -1601,10 +1597,6 @@ msgstr "Keine Gruppenbeitrittsanfragen."
msgid "No group leave requests." msgid "No group leave requests."
msgstr "Keine Gruppenaustrittsanfragen" msgstr "Keine Gruppenaustrittsanfragen"
#: stock/templates/registered/groupmanagementmenu.html:14
msgid "Group Management"
msgstr "Gruppenmanagement"
#: stock/templates/registered/groupmanagementmenu.html:19 #: stock/templates/registered/groupmanagementmenu.html:19
msgid "Group Requests" msgid "Group Requests"
msgstr "Gruppen anfragen" msgstr "Gruppen anfragen"
@@ -2171,10 +2163,6 @@ msgstr "Server beitreten"
msgid "Structure Timer Management" msgid "Structure Timer Management"
msgstr "Struktur-Timer Verwaltung" msgstr "Struktur-Timer Verwaltung"
#: stock/templates/registered/timermanagement.html:13
msgid "Structure Timers"
msgstr "Struktur-Timer"
#: stock/templates/registered/timermanagement.html:26 #: stock/templates/registered/timermanagement.html:26
msgid "Corp Timers" msgid "Corp Timers"
msgstr "Corp Timer" msgstr "Corp Timer"

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@@ -1,12 +1,12 @@
from allianceauth.services.hooks import MenuItemHook, UrlHook from allianceauth.services.hooks import MenuItemHook, UrlHook
from django.utils.translation import ugettext_lazy as _
from allianceauth import hooks from allianceauth import hooks
from . import urls from . import urls
class OpTimerboardMenu(MenuItemHook): class OpTimerboardMenu(MenuItemHook):
def __init__(self): def __init__(self):
MenuItemHook.__init__(self, 'Fleet Operations', MenuItemHook.__init__(self, _('Fleet Operations'),
'fa fa-exclamation fa-fw', 'fa fa-exclamation fa-fw',
'optimer:view', 'optimer:view',
navactive=['optimer:']) navactive=['optimer:'])

View File

@@ -19,7 +19,8 @@
<div class="col-lg-12 text-center row"> <div class="col-lg-12 text-center row">
<div class="label label-info text-left"> <div class="label label-info text-left">
<b>{% trans "Current Eve Time:" %} </b> <b>{% trans "Current Eve Time:" %} </b>
</div><div class="label label-info text-left" id="current-time"></div> </div>
<strong class="label label-info text-left" id="current-time"></strong>
<br /> <br />
</div> </div>
@@ -111,7 +112,7 @@
} }
function updateClock() { function updateClock() {
document.getElementById("current-time").innerHTML = "<b>" + moment.utc().format('LLLL') + "</b>"; document.getElementById("current-time").innerHTML = getCurrentEveTimeString();
} }
</script> </script>
{% endblock content %} {% endblock content %}

View File

@@ -82,6 +82,7 @@ ugettext = lambda s: s
LANGUAGES = ( LANGUAGES = (
('en', ugettext('English')), ('en', ugettext('English')),
('de', ugettext('German')), ('de', ugettext('German')),
('es', ugettext('Spanish')),
) )
TEMPLATES = [ TEMPLATES = [

View File

@@ -219,22 +219,18 @@ class DiscordOAuthManager:
@staticmethod @staticmethod
@api_backoff @api_backoff
def update_nickname(user_id, nickname): def update_nickname(user_id, nickname):
try: nickname = DiscordOAuthManager._sanitize_name(nickname)
nickname = DiscordOAuthManager._sanitize_name(nickname) custom_headers = {'content-type': 'application/json', 'authorization': 'Bot ' + settings.DISCORD_BOT_TOKEN}
custom_headers = {'content-type': 'application/json', 'authorization': 'Bot ' + settings.DISCORD_BOT_TOKEN} data = {'nick': nickname}
data = {'nick': nickname} path = DISCORD_URL + "/guilds/" + str(settings.DISCORD_GUILD_ID) + "/members/" + str(user_id)
path = DISCORD_URL + "/guilds/" + str(settings.DISCORD_GUILD_ID) + "/members/" + str(user_id) r = requests.patch(path, headers=custom_headers, json=data)
r = requests.patch(path, headers=custom_headers, json=data) logger.debug("Got status code %s after setting nickname for Discord user ID %s (%s)" % (
logger.debug("Got status code %s after setting nickname for Discord user ID %s (%s)" % ( r.status_code, user_id, nickname))
r.status_code, user_id, nickname)) if r.status_code == 404:
if r.status_code == 404: logger.warn("Discord user ID %s could not be found in server." % user_id)
logger.warn("Discord user ID %s could not be found in server." % user_id)
return True
r.raise_for_status()
return True return True
except: r.raise_for_status()
logger.exception("Failed to set nickname for Discord user ID %s (%s)" % (user_id, nickname)) return True
return False
@staticmethod @staticmethod
def delete_user(user_id): def delete_user(user_id):

View File

@@ -57,5 +57,5 @@ class Migration(migrations.Migration):
name='discorduser', name='discorduser',
options={'permissions': (('access_discord', 'Can access the Discord service'),)}, options={'permissions': (('access_discord', 'Can access the Discord service'),)},
), ),
migrations.RunPython(migrate_service_enabled), migrations.RunPython(migrate_service_enabled, migrations.RunPython.noop),
] ]

View File

@@ -58,5 +58,5 @@ class Migration(migrations.Migration):
name='discourseuser', name='discourseuser',
options={'permissions': (('access_discourse', 'Can access the Discourse service'),)}, options={'permissions': (('access_discourse', 'Can access the Discourse service'),)},
), ),
migrations.RunPython(migrate_service_enabled), migrations.RunPython(migrate_service_enabled, migrations.RunPython.noop),
] ]

View File

@@ -57,5 +57,5 @@ class Migration(migrations.Migration):
name='ips4user', name='ips4user',
options={'permissions': (('access_ips4', 'Can access the IPS4 service'),)}, options={'permissions': (('access_ips4', 'Can access the IPS4 service'),)},
), ),
migrations.RunPython(migrate_service_enabled), migrations.RunPython(migrate_service_enabled, migrations.RunPython.noop),
] ]

View File

@@ -57,5 +57,5 @@ class Migration(migrations.Migration):
name='marketuser', name='marketuser',
options={'permissions': (('access_market', 'Can access the Evernus Market service'),)}, options={'permissions': (('access_market', 'Can access the Evernus Market service'),)},
), ),
migrations.RunPython(migrate_service_enabled), migrations.RunPython(migrate_service_enabled, migrations.RunPython.noop),
] ]

View File

@@ -57,5 +57,5 @@ class Migration(migrations.Migration):
name='mumbleuser', name='mumbleuser',
options={'permissions': (('access_mumble', 'Can access the Mumble service'),)}, options={'permissions': (('access_mumble', 'Can access the Mumble service'),)},
), ),
migrations.RunPython(migrate_service_enabled), migrations.RunPython(migrate_service_enabled, migrations.RunPython.noop),
] ]

View File

@@ -57,5 +57,5 @@ class Migration(migrations.Migration):
name='openfireuser', name='openfireuser',
options={'permissions': (('access_openfire', 'Can access the Openfire service'),)}, options={'permissions': (('access_openfire', 'Can access the Openfire service'),)},
), ),
migrations.RunPython(migrate_service_enabled), migrations.RunPython(migrate_service_enabled, migrations.RunPython.noop),
] ]

View File

@@ -57,5 +57,5 @@ class Migration(migrations.Migration):
name='phpbb3user', name='phpbb3user',
options={'permissions': (('access_phpbb3', 'Can access the phpBB3 service'),)}, options={'permissions': (('access_phpbb3', 'Can access the phpBB3 service'),)},
), ),
migrations.RunPython(migrate_service_enabled), migrations.RunPython(migrate_service_enabled, migrations.RunPython.noop),
] ]

View File

@@ -57,5 +57,5 @@ class Migration(migrations.Migration):
name='smfuser', name='smfuser',
options={'permissions': (('access_smf', 'Can access the SMF service'),)}, options={'permissions': (('access_smf', 'Can access the SMF service'),)},
), ),
migrations.RunPython(migrate_service_enabled), migrations.RunPython(migrate_service_enabled, migrations.RunPython.noop),
] ]

View File

@@ -179,18 +179,19 @@ class Teamspeak3Manager:
except: except:
logger.exception("An unhandled exception has occured while syncing TS groups.") logger.exception("An unhandled exception has occured while syncing TS groups.")
def add_user(self, username): def add_user(self, user, fmt_name):
username_clean = self.__santatize_username(username[:30]) username_clean = self.__santatize_username(fmt_name[:30])
logger.debug("Adding user to TS3 server with cleaned username %s" % username_clean) logger.debug("Adding user to TS3 server with cleaned username %s" % username_clean)
server_groups = self._group_list() server_groups = self._group_list()
if 'Member' not in server_groups: state = user.profile.state.name
self._create_group('Member') if state not in server_groups:
self._create_group(state)
alliance_group_id = self._group_id_by_name('Member') state_group_id = self._group_id_by_name(state)
try: try:
ret = self.server.send_command('tokenadd', {'tokentype': 0, 'tokenid1': alliance_group_id, 'tokenid2': 0, ret = self.server.send_command('tokenadd', {'tokentype': 0, 'tokenid1': state_group_id, 'tokenid2': 0,
'tokendescription': username_clean, 'tokendescription': username_clean,
'tokencustomset': "ident=sso_uid value=%s" % username_clean}) 'tokencustomset': "ident=sso_uid value=%s" % username_clean})
except TeamspeakError as e: except TeamspeakError as e:

View File

@@ -57,5 +57,5 @@ class Migration(migrations.Migration):
name='teamspeak3user', name='teamspeak3user',
options={'permissions': (('access_teamspeak3', 'Can access the Teamspeak3 service'),)}, options={'permissions': (('access_teamspeak3', 'Can access the Teamspeak3 service'),)},
), ),
migrations.RunPython(migrate_service_enabled), migrations.RunPython(migrate_service_enabled, migrations.RunPython.noop),
] ]

View File

@@ -22,7 +22,7 @@ def activate_teamspeak3(request):
character = request.user.profile.main_character character = request.user.profile.main_character
with Teamspeak3Manager() as ts3man: with Teamspeak3Manager() as ts3man:
logger.debug("Adding TS3 user for user %s with main character %s" % (request.user, character)) logger.debug("Adding TS3 user for user %s with main character %s" % (request.user, character))
result = ts3man.add_user(Teamspeak3Tasks.get_username(request.user)) result = ts3man.add_user(request.user, Teamspeak3Tasks.get_username(request.user))
# if its empty we failed # if its empty we failed
if result[0] is not "": if result[0] is not "":

View File

@@ -57,5 +57,5 @@ class Migration(migrations.Migration):
name='xenforouser', name='xenforouser',
options={'permissions': (('access_xenforo', 'Can access the XenForo service'),)}, options={'permissions': (('access_xenforo', 'Can access the XenForo service'),)},
), ),
migrations.RunPython(migrate_service_enabled), migrations.RunPython(migrate_service_enabled, migrations.RunPython.noop),
] ]

View File

@@ -1,12 +1,12 @@
from allianceauth.services.hooks import MenuItemHook, UrlHook from allianceauth.services.hooks import MenuItemHook, UrlHook
from django.utils.translation import ugettext_lazy as _
from allianceauth import hooks from allianceauth import hooks
from . import urls from . import urls
class SrpMenu(MenuItemHook): class SrpMenu(MenuItemHook):
def __init__(self): def __init__(self):
MenuItemHook.__init__(self, 'Ship Replacement', MenuItemHook.__init__(self, _('Ship Replacement'),
'fa fa-money fa-fw', 'fa fa-money fa-fw',
'srp:management', 'srp:management',
navactive=['srp:']) navactive=['srp:'])

View File

@@ -8,8 +8,16 @@ function getDurationString(duration) {
if (duration.years()) { if (duration.years()) {
out += duration.years() + 'y '; out += duration.years() + 'y ';
} }
if (duration.months()) {
out += duration.months() + 'm ';
}
if (duration.days()) { if (duration.days()) {
out += duration.days() + 'd '; out += duration.days() + 'd ';
} }
return out + duration.hours() + "h " + duration.minutes() + "m " + duration.seconds() + "s"; return out + duration.hours() + "h " + duration.minutes() + "m " + duration.seconds() + "s";
} }
function getCurrentEveTimeString() {
return moment().utc().format('dddd LL HH:mm:ss')
}

View File

@@ -1,11 +1,12 @@
{% extends "allianceauth/base.html" %} {% extends "allianceauth/base.html" %}
{% load i18n %}
{% block page_title %}Help{% endblock page_title %} {% block page_title %}{% trans "Help" %}{% endblock page_title %}
{% block content %} {% block content %}
<div class="col-lg-12"> <div class="col-lg-12">
<h1 class="page-header text-center">Help</h1> <h1 class="page-header text-center">{% trans "Help" %}</h1>
<div class="container-fluid"> <div class="container-fluid">
<div class="embed-responsive embed-responsive-16by9"> <div class="embed-responsive embed-responsive-16by9">

View File

@@ -7,12 +7,12 @@
<li> <li>
<a class="{% navactive request 'authentication:dashboard' %}" <a class="{% navactive request 'authentication:dashboard' %}"
href="{% url 'authentication:dashboard' %}"> href="{% url 'authentication:dashboard' %}">
<i class="fa fa-dashboard fa-fw"></i>{% trans " Dashboard" %} <i class="fa fa-dashboard fa-fw"></i> {% trans "Dashboard" %}
</a> </a>
</li> </li>
<li> <li>
<a class="{% navactive request 'groupmanagement:groups' %}" href="{% url 'groupmanagement:groups' %}"> <a class="{% navactive request 'groupmanagement:groups' %}" href="{% url 'groupmanagement:groups' %}">
<i class="fa fa-cogs fa-fw fa-sitemap"></i>{% trans " Groups" %} <i class="fa fa-cogs fa-fw fa-sitemap"></i> {% trans "Groups" %}
</a> </a>
</li> </li>
@@ -20,7 +20,7 @@
<li> <li>
<a class="{% navactive request 'groupmanagement:management groupmanagement:membership groupmanagement:membership_list' %}" <a class="{% navactive request 'groupmanagement:management groupmanagement:membership groupmanagement:membership_list' %}"
href="{% url 'groupmanagement:management' %}"> href="{% url 'groupmanagement:management' %}">
<i class="fa fa-lock fa-sitemap fa-fw"></i>{% trans " Group Management" %} <i class="fa fa-lock fa-sitemap fa-fw"></i> {% trans "Group Management" %}
</a> </a>
</li> </li>
{% endif %} {% endif %}
@@ -30,7 +30,7 @@
<li> <li>
<a class="{% navactive request 'authentication:help' %}" <a class="{% navactive request 'authentication:help' %}"
href="{% url 'authentication:help' %}"> href="{% url 'authentication:help' %}">
<i class="fa fa-question fa-fw"></i>{% trans " Help" %} <i class="fa fa-question fa-fw"></i> {% trans "Help" %}
</a> </a>
</li> </li>
</ul> </ul>

View File

@@ -1,4 +1,4 @@
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.17.1/moment.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.22.1/moment.min.js"></script>
{% if locale and LANGUAGE_CODE != 'en' %} {% if locale and LANGUAGE_CODE != 'en' %}
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.17.1/locale/{{ LANGUAGE_CODE }}.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.22.1/locale/{{ LANGUAGE_CODE }}.js"></script>
{% endif %} {% endif %}

View File

@@ -18,7 +18,8 @@
<div class="col-lg-12 text-center"> <div class="col-lg-12 text-center">
<div class="label label-info text-left"> <div class="label label-info text-left">
<b>{% trans "Current Eve Time:" %} </b> <b>{% trans "Current Eve Time:" %} </b>
</div><div class="label label-info text-left" id="current-time"></div> </div>
<strong class="label label-info text-left" id="current-time"></strong>
</div> </div>
{% if corp_timers %} {% if corp_timers %}
<h4><b>{% trans "Corp Timers" %}</b></h4> <h4><b>{% trans "Corp Timers" %}</b></h4>
@@ -555,7 +556,7 @@
} }
function updateClock() { function updateClock() {
document.getElementById("current-time").innerHTML = "<b>" + moment().format('LLLL') + "</b>"; document.getElementById("current-time").innerHTML = getCurrentEveTimeString();
} }
</script> </script>
{% endblock content %} {% endblock content %}

View File

@@ -39,7 +39,7 @@ Ubuntu:
CentOS: CentOS:
yum install mariadb-server mariadb-devel mariadb yum install mariadb-server mariadb-devel mariadb-shared mariadb
```eval_rst ```eval_rst
.. note:: .. note::

View File

@@ -34,6 +34,7 @@ Mumble ships with a configuration file that needs customization. By default it
REQUIRED: To enable the ICE authenticator, edit the following: REQUIRED: To enable the ICE authenticator, edit the following:
- `icesecretwrite=MY_CLEVER_PASSWORD`, obviously choosing a secure password - `icesecretwrite=MY_CLEVER_PASSWORD`, obviously choosing a secure password
- ensure the line containing `Ice="tcp -h 127.0.0.1 -p 6502"` is uncommented
By default mumble operates on SQLite which is fine, but slower than a dedicated MySQL server. To customize the database, edit the following: By default mumble operates on SQLite which is fine, but slower than a dedicated MySQL server. To customize the database, edit the following:
@@ -46,7 +47,7 @@ By default mumble operates on SQLite which is fine, but slower than a dedicated
To name your root channel, uncomment and set `registerName=` to whatever cool name you want To name your root channel, uncomment and set `registerName=` to whatever cool name you want
Save and close the file (control + O, control + X). Save and close the file.
To get Mumble superuser account credentials, run the following: To get Mumble superuser account credentials, run the following:
@@ -80,7 +81,21 @@ Test your configuration by starting it: `python authenticator.py`
## Running the Authenticator ## Running the Authenticator
The authenticator needs to be running 24/7 to validate users on Mumble. You should check the [supervisor docs](../auth/supervisor.md) on how to achieve this. The authenticator needs to be running 24/7 to validate users on Mumble. This can be achieved by adding a section to your auth project's supervisor config file like the following example:
```
[program:authenticator]
command=/path/to/venv/bin/python authenticator.py
directory=/path/to/authenticator/directory/
user=allianceserver
stdout_logfile=/path/to/authenticator/directory/authenticator.log
stderr_logfile=/path/to/authenticator/directory/authenticator.log
autostart=true
autorestart=true
startsecs=10
priority=998
```
Note that groups will only be created on Mumble automatically when a user joins who is in the group. Note that groups will only be created on Mumble automatically when a user joins who is in the group.