mirror of
https://gitlab.com/allianceauth/allianceauth.git
synced 2025-07-11 21:40:17 +02:00
Merge branch 'esi' of https://github.com/r4stl1n/allianceauth into multitenant
This commit is contained in:
commit
3cdbff6b36
@ -61,8 +61,9 @@ INSTALLED_APPS = [
|
||||
'corputils',
|
||||
'fleetactivitytracking',
|
||||
'notifications',
|
||||
'eve_sso',
|
||||
'esi',
|
||||
'geelweb.django.navhelper',
|
||||
'bootstrap_pagination',
|
||||
]
|
||||
|
||||
MIDDLEWARE = [
|
||||
@ -229,9 +230,9 @@ SITE_NAME = os.environ.get('AA_SITE_NAME', 'Alliance Auth')
|
||||
# Callback URL should be http://mydomain.com/sso/callback
|
||||
# Leave callback blank to hide SSO button on login page
|
||||
###################
|
||||
EVE_SSO_CLIENT_ID = os.environ.get('AA_EVE_SSO_CLIENT_ID', '')
|
||||
EVE_SSO_CLIENT_SECRET = os.environ.get('AA_EVE_SSO_CLIENT_SECRET', '')
|
||||
EVE_SSO_CALLBACK_URL = os.environ.get('AA_EVE_SSO_CALLBACK_URL', '')
|
||||
ESI_SSO_CLIENT_ID = os.environ.get('AA_EVE_SSO_CLIENT_ID', '')
|
||||
ESI_SSO_CLIENT_SECRET = os.environ.get('AA_EVE_SSO_CLIENT_SECRET', '')
|
||||
ESI_SSO_CALLBACK_URL = os.environ.get('AA_EVE_SSO_CALLBACK_URL', '')
|
||||
|
||||
#########################
|
||||
# Default Group Settings
|
||||
@ -346,6 +347,19 @@ REJECT_OLD_APIS = 'True' == os.environ.get('AA_REJECT_OLD_APIS', 'False')
|
||||
REJECT_OLD_APIS_MARGIN = os.environ.get('AA_REJECT_OLD_APIS_MARGIN', 50)
|
||||
API_SSO_VALIDATION = 'True' == os.environ.get('AA_API_SSO_VALIDATION', 'False')
|
||||
|
||||
#######################
|
||||
# EVE Provider Settings
|
||||
#######################
|
||||
# EVEONLINE_CHARACTER_PROVIDER - Name of default data source for getting eve character data
|
||||
# EVEONLINE_CORP_PROVIDER - Name of default data source for getting eve corporation data
|
||||
# EVEONLINE_ALLIANCE_PROVIDER - Name of default data source for getting eve alliance data
|
||||
#
|
||||
# Available soruces are 'esi' and 'xml'
|
||||
#######################
|
||||
EVEONLINE_CHARACTER_PROVIDER = os.environ.get('AA_EVEONLINE_CHARACTER_PROVIDER', 'esi')
|
||||
EVEONLINE_CORP_PROVIDER = os.environ.get('AA_EVEONLINE_CORP_PROVIDER', 'esi')
|
||||
EVEONLINE_ALLIANCE_PROVIDER = os.environ.get('AA_EVEONLINE_ALLIANCE_PROVIDER', 'esi')
|
||||
|
||||
#####################
|
||||
# Alliance Market
|
||||
#####################
|
||||
|
@ -10,13 +10,13 @@ import services.views
|
||||
import groupmanagement.views
|
||||
import optimer.views
|
||||
import timerboard.views
|
||||
import corputils.views
|
||||
import fleetactivitytracking.views
|
||||
import fleetup.views
|
||||
import srp.views
|
||||
import notifications.views
|
||||
import hrapplications.views
|
||||
import eve_sso.urls
|
||||
import corputils.urls
|
||||
import esi.urls
|
||||
|
||||
# Functional/Untranslated URL's
|
||||
urlpatterns = [
|
||||
@ -27,8 +27,11 @@ urlpatterns = [
|
||||
url(r'^admin/', include(admin.site.urls)),
|
||||
|
||||
# SSO
|
||||
url (r'^sso/', include(eve_sso.urls, namespace='eve_sso')),
|
||||
url (r'^sso/login$', authentication.views.sso_login, name='auth_sso_login'),
|
||||
url(r'^sso/', include(esi.urls, namespace='esi')),
|
||||
url(r'^sso/login$', authentication.views.sso_login, name='auth_sso_login'),
|
||||
|
||||
# Corputils
|
||||
url(r'^corpstats/', include(corputils.urls, namespace='corputils')),
|
||||
|
||||
# Index
|
||||
url(_(r'^$'), authentication.views.index_view, name='auth_index'),
|
||||
@ -144,14 +147,6 @@ urlpatterns = [
|
||||
# User viewed/translated URLS
|
||||
urlpatterns += i18n_patterns(
|
||||
|
||||
# corputils
|
||||
url(r'^corputils/$', corputils.views.corp_member_view, name='auth_corputils'),
|
||||
url(r'^corputils/(?P<corpid>[0-9]+)/$', corputils.views.corp_member_view, name='auth_corputils_corp_view'),
|
||||
url(r'^corputils/(?P<corpid>[0-9]+)/(?P<year>[0-9]+)/(?P<month>[0-9]+)/$', corputils.views.corp_member_view,
|
||||
name='auth_corputils_month'),
|
||||
url(r'^corputils/search/$', corputils.views.corputils_search, name="auth_corputils_search"),
|
||||
url(r'^corputils/search/(?P<corpid>[0-9]+)/$', corputils.views.corputils_search, name='auth_corputils_search_corp'),
|
||||
|
||||
# Fleetup
|
||||
url(r'^fleetup/$', fleetup.views.fleetup_view, name='auth_fleetup_view'),
|
||||
url(r'^fleetup/fittings/$', fleetup.views.fleetup_fittings, name='auth_fleetup_fittings'),
|
||||
@ -245,12 +240,6 @@ urlpatterns += i18n_patterns(
|
||||
# Teamspeak Urls
|
||||
url(r'verify_teamspeak3/$', services.views.verify_teamspeak3, name='auth_verify_teamspeak3'),
|
||||
|
||||
# corputils
|
||||
url(_(r'^corputils/$'), corputils.views.corp_member_view, name='auth_corputils'),
|
||||
url(_(r'^corputils/(?P<corpid>[0-9]+)/$'), corputils.views.corp_member_view, name='auth_corputils_corp_view'),
|
||||
url(_(r'^corputils/search/$'), corputils.views.corputils_search, name="auth_corputils_search"),
|
||||
url(_(r'^corputils/search/(?P<corpid>[0-9]+)/$'), corputils.views.corputils_search, name='auth_corputils_search_corp'),
|
||||
|
||||
# Timer URLS
|
||||
url(_(r'^timers/$'), timerboard.views.timer_view, name='auth_timer_view'),
|
||||
url(_(r'^add_timer/$'), timerboard.views.add_timer_view, name='auth_add_timer_view'),
|
||||
|
@ -21,5 +21,5 @@ def states(request):
|
||||
|
||||
def sso(request):
|
||||
return {
|
||||
'EVE_SSO_CALLBACK_URL': settings.EVE_SSO_CALLBACK_URL,
|
||||
'EVE_SSO_CALLBACK_URL': settings.ESI_SSO_CALLBACK_URL,
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ from authentication.models import AuthServicesInfo
|
||||
from authentication.forms import LoginForm, RegistrationForm
|
||||
from django.contrib.auth.models import User
|
||||
from django.contrib import messages
|
||||
from eve_sso.decorators import token_required
|
||||
from esi.decorators import token_required
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@ -102,13 +102,14 @@ def help_view(request):
|
||||
return render(request, 'registered/help.html')
|
||||
|
||||
@token_required(new=True)
|
||||
def sso_login(request, tokens=[]):
|
||||
token = tokens[0]
|
||||
def sso_login(request, token):
|
||||
try:
|
||||
char = EveCharacter.objects.get(character_id=token.character_id)
|
||||
if char.user:
|
||||
if char.user.is_active:
|
||||
login(request, char.user)
|
||||
token.user = char.user
|
||||
token.save()
|
||||
return redirect(dashboard_view)
|
||||
else:
|
||||
messages.error(request, 'Your account has been disabled.')
|
||||
|
@ -1 +1,5 @@
|
||||
from __future__ import unicode_literals
|
||||
from corputils.models import CorpStats
|
||||
from django.contrib import admin
|
||||
|
||||
admin.site.register(CorpStats)
|
||||
|
@ -1,8 +0,0 @@
|
||||
from __future__ import unicode_literals
|
||||
from django import forms
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
|
||||
class CorputilsSearchForm(forms.Form):
|
||||
search_string = forms.CharField(max_length=254, required=True, label="",
|
||||
widget=forms.TextInput(attrs={'placeholder': _('Search characters...')}))
|
42
corputils/managers.py
Normal file
42
corputils/managers.py
Normal file
@ -0,0 +1,42 @@
|
||||
from django.db import models
|
||||
from authentication.models import AuthServicesInfo
|
||||
from eveonline.models import EveCharacter
|
||||
|
||||
|
||||
class CorpStatsQuerySet(models.QuerySet):
|
||||
def visible_to(self, user):
|
||||
# superusers get all visible
|
||||
if user.is_superuser:
|
||||
return self
|
||||
|
||||
auth = AuthServicesInfo.objects.get_or_create(user=user)[0]
|
||||
try:
|
||||
char = EveCharacter.objects.get(character_id=auth.main_char_id)
|
||||
# build all accepted queries
|
||||
queries = []
|
||||
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 user.has_perm('corputils.view_blue_corpstats'):
|
||||
queries.append(models.Q(corp__is_blue=True))
|
||||
|
||||
# filter based on queries
|
||||
if queries:
|
||||
query = queries.pop()
|
||||
for q in queries:
|
||||
query |= q
|
||||
return self.filter(query)
|
||||
else:
|
||||
# not allowed to see any
|
||||
return self.none()
|
||||
except EveCharacter.DoesNotExist:
|
||||
return self.none()
|
||||
|
||||
|
||||
class CorpStatsManager(models.Manager):
|
||||
def get_queryset(self):
|
||||
return CorpStatsQuerySet(self.model, using=self._db)
|
||||
|
||||
def visible_to(self, user):
|
||||
return self.get_queryset().visible_to(user)
|
35
corputils/migrations/0001_initial.py
Normal file
35
corputils/migrations/0001_initial.py
Normal file
@ -0,0 +1,35 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.10.1 on 2016-12-14 21:36
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
('esi', '0002_scopes_20161208'),
|
||||
('eveonline', '0004_eveapikeypair_sso_verified'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='CorpStats',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('last_update', models.DateTimeField(auto_now=True)),
|
||||
('_members', models.TextField(default='{}')),
|
||||
('corp', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to='eveonline.EveCorporationInfo')),
|
||||
('token', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='esi.Token')),
|
||||
],
|
||||
options={
|
||||
'default_permissions': ('add', 'change', 'remove', 'view_corp', 'view_alliance', 'view_blue'),
|
||||
'verbose_name': 'corp stats',
|
||||
'verbose_name_plural': 'corp stats',
|
||||
'permissions': (('corp_apis', 'Can view API keys of members of their corporation.'), ('alliance_apis', 'Can view API keys of members of their alliance.'), ('blue_apis', 'Can view API keys of members of blue corporations.')),
|
||||
},
|
||||
),
|
||||
]
|
125
corputils/migrations/0002_migrate_permissions.py
Normal file
125
corputils/migrations/0002_migrate_permissions.py
Normal file
@ -0,0 +1,125 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.10.1 on 2016-12-14 21:48
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
PERMISSIONS = {
|
||||
'user': [
|
||||
'corp_apis',
|
||||
'alliance_apis',
|
||||
],
|
||||
'corpstats': {
|
||||
'corp_apis': 'Can view API keys of members of their corporation.',
|
||||
'alliance_apis': 'Can view API keys of members of their alliance.',
|
||||
'blue_apis': 'Can view API keys of members of blue corporations.',
|
||||
'view_corp_corpstats': 'Can view_corp corpstats',
|
||||
'view_alliance_corpstats': 'Can view_alliance corpstats',
|
||||
'view_blue_corpstats': 'Can view_blue corpstats',
|
||||
}
|
||||
}
|
||||
|
||||
def user_permissions_dict(apps):
|
||||
Permission = apps.get_model('auth', 'Permission')
|
||||
ContentType = apps.get_model('contenttypes', 'ContentType')
|
||||
User = apps.get_model('auth', 'User')
|
||||
CorpStats = apps.get_model('corputils', 'CorpStats')
|
||||
|
||||
user_ct = ContentType.objects.get_for_model(User)
|
||||
corpstats_ct = ContentType.objects.get_for_model(CorpStats)
|
||||
|
||||
return {
|
||||
'user': {x: Permission.objects.get_or_create(name=x, codename=x, content_type=user_ct)[0] for x in PERMISSIONS['user']},
|
||||
'corpstats': {x: Permission.objects.get_or_create(codename=x, content_type=corpstats_ct)[0] for x, y in PERMISSIONS['corpstats'].items()},
|
||||
}
|
||||
|
||||
def users_with_permission(apps, perm):
|
||||
User = apps.get_model('auth', 'User')
|
||||
return User.objects.filter(user_permissions=perm.pk)
|
||||
|
||||
def groups_with_permission(apps, perm):
|
||||
Group = apps.get_model('auth', 'Group')
|
||||
return Group.objects.filter(permissions=perm.pk)
|
||||
|
||||
def forward(apps, schema_editor):
|
||||
perm_dict = user_permissions_dict(apps)
|
||||
|
||||
corp_users = users_with_permission(apps, perm_dict['user']['corp_apis'])
|
||||
for u in corp_users:
|
||||
u.user_permissions.add(perm_dict['corpstats']['corp_apis'].pk)
|
||||
u.user_permissions.add(perm_dict['corpstats']['view_corp_corpstats'].pk)
|
||||
|
||||
alliance_users = users_with_permission(apps, perm_dict['user']['alliance_apis'])
|
||||
for u in alliance_users:
|
||||
u.user_permissions.add(perm_dict['corpstats']['alliance_apis'].pk)
|
||||
u.user_permissions.add(perm_dict['corpstats']['view_alliance_corpstats'].pk)
|
||||
|
||||
corp_groups = groups_with_permission(apps, perm_dict['user']['corp_apis'])
|
||||
for g in corp_groups:
|
||||
g.permissions.add(perm_dict['corpstats']['corp_apis'].pk)
|
||||
g.permissions.add(perm_dict['corpstats']['view_corp_corpstats'].pk)
|
||||
|
||||
alliance_groups = groups_with_permission(apps, perm_dict['user']['alliance_apis'])
|
||||
for g in alliance_groups:
|
||||
g.permissions.add(perm_dict['corpstats']['alliance_apis'].pk)
|
||||
g.permissions.add(perm_dict['corpstats']['view_alliance_corpstats'].pk)
|
||||
|
||||
for name, perm in perm_dict['user'].items():
|
||||
perm.delete()
|
||||
|
||||
def reverse(apps, schema_editor):
|
||||
perm_dict = user_permissions_dict(apps)
|
||||
|
||||
corp_users = users_with_permission(apps, perm_dict['corpstats']['view_corp_corpstats'])
|
||||
corp_api_users = users_with_permission(apps, perm_dict['corpstats']['corp_apis'])
|
||||
corp_us = corp_users | corp_api_users
|
||||
for u in corp_us.distinct():
|
||||
u.user_permissions.add(perm_dict['user']['corp_apis'].pk)
|
||||
for u in corp_users:
|
||||
u.user_permissions.remove(perm_dict['corpstats']['view_corp_corpstats'].pk)
|
||||
for u in corp_api_users:
|
||||
u.user_permissions.remove(perm_dict['corpstats']['corp_apis'].pk)
|
||||
|
||||
|
||||
alliance_users = users_with_permission(apps, perm_dict['corpstats']['view_alliance_corpstats'])
|
||||
alliance_api_users = users_with_permission(apps, perm_dict['corpstats']['alliance_apis'])
|
||||
alliance_us = alliance_users | alliance_api_users
|
||||
for u in alliance_us.distinct():
|
||||
u.user_permissions.add(perm_dict['user']['alliance_apis'].pk)
|
||||
for u in alliance_users:
|
||||
u.user_permissions.remove(perm_dict['corpstats']['view_alliance_corpstats'].pk)
|
||||
for u in alliance_api_users:
|
||||
u.user_permissions.remove(perm_dict['corpstats']['alliance_apis'].pk)
|
||||
|
||||
corp_groups = groups_with_permission(apps, perm_dict['corpstats']['view_corp_corpstats'])
|
||||
corp_api_groups = groups_with_permission(apps, perm_dict['corpstats']['corp_apis'])
|
||||
corp_gs = corp_groups | corp_api_groups
|
||||
for g in corp_groups.distinct():
|
||||
g.permissions.add(perm_dict['user']['corp_apis'].pk)
|
||||
for g in corp_groups:
|
||||
g.permissions.remove(perm_dict['corpstats']['view_corp_corpstats'].pk)
|
||||
for g in corp_api_groups:
|
||||
g.permissions.remove(perm_dict['corpstats']['corp_apis'].pk)
|
||||
|
||||
alliance_groups = groups_with_permission(apps, perm_dict['corpstats']['view_alliance_corpstats'])
|
||||
alliance_api_groups = groups_with_permission(apps, perm_dict['corpstats']['alliance_apis'])
|
||||
alliance_gs = alliance_groups | alliance_api_groups
|
||||
for g in alliance_gs.distinct():
|
||||
g.permissions.add(perm_dict['user']['alliance_apis'].pk)
|
||||
for g in alliance_groups:
|
||||
g.permissions.remove(perm_dict['corpstats']['view_alliance_corpstats'].pk)
|
||||
for g in alliance_api_groups:
|
||||
g.permissions.remove(perm_dict['corpstats']['alliance_apis'].pk)
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('corputils', '0001_initial'),
|
||||
('authentication', '0005_delete_perms'),
|
||||
('auth', '0008_alter_user_username_max_length'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RunPython(forward, reverse),
|
||||
]
|
0
corputils/migrations/__init__.py
Normal file
0
corputils/migrations/__init__.py
Normal file
@ -1 +1,174 @@
|
||||
from __future__ import unicode_literals
|
||||
from django.utils.encoding import python_2_unicode_compatible
|
||||
from django.db import models
|
||||
from eveonline.models import EveCorporationInfo, EveCharacter, EveApiKeyPair
|
||||
from esi.models import Token
|
||||
from esi.errors import TokenError
|
||||
from notifications import notify
|
||||
from authentication.models import AuthServicesInfo
|
||||
from bravado.exception import HTTPForbidden
|
||||
from corputils.managers import CorpStatsManager
|
||||
from operator import attrgetter
|
||||
import json
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class CorpStats(models.Model):
|
||||
token = models.ForeignKey(Token, on_delete=models.CASCADE)
|
||||
corp = models.OneToOneField(EveCorporationInfo)
|
||||
last_update = models.DateTimeField(auto_now=True)
|
||||
_members = models.TextField(default='{}')
|
||||
|
||||
class Meta:
|
||||
permissions = (
|
||||
('corp_apis', 'Can view API keys of members of their corporation.'),
|
||||
('alliance_apis', 'Can view API keys of members of their alliance.'),
|
||||
('blue_apis', 'Can view API keys of members of blue corporations.'),
|
||||
)
|
||||
default_permissions = (
|
||||
'add',
|
||||
'change',
|
||||
'remove',
|
||||
'view_corp',
|
||||
'view_alliance',
|
||||
'view_blue',
|
||||
)
|
||||
verbose_name = "corp stats"
|
||||
verbose_name_plural = "corp stats"
|
||||
|
||||
objects = CorpStatsManager()
|
||||
|
||||
def __str__(self):
|
||||
return "%s for %s" % (self.__class__.__name__, self.corp)
|
||||
|
||||
def update(self):
|
||||
try:
|
||||
c = self.token.get_esi_client()
|
||||
assert c.Character.get_characters_character_id(character_id=self.token.character_id).result()['corporation_id'] == int(self.corp.corporation_id)
|
||||
members = c.Corporation.get_corporations_corporation_id_members(corporation_id=self.corp.corporation_id).result()
|
||||
member_ids = [m['character_id'] for m in members]
|
||||
member_names = c.Character.get_characters_names(character_ids=member_ids).result()
|
||||
member_list = {m['character_id']:m['character_name'] for m in member_names}
|
||||
self.members = member_list
|
||||
self.save()
|
||||
except TokenError as e:
|
||||
logger.warning("%s failed to update: %s" % (self, e))
|
||||
if self.token.user:
|
||||
notify(self.token.user, "%s failed to update with your ESI token." % self, message="Your token has expired or is no longer valid. Please add a new one to create a new CorpStats.", level="error")
|
||||
self.delete()
|
||||
except HTTPForbidden as e:
|
||||
logger.warning("%s failed to update: %s" % (self, e))
|
||||
if self.token.user:
|
||||
notify(self.token.user, "%s failed to update with your ESI token." % self, message="%s: %s" % (e.status_code, e.message), level="error")
|
||||
self.delete()
|
||||
except AssertionError:
|
||||
logger.warning("%s token character no longer in corp." % self)
|
||||
if self.token.user:
|
||||
notify(self.token.user, "%s cannot update with your ESI token." % self, message="%s cannot update with your ESI token as you have left corp." % self, level="error")
|
||||
self.delete()
|
||||
|
||||
@property
|
||||
def members(self):
|
||||
return json.loads(self._members)
|
||||
|
||||
@members.setter
|
||||
def members(self, dict):
|
||||
self._members = json.dumps(dict)
|
||||
|
||||
@property
|
||||
def member_ids(self):
|
||||
return [id for id, name in self.members.items()]
|
||||
|
||||
@property
|
||||
def member_names(self):
|
||||
return [name for id, name in self.members.items()]
|
||||
|
||||
def show_apis(self, user):
|
||||
auth = AuthServicesInfo.objects.get_or_create(user=user)[0]
|
||||
if auth.main_char_id:
|
||||
try:
|
||||
char = EveCharacter.objects.get(character_id=auth.main_char_id)
|
||||
if char.corporation_id == self.corp.corporation_id and user.has_perm('corputils.corp_apis'):
|
||||
return True
|
||||
if self.corp.alliance and char.alliance_id == self.corp.alliance.alliance_id and user.has_perm('corputils.alliance_apis'):
|
||||
return True
|
||||
if user.has_perm('corputils.blue_apis') and self.corp.is_blue:
|
||||
return True
|
||||
except EveCharacter.DoesNotExist:
|
||||
pass
|
||||
return user.is_superuser
|
||||
|
||||
def entered_apis(self):
|
||||
return EveCharacter.objects.filter(character_id__in=self.member_ids).exclude(api_id__isnull=True).count()
|
||||
|
||||
def member_count(self):
|
||||
return len(self.members)
|
||||
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class MemberObject(object):
|
||||
def __init__(self, character_id, character_name, show_apis=False):
|
||||
self.character_id = character_id
|
||||
self.character_name = character_name
|
||||
try:
|
||||
char = EveCharacter.objects.get(character_id=character_id)
|
||||
auth = AuthServicesInfo.objects.get(user=char.user)
|
||||
try:
|
||||
self.main = EveCharacter.objects.get(character_id=auth.main_char_id)
|
||||
except EveCharacter.DoesNotExist:
|
||||
self.main = None
|
||||
api = EveApiKeyPair.objects.get(api_id=char.api_id)
|
||||
self.registered = True
|
||||
if show_apis:
|
||||
self.api = api
|
||||
else:
|
||||
self.api = None
|
||||
except (EveCharacter.DoesNotExist, AuthServicesInfo.DoesNotExist):
|
||||
self.main = None
|
||||
self.api = None
|
||||
self.registered = False
|
||||
except EveApiKeyPair.DoesNotExist:
|
||||
self.api = None
|
||||
self.registered = False
|
||||
|
||||
def __str__(self):
|
||||
return self.character_name
|
||||
|
||||
def portrait_url(self, size=32):
|
||||
return "https://image.eveonline.com/Character/%s_%s.jpg" % (self.character_id, size)
|
||||
|
||||
def get_member_objects(self, user):
|
||||
show_apis = self.show_apis(user)
|
||||
return sorted([CorpStats.MemberObject(id, name, show_apis=show_apis) for id, name in self.members.items()], key=attrgetter('character_name'))
|
||||
|
||||
def can_update(self, user):
|
||||
return user.is_superuser or user == self.token.user
|
||||
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class ViewModel(object):
|
||||
def __init__(self, corpstats, user):
|
||||
self.corp = corpstats.corp
|
||||
self.members = corpstats.get_member_objects(user)
|
||||
self.can_update = corpstats.can_update(user)
|
||||
self.total_members = len(self.members)
|
||||
self.registered_members = corpstats.entered_apis()
|
||||
self.show_apis = corpstats.show_apis(user)
|
||||
self.last_updated = corpstats.last_update
|
||||
|
||||
def __str__(self):
|
||||
return str(self.corp)
|
||||
|
||||
def corp_logo(self, size=128):
|
||||
return "https://image.eveonline.com/Corporation/%s_%s.png" % (self.corp.corporation_id, size)
|
||||
|
||||
def alliance_logo(self, size=128):
|
||||
if self.corp.alliance:
|
||||
return "https://image.eveonline.com/Alliance/%s_%s.png" % (self.corp.alliance.alliance_id, size)
|
||||
else:
|
||||
return "https://image.eveonline.com/Alliance/1_%s.png" % size
|
||||
|
||||
def get_view_model(self, user):
|
||||
return CorpStats.ViewModel(self, user)
|
||||
|
39
corputils/templates/corputils/base.html
Normal file
39
corputils/templates/corputils/base.html
Normal file
@ -0,0 +1,39 @@
|
||||
{% extends 'public/base.html' %}
|
||||
{% load i18n %}
|
||||
{% block title %}{% trans "Corporation Member Data" %}{% endblock %}
|
||||
{% block page_title %}{% trans "Corporation Member Data" %}{% endblock %}
|
||||
{% block content %}
|
||||
<div class="col-lg-12">
|
||||
<h1 class="page-header text-center">{% trans "Corporation Member Data" %}</h1>
|
||||
<div class="col-lg-10 col-lg-offset-1 container">
|
||||
<nav class="navbar navbar-default">
|
||||
<div class="container-fluid">
|
||||
<ul class="nav navbar-nav">
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Corporations<span class="caret"></span></a>
|
||||
<ul class="dropdown-menu">
|
||||
{% for corpstat in available %}
|
||||
<li>
|
||||
<a href="{% url 'corputils:view_corp' corpstat.corp.corporation_id %}">{{ corpstat.corp.corporation_name }}</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</li>
|
||||
{% if perms.corputils.add_corpstats %}
|
||||
<li>
|
||||
<a href="{% url 'corputils:add' %}">Add</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
<form class="navbar-form navbar-right" role="search" action="{% url 'corputils:search' %}" method="GET">
|
||||
<div class="form-group">
|
||||
<input type="text" class="form-control" name="search_string" placeholder="{% if search_string %}{{ search_string }}{% else %}Search characters...{% endif %}">
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</nav>
|
||||
{% block member_data %}{% endblock %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
92
corputils/templates/corputils/corpstats.html
Normal file
92
corputils/templates/corputils/corpstats.html
Normal file
@ -0,0 +1,92 @@
|
||||
{% extends 'corputils/base.html' %}
|
||||
{% load i18n %}
|
||||
{% load humanize %}
|
||||
{% load bootstrap_pagination %}
|
||||
{% block member_data %}
|
||||
{% if corpstats %}
|
||||
<div class="row">
|
||||
<div class="col-lg-12 text-center">
|
||||
<table class="table">
|
||||
<tr>
|
||||
<td class="text-center col-lg-6 {% if corpstats.corp.alliance %}{% else %}col-lg-offset-3{% endif %}"><img class="ra-avatar" src="{{ corpstats.corp_logo }}"></td>
|
||||
{% if corpstats.corp.alliance %}
|
||||
<td class="text-center col-lg-6"><img class="ra-avatar" src="{{ corpstats.alliance_logo }}"></td>
|
||||
{% endif %}
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="text-center"><h4>{{ corpstats.corp.corporation_name }}</h4></td>
|
||||
{% if corpstats.corp.alliance %}
|
||||
<td class="text-center"><h4>{{ corpstats.corp.alliance.alliance_name }}</h4></td>
|
||||
{% endif %}
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<b>{% trans "API Index:" %}</b>
|
||||
<div class="progress">
|
||||
<div class="progress-bar" role="progressbar" aria-valuenow="{{ corpstats.registered_members }}" aria-valuemin="0" aria-valuemax="{{ corpstats.total_members }}" style="width: {% widthratio corpstats.registered_members corpstats.total_members 100 %}%;">
|
||||
{{ corpstats.registered_members }}/{{ corpstats.total_members }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading clearfix">
|
||||
<div class="panel-title pull-left">
|
||||
<h4>Members</h4>
|
||||
</div>
|
||||
<div class="panel-title pull-right">
|
||||
Last update: {{ corpstats.last_updated|naturaltime }}
|
||||
{% if corpstats.can_update %}
|
||||
<a class="btn btn-success" type="button" href="{% url 'corputils:update' corpstats.corp.corporation_id %}" title="Update Now">
|
||||
<span class="glyphicon glyphicon-refresh"></span>
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div class="text-center">
|
||||
{% bootstrap_paginate members range=10 %}
|
||||
</div>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover">
|
||||
<tr>
|
||||
<th></th>
|
||||
<th class="text-center">Character</th>
|
||||
{% if corpstats.show_apis %}
|
||||
<th class="text-center">API</th>
|
||||
{% endif %}
|
||||
<th class="text-center">zKillboard</th>
|
||||
<th class="text-center">Main Character</th>
|
||||
<th class="text-center">Main Corporation</th>
|
||||
<th class="text-center">Main Alliance</th>
|
||||
</tr>
|
||||
{% for member in members %}
|
||||
<tr {% if not member.registered %}class="danger"{% endif %}>
|
||||
<td><img src="{{ member.portrait_url }}" class="img-circle"></td>
|
||||
<td class="text-center">{{ member.character_name }}</td>
|
||||
{% if corpstats.show_apis %}
|
||||
{% if member.api %}
|
||||
<td class="text-center"><a href="{{ JACK_KNIFE_URL }}?usid={{ member.api.api_id }}&apik={{ member.api.api_key }}" target="_blank" class="label label-primary">{{ member.api.api_id }}</td>
|
||||
{% else %}
|
||||
<td></td>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
<td class="text-center"><a href="https://zkillboard.com/character/{{ member.character_id }}/" class="label label-danger" target="_blank">{% trans "Killboard" %}</a></td>
|
||||
<td class="text-center">{{ member.main.character_name }}</td>
|
||||
<td class="text-center">{{ member.main.corporation_name }}</td>
|
||||
<td class="text-center">{{ member.main.alliance_name }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
43
corputils/templates/corputils/search.html
Normal file
43
corputils/templates/corputils/search.html
Normal file
@ -0,0 +1,43 @@
|
||||
{% extends "corputils/base.html" %}
|
||||
{% load i18n %}
|
||||
{% load bootstrap_pagination %}
|
||||
{% block member_data %}
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading clearfix">
|
||||
<div class="panel-title pull-left">Search Results</div>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div class="text-center">
|
||||
{% bootstrap_paginate results range=10 %}
|
||||
</div>
|
||||
<table class="table table-hover">
|
||||
<tr>
|
||||
<th class="text-center"></th>
|
||||
<th class="text-center">Character</th>
|
||||
<th class="text-center">Corporation</th>
|
||||
<th class="text-center">API</th>
|
||||
<th class="text-center">zKillboard</th>
|
||||
<th class="text-center">Main Character</th>
|
||||
<th class="text-center">Main Corporation</th>
|
||||
<th class="text-center">Main Alliance</th>
|
||||
</tr>
|
||||
{% for result in results %}
|
||||
<tr {% if not result.1.registered %}class="danger"{% endif %}>
|
||||
<td class="text-center"><img src="{{ result.1.portrait_url }}" class="img-circle"></td>
|
||||
<td class="text-center">{{ result.1.character_name }}</td>
|
||||
<td class="text-center">{{ result.0.corp.corporation_name }}</td>
|
||||
{% if result.1.api %}
|
||||
<td class="text-center"><a href="{{ JACK_KNIFE_URL }}?usid={{ result.1.api.api_id }}&apik={{ result.1.api.api_key }}" target="_blank" class="label label-primary">{{ result.1.api.api_id }}</td>
|
||||
{% else %}
|
||||
<td></td>
|
||||
{% endif %}
|
||||
<td class="text-center"><a href="https://zkillboard.com/character/{{ result.1.character_id }}/" class="label label-danger" target="_blank">{% trans "Killboard" %}</a></td>
|
||||
<td class="text-center">{{ result.1.main.character_name }}</td>
|
||||
<td class="text-center">{{ result.1.main.corporation_name }}</td>
|
||||
<td class="text-center">{{ result.1.main.alliance_name }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
11
corputils/urls.py
Normal file
11
corputils/urls.py
Normal file
@ -0,0 +1,11 @@
|
||||
from django.conf.urls import url
|
||||
import corputils.views
|
||||
|
||||
app_name='corputils'
|
||||
urlpatterns = [
|
||||
url(r'^$', corputils.views.corpstats_view, name='view'),
|
||||
url(r'^add/$', corputils.views.corpstats_add, name='add'),
|
||||
url(r'^(?P<corp_id>(\d)*)/$', corputils.views.corpstats_view, name='view_corp'),
|
||||
url(r'^(?P<corp_id>(\d)+)/update/$', corputils.views.corpstats_update, name='update'),
|
||||
url(r'^search/$', corputils.views.corpstats_search, name='search'),
|
||||
]
|
@ -1,325 +1,124 @@
|
||||
from __future__ import unicode_literals
|
||||
from django.conf import settings
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.shortcuts import render, redirect
|
||||
from django.contrib.auth.decorators import login_required, permission_required, user_passes_test
|
||||
from django.shortcuts import render, redirect, get_object_or_404
|
||||
from django.contrib import messages
|
||||
from django.core.exceptions import PermissionDenied
|
||||
from django.db import IntegrityError
|
||||
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
|
||||
from django.conf import settings
|
||||
from eveonline.models import EveCharacter, EveCorporationInfo
|
||||
from corputils.models import CorpStats
|
||||
from esi.decorators import token_required
|
||||
|
||||
from collections import namedtuple
|
||||
MEMBERS_PER_PAGE = int(getattr(settings, 'CORPSTATS_MEMBERS_PER_PAGE', 20))
|
||||
|
||||
from authentication.models import AuthServicesInfo
|
||||
from services.managers.eve_api_manager import EveApiManager
|
||||
from services.managers.evewho_manager import EveWhoManager
|
||||
from eveonline.models import EveCorporationInfo
|
||||
from eveonline.models import EveAllianceInfo
|
||||
from eveonline.models import EveCharacter
|
||||
from eveonline.models import EveApiKeyPair
|
||||
from fleetactivitytracking.models import Fat
|
||||
from corputils.forms import CorputilsSearchForm
|
||||
from evelink.api import APIError
|
||||
|
||||
import logging
|
||||
import datetime
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Player(object):
|
||||
def __init__(self, main, user, maincorp, maincorpid, altlist, apilist, n_fats):
|
||||
self.main = main
|
||||
self.user = user
|
||||
self.maincorp = maincorp
|
||||
self.maincorpid = maincorpid
|
||||
self.altlist = altlist
|
||||
self.apilist = apilist
|
||||
self.n_fats = n_fats
|
||||
|
||||
|
||||
def first_day_of_next_month(year, month):
|
||||
if month == 12:
|
||||
return datetime.datetime(year + 1, 1, 1)
|
||||
else:
|
||||
return datetime.datetime(year, month + 1, 1)
|
||||
|
||||
|
||||
def first_day_of_previous_month(year, month):
|
||||
if month == 1:
|
||||
return datetime.datetime(year - 1, 12, 1)
|
||||
else:
|
||||
return datetime.datetime(year, month - 1, 1)
|
||||
def get_page(model_list, page_num):
|
||||
p = Paginator(model_list, MEMBERS_PER_PAGE)
|
||||
try:
|
||||
members = p.page(page_num)
|
||||
except PageNotAnInteger:
|
||||
members = p.page(1)
|
||||
except EmptyPage:
|
||||
members = p.page(p.num_pages)
|
||||
return members
|
||||
|
||||
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_blue_corpstats')
|
||||
|
||||
@login_required
|
||||
def corp_member_view(request, corpid=None, year=datetime.date.today().year, month=datetime.date.today().month):
|
||||
year = int(year)
|
||||
month = int(month)
|
||||
start_of_month = datetime.datetime(year, month, 1)
|
||||
start_of_next_month = first_day_of_next_month(year, month)
|
||||
start_of_previous_month = first_day_of_previous_month(year, month)
|
||||
logger.debug("corp_member_view called by user %s" % request.user)
|
||||
|
||||
@user_passes_test(access_corpstats_test)
|
||||
@permission_required('corputils.add_corpstats')
|
||||
@token_required(scopes='esi-corporations.read_corporation_membership.v1')
|
||||
def corpstats_add(request, token):
|
||||
try:
|
||||
user_main = EveCharacter.objects.get(
|
||||
character_id=AuthServicesInfo.objects.get_or_create(user=request.user)[0].main_char_id)
|
||||
user_corp_id = user_main.corporation_id
|
||||
except (ValueError, EveCharacter.DoesNotExist):
|
||||
user_corp_id = settings.CORP_ID
|
||||
|
||||
if not settings.IS_CORP:
|
||||
alliance = EveAllianceInfo.objects.get(alliance_id=settings.ALLIANCE_ID)
|
||||
alliancecorps = EveCorporationInfo.objects.filter(alliance=alliance)
|
||||
membercorplist = [(int(membercorp.corporation_id), str(membercorp.corporation_name)) for membercorp in
|
||||
alliancecorps]
|
||||
membercorplist.sort(key=lambda tup: tup[1])
|
||||
membercorp_id_list = [int(membercorp.corporation_id) for membercorp in alliancecorps]
|
||||
|
||||
bluecorps = EveCorporationInfo.objects.filter(is_blue=True)
|
||||
bluecorplist = [(int(bluecorp.corporation_id), str(bluecorp.corporation_name)) for bluecorp in bluecorps]
|
||||
bluecorplist.sort(key=lambda tup: tup[1])
|
||||
bluecorp_id_list = [int(bluecorp.corporation_id) for bluecorp in bluecorps]
|
||||
|
||||
if not (user_corp_id in membercorp_id_list or user_corp_id not in bluecorp_id_list):
|
||||
user_corp_id = None
|
||||
|
||||
if not corpid:
|
||||
if settings.IS_CORP:
|
||||
corpid = settings.CORP_ID
|
||||
elif user_corp_id:
|
||||
corpid = user_corp_id
|
||||
if EveCharacter.objects.filter(character_id=token.character_id).exists():
|
||||
corp_id = EveCharacter.objects.get(character_id=token.character_id).corporation_id
|
||||
else:
|
||||
corpid = membercorplist[0][0]
|
||||
|
||||
corp = EveCorporationInfo.objects.get(corporation_id=corpid)
|
||||
if request.user.has_perm('auth.alliance_apis') or (request.user.has_perm('auth.corp_apis') and user_corp_id == corpid):
|
||||
logger.debug("Retreiving and sending API-information")
|
||||
|
||||
if settings.IS_CORP:
|
||||
try:
|
||||
member_list = EveApiManager.get_corp_membertracking(settings.CORP_API_ID, settings.CORP_API_VCODE)
|
||||
except APIError:
|
||||
logger.debug("Corp API does not have membertracking scope, using EveWho data instead.")
|
||||
member_list = EveWhoManager.get_corporation_members(corpid)
|
||||
else:
|
||||
member_list = EveWhoManager.get_corporation_members(corpid)
|
||||
|
||||
characters_with_api = {}
|
||||
characters_without_api = {}
|
||||
|
||||
num_registered_characters = 0
|
||||
for char_id, member_data in member_list.items():
|
||||
try:
|
||||
char = EveCharacter.objects.get(character_id=char_id)
|
||||
char_owner = char.user
|
||||
try:
|
||||
if not char_owner:
|
||||
raise AttributeError("Character has no assigned user.")
|
||||
mainid = int(AuthServicesInfo.objects.get_or_create(user=char_owner)[0].main_char_id)
|
||||
mainchar = EveCharacter.objects.get(character_id=mainid)
|
||||
mainname = mainchar.character_name
|
||||
maincorp = mainchar.corporation_name
|
||||
maincorpid = mainchar.corporation_id
|
||||
api_pair = EveApiKeyPair.objects.get(api_id=char.api_id)
|
||||
except (ValueError, EveCharacter.DoesNotExist, EveApiKeyPair.DoesNotExist):
|
||||
logger.debug("No main character seem to be set for character %s" % char.character_name)
|
||||
mainname = "User: " + char_owner.username
|
||||
mainchar = char
|
||||
maincorp = "Not set."
|
||||
maincorpid = None
|
||||
api_pair = None
|
||||
except AttributeError:
|
||||
logger.debug("No associated user for character %s" % char.character_name)
|
||||
mainname = None
|
||||
mainchar = char
|
||||
maincorp = None
|
||||
maincorpid = None
|
||||
try:
|
||||
api_pair = EveApiKeyPair.objects.get(api_id=char.api_id)
|
||||
except EveApiKeyPair.DoesNotExist:
|
||||
api_pair = None
|
||||
num_registered_characters += 1
|
||||
characters_with_api.setdefault(mainname, Player(main=mainchar,
|
||||
user=char_owner,
|
||||
maincorp=maincorp,
|
||||
maincorpid=maincorpid,
|
||||
altlist=[],
|
||||
apilist=[],
|
||||
n_fats=0)
|
||||
).altlist.append(char)
|
||||
if api_pair:
|
||||
characters_with_api[mainname].apilist.append(api_pair)
|
||||
|
||||
except EveCharacter.DoesNotExist:
|
||||
characters_without_api.update({member_data["name"]: member_data["id"]})
|
||||
|
||||
for char in EveCharacter.objects.filter(corporation_id=corpid):
|
||||
if not int(char.character_id) in member_list:
|
||||
logger.debug("Character '%s' does not exist in EveWho dump." % char.character_name)
|
||||
char_owner = char.user
|
||||
try:
|
||||
if not char_owner:
|
||||
raise AttributeError("Character has no assigned user.")
|
||||
mainid = int(AuthServicesInfo.objects.get_or_create(user=char_owner)[0].main_char_id)
|
||||
mainchar = EveCharacter.objects.get(character_id=mainid)
|
||||
mainname = mainchar.character_name
|
||||
maincorp = mainchar.corporation_name
|
||||
maincorpid = mainchar.corporation_id
|
||||
api_pair = EveApiKeyPair.objects.get(api_id=char.api_id)
|
||||
except (ValueError, EveCharacter.DoesNotExist, EveApiKeyPair.DoesNotExist):
|
||||
logger.debug("No main character seem to be set for character %s" % char.character_name)
|
||||
mainname = "User: " + char_owner.username
|
||||
mainchar = char
|
||||
maincorp = "Not set."
|
||||
maincorpid = None
|
||||
api_pair = None
|
||||
except AttributeError:
|
||||
logger.debug("No associated user for character %s" % char.character_name)
|
||||
mainname = None
|
||||
mainchar = char
|
||||
maincorp = None
|
||||
maincorpid = None
|
||||
try:
|
||||
api_pair = EveApiKeyPair.objects.get(api_id=char.api_id)
|
||||
except EveApiKeyPair.DoesNotExist:
|
||||
api_pair = None
|
||||
num_registered_characters += 1
|
||||
characters_with_api.setdefault(mainname, Player(main=mainchar,
|
||||
user=char_owner,
|
||||
maincorp=maincorp,
|
||||
maincorpid=maincorpid,
|
||||
altlist=[],
|
||||
apilist=[],
|
||||
n_fats=0)
|
||||
).altlist.append(char)
|
||||
if api_pair:
|
||||
characters_with_api[mainname].apilist.append(api_pair)
|
||||
|
||||
n_unacounted = corp.member_count - (num_registered_characters + len(characters_without_api))
|
||||
|
||||
for mainname, player in characters_with_api.items():
|
||||
fats_this_month = Fat.objects.filter(user=player.user).filter(
|
||||
fatlink__fatdatetime__gte=start_of_month).filter(fatlink__fatdatetime__lt=start_of_next_month)
|
||||
characters_with_api[mainname].n_fats = len(fats_this_month)
|
||||
|
||||
if start_of_next_month > datetime.datetime.now():
|
||||
start_of_next_month = None
|
||||
|
||||
if not settings.IS_CORP:
|
||||
context = {"membercorplist": membercorplist,
|
||||
"corp": corp,
|
||||
"characters_with_api": sorted(characters_with_api.items()),
|
||||
'n_registered': num_registered_characters,
|
||||
'n_unacounted': n_unacounted,
|
||||
"characters_without_api": sorted(characters_without_api.items()),
|
||||
"search_form": CorputilsSearchForm()}
|
||||
else:
|
||||
logger.debug("corp_member_view running in corportation mode")
|
||||
context = {"corp": corp,
|
||||
"characters_with_api": sorted(characters_with_api.items()),
|
||||
'n_registered': num_registered_characters,
|
||||
'n_unacounted': n_unacounted,
|
||||
"characters_without_api": sorted(characters_without_api.items()),
|
||||
"search_form": CorputilsSearchForm()}
|
||||
|
||||
context["next_month"] = start_of_next_month
|
||||
context["previous_month"] = start_of_previous_month
|
||||
context["this_month"] = start_of_month
|
||||
|
||||
return render(request, 'registered/corputils.html', context=context)
|
||||
else:
|
||||
logger.warn('User %s (%s) not authorized to view corp stats for corp id %s' % (request.user, user_corp_id, corpid))
|
||||
return redirect("auth_dashboard")
|
||||
|
||||
|
||||
def can_see_api(user, character):
|
||||
if user.has_perm('auth.alliance_apis'):
|
||||
return True
|
||||
try:
|
||||
user_main = EveCharacter.objects.get(
|
||||
character_id=AuthServicesInfo.objects.get_or_create(user=user)[0].main_char_id)
|
||||
if user.has_perm('auth.corp_apis') and user_main.corporation_id == character.corporation_id:
|
||||
return True
|
||||
except EveCharacter.DoesNotExist:
|
||||
return False
|
||||
return False
|
||||
|
||||
corp_id = token.get_esi_client().Character.get_characters_character_id(character_id=token.character_id).result()['corporation_id']
|
||||
corp = EveCorporationInfo.objects.get(corporation_id=corp_id)
|
||||
cs = CorpStats.objects.create(token=token, corp=corp)
|
||||
cs.update()
|
||||
assert cs.pk # ensure update was succesful
|
||||
if CorpStats.objects.filter(pk=cs.pk).visible_to(request.user).exists():
|
||||
return redirect('corputils:view_corp', corp_id=corp.corporation_id)
|
||||
except EveCorporationInfo.DoesNotExist:
|
||||
messages.error(request, 'Unrecognized corporation. Please ensure it is a member of the alliance or a blue.')
|
||||
except IntegrityError:
|
||||
messages.error(request, 'Selected corp already has a statistics module.')
|
||||
except AssertionError:
|
||||
messages.error(request, 'Failed to gather corporation statistics with selected token.')
|
||||
return redirect('corputils:view')
|
||||
|
||||
@login_required
|
||||
def corputils_search(request, corpid=settings.CORP_ID):
|
||||
logger.debug("corputils_search called by user %s" % request.user)
|
||||
@user_passes_test(access_corpstats_test)
|
||||
def corpstats_view(request, corp_id=None):
|
||||
corpstats = None
|
||||
show_apis = False
|
||||
|
||||
corp = EveCorporationInfo.objects.get(corporation_id=corpid)
|
||||
# get requested model
|
||||
if corp_id:
|
||||
corp = get_object_or_404(EveCorporationInfo, corporation_id=corp_id)
|
||||
corpstats = get_object_or_404(CorpStats, corp=corp)
|
||||
|
||||
authorized = False
|
||||
try:
|
||||
user_main = EveCharacter.objects.get(
|
||||
character_id=AuthServicesInfo.objects.get_or_create(user=request.user)[0].main_char_id)
|
||||
if request.user.has_perm('auth.alliance_apis') or (
|
||||
request.user.has_perm('auth.corp_apis') and (user_main.corporation_id == corpid)):
|
||||
logger.debug("Retreiving and sending API-information")
|
||||
authorized = True
|
||||
except (ValueError, EveCharacter.DoesNotExist):
|
||||
if request.user.has_perm('auth.alliance_apis'):
|
||||
logger.debug("Retrieving and sending API-information")
|
||||
authorized = True
|
||||
# get available models
|
||||
available = CorpStats.objects.visible_to(request.user)
|
||||
|
||||
if authorized:
|
||||
if request.method == 'POST':
|
||||
form = CorputilsSearchForm(request.POST)
|
||||
logger.debug("Request type POST contains form valid: %s" % form.is_valid())
|
||||
if form.is_valid():
|
||||
# Really dumb search and only checks character name
|
||||
# This can be improved but it does the job for now
|
||||
searchstring = form.cleaned_data['search_string']
|
||||
logger.debug("Searching for player with character name %s for user %s" % (searchstring, request.user))
|
||||
# ensure we can see the requested model
|
||||
if corpstats and not corpstats in available:
|
||||
raise PermissionDenied('You do not have permission to view the selected corporation statistics module.')
|
||||
|
||||
member_list = {}
|
||||
if settings.IS_CORP:
|
||||
member_list = EveApiManager.get_corp_membertracking(settings.CORP_API_ID, settings.CORP_API_VCODE)
|
||||
if not member_list:
|
||||
logger.debug('Unable to fetch members from API. Pulling from EveWho')
|
||||
member_list = EveWhoManager.get_corporation_members(corpid)
|
||||
# get default model if none requested
|
||||
if not corp_id and available.count() == 1:
|
||||
corpstats = available[0]
|
||||
|
||||
SearchResult = namedtuple('SearchResult',
|
||||
['name', 'id', 'main', 'api_registered', 'character', 'apiinfo'])
|
||||
context = {
|
||||
'available': available,
|
||||
}
|
||||
|
||||
searchresults = []
|
||||
for memberid, member_data in member_list.items():
|
||||
if searchstring.lower() in member_data["name"].lower():
|
||||
try:
|
||||
char = EveCharacter.objects.get(character_name=member_data["name"])
|
||||
user = char.user
|
||||
mainid = int(AuthServicesInfo.objects.get_or_create(user=user)[0].main_char_id)
|
||||
main = EveCharacter.objects.get(character_id=mainid)
|
||||
if can_see_api(request.user, char):
|
||||
api_registered = True
|
||||
apiinfo = EveApiKeyPair.objects.get(api_id=char.api_id)
|
||||
else:
|
||||
api_registered = False
|
||||
apiinfo = None
|
||||
except EveCharacter.DoesNotExist:
|
||||
api_registered = False
|
||||
char = None
|
||||
main = ""
|
||||
apiinfo = None
|
||||
# paginate
|
||||
members = []
|
||||
if corpstats:
|
||||
page = request.GET.get('page', 1)
|
||||
members = get_page(corpstats.get_member_objects(request.user), page)
|
||||
|
||||
searchresults.append(SearchResult(name=member_data["name"], id=memberid, main=main,
|
||||
api_registered=api_registered,
|
||||
character=char, apiinfo=apiinfo))
|
||||
if corpstats:
|
||||
context.update({
|
||||
'corpstats': corpstats.get_view_model(request.user),
|
||||
'members': members,
|
||||
})
|
||||
|
||||
logger.info("Found %s members for user %s matching search string %s" % (
|
||||
len(searchresults), request.user, searchstring))
|
||||
return render(request, 'corputils/corpstats.html', context=context)
|
||||
|
||||
context = {'corp': corp, 'results': searchresults, 'search_form': CorputilsSearchForm(),
|
||||
"year": datetime.datetime.now().year, "month": datetime.datetime.now().month}
|
||||
|
||||
return render(request, 'registered/corputilssearchview.html',
|
||||
context=context)
|
||||
else:
|
||||
logger.debug("Form invalid - returning for user %s to retry." % request.user)
|
||||
context = {'corp': corp, 'members': None, 'search_form': CorputilsSearchForm()}
|
||||
return render(request, 'registered/corputilssearchview.html', context=context)
|
||||
|
||||
else:
|
||||
logger.debug("Returning empty search form for user %s" % request.user)
|
||||
return redirect("auth_corputils")
|
||||
@login_required
|
||||
@user_passes_test(access_corpstats_test)
|
||||
def corpstats_update(request, corp_id):
|
||||
corp = get_object_or_404(EveCorporationInfo, corporation_id=corp_id)
|
||||
corpstats = get_object_or_404(CorpStats, corp=corp)
|
||||
if corpstats.can_update(request.user):
|
||||
corpstats.update()
|
||||
else:
|
||||
logger.warn('User %s not authorized to view corp stats for corp ID %s' % (request.user, corpid))
|
||||
return redirect("auth_dashboard")
|
||||
raise PermissionDenied('You do not have permission to update member data for the selected corporation statistics module.')
|
||||
return redirect('corputils:view_corp', corp_id=corp.corporation_id)
|
||||
|
||||
@login_required
|
||||
@user_passes_test(access_corpstats_test)
|
||||
def corpstats_search(request):
|
||||
results = []
|
||||
search_string = request.GET.get('search_string', None)
|
||||
if search_string:
|
||||
has_similar = CorpStats.objects.filter(_members__icontains=search_string).visible_to(request.user)
|
||||
for corpstats in has_similar:
|
||||
similar = [(member_id, corpstats.members[member_id]) for member_id in corpstats.members if search_string.lower() in corpstats.members[member_id].lower()]
|
||||
for s in similar:
|
||||
results.append((corpstats, CorpStats.MemberObject(s[0], s[1], show_apis=corpstats.show_apis(request.user))))
|
||||
page = request.GET.get('page', 1)
|
||||
results = sorted(results, key=lambda x: x[1].character_name)
|
||||
results_page = get_page(results, page)
|
||||
context = {
|
||||
'available': CorpStats.objects.visible_to(request.user),
|
||||
'results': results_page,
|
||||
'search_string': search_string,
|
||||
}
|
||||
return render(request, 'corputils/search.html', context=context)
|
||||
return redirect('corputils:view')
|
||||
|
@ -3,71 +3,48 @@ from eveonline.models import EveCharacter
|
||||
from eveonline.models import EveApiKeyPair
|
||||
from eveonline.models import EveAllianceInfo
|
||||
from eveonline.models import EveCorporationInfo
|
||||
|
||||
from eveonline.providers import eve_adapter_factory, EveXmlProvider
|
||||
from services.managers.eve_api_manager import EveApiManager
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
adapter = eve_adapter_factory()
|
||||
|
||||
class EveManager:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@staticmethod
|
||||
def create_character(character_id, character_name, corporation_id,
|
||||
corporation_name, corporation_ticker, alliance_id,
|
||||
alliance_name, user, api_id):
|
||||
logger.debug("Creating model for character %s id %s" % (character_name, character_id))
|
||||
if not EveCharacter.objects.filter(character_id=character_id).exists():
|
||||
eve_char = EveCharacter()
|
||||
eve_char.character_id = character_id
|
||||
eve_char.character_name = character_name
|
||||
eve_char.corporation_id = corporation_id
|
||||
eve_char.corporation_name = corporation_name
|
||||
eve_char.corporation_ticker = corporation_ticker
|
||||
eve_char.alliance_id = alliance_id
|
||||
eve_char.alliance_name = alliance_name
|
||||
eve_char.user = user
|
||||
eve_char.api_id = api_id
|
||||
eve_char.save()
|
||||
logger.info("Created new character model %s for user %s" % (eve_char, user))
|
||||
else:
|
||||
logger.warn("Attempting to create existing character model with id %s" % character_id)
|
||||
def create_character(id, user, api_id):
|
||||
return EveManager.create_character_obj(adapter.get_character(id), user, api_id)
|
||||
|
||||
@staticmethod
|
||||
def create_characters_from_list(chars, user, api_id):
|
||||
logger.debug("Creating characters from batch: %s" % chars.result)
|
||||
for char in chars.result:
|
||||
if not EveManager.check_if_character_exist(chars.result[char]['name']):
|
||||
EveManager.create_character(chars.result[char]['id'],
|
||||
chars.result[char]['name'],
|
||||
chars.result[char]['corp']['id'],
|
||||
chars.result[char]['corp']['name'],
|
||||
EveApiManager.get_corporation_ticker_from_id(
|
||||
chars.result[char]['corp']['id']),
|
||||
chars.result[char]['alliance']['id'],
|
||||
chars.result[char]['alliance']['name'],
|
||||
user, api_id)
|
||||
def create_character_obj(character, user, api_id):
|
||||
EveCharacter.objects.create(
|
||||
character_id = character.id,
|
||||
character_name = character.name,
|
||||
corporation_id = character.corp.id,
|
||||
corporation_name = character.corp.name,
|
||||
alliance_id = character.alliance.id,
|
||||
alliance_name = character.alliance.name,
|
||||
user = user,
|
||||
api_id = api_id,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def update_characters_from_list(chars):
|
||||
logger.debug("Updating characters from list: %s" % chars.result)
|
||||
for char in chars.result:
|
||||
if EveManager.check_if_character_exist(chars.result[char]['name']):
|
||||
eve_char = EveManager.get_character_by_character_name(chars.result[char]['name'])
|
||||
logger.debug("Got existing character model %s" % eve_char)
|
||||
eve_char.corporation_id = chars.result[char]['corp']['id']
|
||||
eve_char.corporation_name = chars.result[char]['corp']['name']
|
||||
eve_char.corporation_ticker = EveApiManager.get_corporation_ticker_from_id(
|
||||
chars.result[char]['corp']['id'])
|
||||
eve_char.alliance_id = chars.result[char]['alliance']['id']
|
||||
eve_char.alliance_name = chars.result[char]['alliance']['name']
|
||||
eve_char.save()
|
||||
logger.info("Updated character model %s" % eve_char)
|
||||
else:
|
||||
logger.warn(
|
||||
"Attempting to update non-existing character model with name %s" % chars.result[char]['name'])
|
||||
def update_character(id):
|
||||
return EveManager.update_character_obj(adapter.get_character(id))
|
||||
|
||||
@staticmethod
|
||||
def update_character_obj(char):
|
||||
model = EveCharacter.objects.get(character_id=char.id)
|
||||
model.character_name = char.name
|
||||
model.corporation_id = char.corp.id
|
||||
model.corporation_name = char.corp.name
|
||||
model.alliance_id = char.alliance.id
|
||||
model.alliance_name = char.alliance.name
|
||||
model.save()
|
||||
|
||||
@staticmethod
|
||||
def create_api_keypair(api_id, api_key, user_id):
|
||||
@ -83,64 +60,80 @@ class EveManager:
|
||||
logger.warn("Attempting to create existing api keypair with id %s" % api_id)
|
||||
|
||||
@staticmethod
|
||||
def create_alliance_info(alliance_id, alliance_name, alliance_ticker, alliance_executor_corp_id,
|
||||
alliance_member_count, is_blue):
|
||||
logger.debug("Creating alliance info for alliance %s id %s" % (alliance_name, alliance_id))
|
||||
if not EveManager.check_if_alliance_exists_by_id(alliance_id):
|
||||
alliance_info = EveAllianceInfo()
|
||||
alliance_info.alliance_id = alliance_id
|
||||
alliance_info.alliance_name = alliance_name
|
||||
alliance_info.alliance_ticker = alliance_ticker
|
||||
alliance_info.executor_corp_id = alliance_executor_corp_id
|
||||
alliance_info.member_count = alliance_member_count
|
||||
alliance_info.is_blue = is_blue
|
||||
alliance_info.save()
|
||||
logger.info("Created alliance model for %s" % alliance_info)
|
||||
else:
|
||||
logger.warn("Attempting to create existing alliance model with id %s" % alliance_id)
|
||||
def create_alliance(id, is_blue=False):
|
||||
return EveManager.create_alliance_obj(adapter.get_alliance(id), is_blue=is_blue)
|
||||
|
||||
@staticmethod
|
||||
def update_alliance_info(alliance_id, alliance_executor_corp_id, alliance_member_count, is_blue):
|
||||
logger.debug("Updating alliance model with id %s" % alliance_id)
|
||||
if EveManager.check_if_alliance_exists_by_id(alliance_id):
|
||||
alliance_info = EveAllianceInfo.objects.get(alliance_id=alliance_id)
|
||||
alliance_info.executor_corp_id = alliance_executor_corp_id
|
||||
alliance_info.member_count = alliance_member_count
|
||||
alliance_info.is_blue = is_blue
|
||||
alliance_info.save()
|
||||
logger.debug("Updated alliance model %s" % alliance_info)
|
||||
else:
|
||||
logger.warn("Attempting to update non-existing alliance model with id %s" % alliance_id)
|
||||
def create_alliance_obj(alliance, is_blue=False):
|
||||
EveAllianceInfo.objects.create(
|
||||
alliance_id = alliance.id,
|
||||
alliance_name = alliance.name,
|
||||
alliance_ticker = alliance.ticker,
|
||||
executor_corp_id = alliance.executor_corp_id,
|
||||
is_blue = is_blue,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def create_corporation_info(corp_id, corp_name, corp_ticker, corp_member_count, is_blue, alliance):
|
||||
logger.debug("Creating corp info for corp %s id %s" % (corp_name, corp_id))
|
||||
if not EveManager.check_if_corporation_exists_by_id(corp_id):
|
||||
corp_info = EveCorporationInfo()
|
||||
corp_info.corporation_id = corp_id
|
||||
corp_info.corporation_name = corp_name
|
||||
corp_info.corporation_ticker = corp_ticker
|
||||
corp_info.member_count = corp_member_count
|
||||
corp_info.is_blue = is_blue
|
||||
if alliance:
|
||||
corp_info.alliance = alliance
|
||||
corp_info.save()
|
||||
logger.info("Created corp model for %s" % corp_info)
|
||||
else:
|
||||
logger.warn("Attempting to create existing corp model with id %s" % corp_id)
|
||||
def update_alliance(id, is_blue=None):
|
||||
return EveManager.update_alliance_obj(adapter.get_alliance(id), is_blue=is_blue)
|
||||
|
||||
@staticmethod
|
||||
def update_corporation_info(corp_id, corp_member_count, alliance, is_blue):
|
||||
logger.debug("Updating corp model with id %s" % corp_id)
|
||||
if EveManager.check_if_corporation_exists_by_id(corp_id):
|
||||
corp_info = EveCorporationInfo.objects.get(corporation_id=corp_id)
|
||||
corp_info.member_count = corp_member_count
|
||||
corp_info.alliance = alliance
|
||||
corp_info.is_blue = is_blue
|
||||
corp_info.save()
|
||||
logger.debug("Updated corp model %s" % corp_info)
|
||||
else:
|
||||
logger.warn("Attempting to update non-existant corp model with id %s" % corp_id)
|
||||
def update_alliance_obj(alliance, is_blue=None):
|
||||
model = EveAllianceInfo.objects.get(alliance_id=alliance.id)
|
||||
model.executor_corp_id = alliance.executor_corp_id
|
||||
model.is_blue = model.is_blue if is_blue == None else is_blue
|
||||
model.save()
|
||||
|
||||
@staticmethod
|
||||
def populate_alliance(id):
|
||||
alliance_model = EveAllianceInfo.objects.get(alliance_id=id)
|
||||
alliance = adapter.get_alliance(id)
|
||||
for corp_id in alliance.corp_ids:
|
||||
if not EveCorporationInfo.objects.filter(corporation_id=corp_id).exists():
|
||||
EveManager.create_corporation(corp_id, is_blue=alliance_model.is_blue)
|
||||
EveCorporationInfo.objects.filter(corporation_id__in=alliance.corp_ids).update(alliance=alliance_model)
|
||||
EveCorporationInfo.objects.filter(alliance=alliance_model).exclude(corporation_id__in=alliance.corp_ids).update(alliance=None)
|
||||
|
||||
|
||||
@staticmethod
|
||||
def create_corporation(id, is_blue=False):
|
||||
return EveManager.create_corporation_obj(adapter.get_corp(id), is_blue=is_blue)
|
||||
|
||||
@staticmethod
|
||||
def create_corporation_obj(corp, is_blue=False):
|
||||
try:
|
||||
alliance = EveAllianceInfo.objects.get(alliance_id=corp.alliance_id)
|
||||
except EveAllianceInfo.DoesNotExist:
|
||||
alliance = None
|
||||
EveCorporationInfo.objects.create(
|
||||
corporation_id = corp.id,
|
||||
corporation_name = corp.name,
|
||||
corporation_ticker = corp.ticker,
|
||||
member_count = corp.members,
|
||||
alliance = alliance,
|
||||
is_blue = is_blue,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def update_corporation(id, is_blue=None):
|
||||
return EveManager.update_corporation_obj(adapter.get_corp(id), is_blue=is_blue)
|
||||
|
||||
@staticmethod
|
||||
def update_corporation_obj(corp, is_blue=None):
|
||||
model = EveCorporationInfo.objects.get(corporation_id=corp.id)
|
||||
model.member_count = corp.members
|
||||
try:
|
||||
model.alliance = EveAllianceInfo.objects.get(alliance_id=corp.alliance_id)
|
||||
except EveAllianceInfo.DoesNotExist:
|
||||
model.alliance = None
|
||||
model.is_blue = model.is_blue if is_blue == None else is_blue
|
||||
model.save()
|
||||
|
||||
@staticmethod
|
||||
def get_characters_from_api(api):
|
||||
char_result = EveApiManager.get_characters_from_api(api.api_id, api.api_key).result
|
||||
provider = EveXmlProvider(adapter=adapter)
|
||||
return [provider._build_character(result) for id, result in char_result.items()]
|
||||
|
||||
@staticmethod
|
||||
def get_api_key_pairs(user):
|
||||
|
@ -0,0 +1,19 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.10.1 on 2016-12-16 23:22
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('eveonline', '0004_eveapikeypair_sso_verified'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='eveallianceinfo',
|
||||
name='member_count',
|
||||
),
|
||||
]
|
@ -38,7 +38,6 @@ class EveAllianceInfo(models.Model):
|
||||
alliance_ticker = models.CharField(max_length=254)
|
||||
executor_corp_id = models.CharField(max_length=254)
|
||||
is_blue = models.BooleanField(default=False)
|
||||
member_count = models.IntegerField()
|
||||
|
||||
def __str__(self):
|
||||
return self.alliance_name
|
||||
|
279
eveonline/providers.py
Normal file
279
eveonline/providers.py
Normal file
@ -0,0 +1,279 @@
|
||||
from django.utils.encoding import python_2_unicode_compatible
|
||||
from esi.clients import esi_client_factory
|
||||
from django.conf import settings
|
||||
from bravado.exception import HTTPNotFound, HTTPUnprocessableEntity
|
||||
import evelink
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class ObjectNotFound(Exception):
|
||||
def __init__(self, id, type):
|
||||
self.id = id
|
||||
self.type = type
|
||||
|
||||
def __str__(self):
|
||||
return '%s with ID %s not found.' % (self.type, self.id)
|
||||
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class Entity(object):
|
||||
def __init__(self, id, name):
|
||||
self.id = id
|
||||
self.name = name
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
def __repr__(self):
|
||||
return "<{} ({}): {}>".format(self.__class__.__name__, self.id, self.name)
|
||||
|
||||
def __bool__(self):
|
||||
return bool(self.id)
|
||||
|
||||
def __eq__(self, other):
|
||||
return self.id == other.id
|
||||
|
||||
|
||||
class Corporation(Entity):
|
||||
def __init__(self, provider, id, name, ticker, ceo_id, members, alliance_id):
|
||||
super(Corporation, self).__init__(id, name)
|
||||
self.provider = provider
|
||||
self.ticker = ticker
|
||||
self.ceo_id = ceo_id
|
||||
self.members = members
|
||||
self.alliance_id = alliance_id
|
||||
|
||||
@property
|
||||
def alliance(self):
|
||||
if self.alliance_id:
|
||||
return self.provider.get_alliance(self.alliance_id)
|
||||
return Entity(None, None)
|
||||
|
||||
@property
|
||||
def ceo(self):
|
||||
return self.provider.get_character(self.ceo_id)
|
||||
|
||||
|
||||
class Alliance(Entity):
|
||||
def __init__(self, provider, id, name, ticker, corp_ids, executor_corp_id):
|
||||
super(Alliance, self).__init__(id, name)
|
||||
self.provider = provider
|
||||
self.ticker = ticker
|
||||
self.corp_ids = corp_ids
|
||||
self.executor_corp_id = executor_corp_id
|
||||
|
||||
def corp(self, id):
|
||||
assert id in self.corp_ids
|
||||
return self.provider.get_corp(id)
|
||||
|
||||
@property
|
||||
def corps(self):
|
||||
return sorted([self.corp(id) for id in self.corp_ids], key=lambda x: x.name)
|
||||
|
||||
@property
|
||||
def executor_corp(self):
|
||||
return self.provider.get_corp(self.executor_corp_id)
|
||||
|
||||
|
||||
class Character(Entity):
|
||||
def __init__(self, provider, id, name, corp_id, alliance_id):
|
||||
super(Character, self).__init__(id, name)
|
||||
self.provider = provider
|
||||
self.corp_id = corp_id
|
||||
self.alliance_id = alliance_id
|
||||
|
||||
@property
|
||||
def corp(self):
|
||||
return self.provider.get_corp(self.corp_id)
|
||||
|
||||
@property
|
||||
def alliance(self):
|
||||
if self.alliance_id:
|
||||
return self.provider.get_alliance(self.alliance_id)
|
||||
return Entity(None, None)
|
||||
|
||||
|
||||
class EveProvider:
|
||||
def get_alliance(self, alliance_id):
|
||||
"""
|
||||
:return: an Alliance object for the given ID
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
|
||||
def get_corp(self, corp_id):
|
||||
"""
|
||||
:return: a Corporation object for the given ID
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
|
||||
def get_character(self, corp_id):
|
||||
"""
|
||||
:return: a Character object for the given ID
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class EveSwaggerProvider(EveProvider):
|
||||
def __init__(self, token=None, adapter=None):
|
||||
self.client = esi_client_factory(token=token)
|
||||
self.adapter = adapter or self
|
||||
|
||||
def __str__(self):
|
||||
return 'esi'
|
||||
|
||||
def get_alliance(self, id):
|
||||
try:
|
||||
data = self.client.Alliance.get_alliances_alliance_id(alliance_id=id).result()
|
||||
corps = self.client.Alliance.get_alliances_alliance_id_corporations(alliance_id=id).result()
|
||||
model = Alliance(
|
||||
self.adapter,
|
||||
id,
|
||||
data['alliance_name'],
|
||||
data['ticker'],
|
||||
corps,
|
||||
data['executor_corp'],
|
||||
)
|
||||
return model
|
||||
except HTTPNotFound:
|
||||
raise ObjectNotFound(id, 'alliance')
|
||||
|
||||
def get_corp(self, id):
|
||||
try:
|
||||
data = self.client.Corporation.get_corporations_corporation_id(corporation_id=id).result()
|
||||
model = Corporation(
|
||||
self.adapter,
|
||||
id,
|
||||
data['corporation_name'],
|
||||
data['ticker'],
|
||||
data['ceo_id'],
|
||||
data['member_count'],
|
||||
data['alliance_id'] if 'alliance_id' in data else None,
|
||||
)
|
||||
return model
|
||||
except HTTPNotFound:
|
||||
raise ObjectNotFound(id, 'corporation')
|
||||
|
||||
def get_character(self, id):
|
||||
try:
|
||||
data = self.client.Character.get_characters_character_id(character_id=id).result()
|
||||
alliance_id = self.adapter.get_corp(data['corporation_id']).alliance_id
|
||||
model = Character(
|
||||
self.adapter,
|
||||
id,
|
||||
data['name'],
|
||||
data['corporation_id'],
|
||||
alliance_id,
|
||||
)
|
||||
return model
|
||||
except (HTTPNotFound, HTTPUnprocessableEntity):
|
||||
raise ObjectNotFound(id, 'character')
|
||||
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class EveXmlProvider(EveProvider):
|
||||
def __init__(self, api_key=None, adapter=None):
|
||||
"""
|
||||
:param api_key: eveonline.EveApiKeyPair
|
||||
"""
|
||||
self.api = evelink.api.API(api_key=(api_key.api_id, api_key.api_key)) if api_key else evelink.api.API()
|
||||
self.adapter = adapter or self
|
||||
|
||||
def __str__(self):
|
||||
return 'xml'
|
||||
|
||||
def get_alliance(self, id):
|
||||
api = evelink.eve.EVE(api=self.api)
|
||||
alliances = api.alliances().result
|
||||
try:
|
||||
results = alliances[int(id)]
|
||||
except KeyError:
|
||||
raise ObjectNotFound(id, 'alliance')
|
||||
model = Alliance(
|
||||
self.adapter,
|
||||
id,
|
||||
results['name'],
|
||||
results['ticker'],
|
||||
results['member_corps'],
|
||||
results['executor_id'],
|
||||
)
|
||||
return model
|
||||
|
||||
def get_corp(self, id):
|
||||
api = evelink.corp.Corp(api=self.api)
|
||||
try:
|
||||
corpinfo = api.corporation_sheet(corp_id=int(id)).result
|
||||
except evelink.api.APIError as e:
|
||||
if int(e.code) == 523:
|
||||
raise ObjectNotFound(id, 'corporation')
|
||||
raise e
|
||||
model = Corporation(
|
||||
self.adapter,
|
||||
id,
|
||||
corpinfo['name'],
|
||||
corpinfo['ceo']['id'],
|
||||
corpinfo['members']['current'],
|
||||
corpinfo['ticker'],
|
||||
corpinfo['alliance']['id'] if corpinfo['alliance'] else None,
|
||||
)
|
||||
return model
|
||||
|
||||
def _build_character(self, result):
|
||||
return Character(
|
||||
self.adapter,
|
||||
result['id'],
|
||||
result['name'],
|
||||
result['corp']['id'],
|
||||
result['alliance']['id'],
|
||||
)
|
||||
|
||||
def get_character(self, id):
|
||||
api = evelink.eve.EVE(api=self.api)
|
||||
try:
|
||||
charinfo = api.character_info_from_id(id).result
|
||||
except evelink.api.APIError as e:
|
||||
if int(e.code) == 105:
|
||||
raise ObjectNotFound(id, 'character')
|
||||
raise e
|
||||
return self._build_character(charinfo)
|
||||
|
||||
|
||||
class EveAdapter(EveProvider):
|
||||
"""
|
||||
Redirects queries to appropriate data source.
|
||||
"""
|
||||
def __init__(self, char_provider, corp_provider, alliance_provider):
|
||||
self.char_provider = char_provider
|
||||
self.corp_provider = corp_provider
|
||||
self.alliance_provider = alliance_provider
|
||||
self.char_provider.adapter = self
|
||||
self.corp_provider.adapter = self
|
||||
self.alliance_provider.adapter = self
|
||||
|
||||
def __repr__(self):
|
||||
return "<{} (char:{}, corp:{}, alliance:{})>".format(self.__class__.__name__, str(self.char_provider), str(self.corp_provider), str(self.alliance_provider))
|
||||
|
||||
def get_character(self, id):
|
||||
return self.char_provider.get_character(id)
|
||||
|
||||
def get_corp(self, id):
|
||||
return self.corp_provider.get_corp(id)
|
||||
|
||||
def get_alliance(self, id):
|
||||
return self.alliance_provider.get_alliance(id)
|
||||
|
||||
|
||||
def eve_adapter_factory(character_source=settings.EVEONLINE_CHARACTER_PROVIDER, corp_source=settings.EVEONLINE_CORP_PROVIDER, alliance_source=settings.EVEONLINE_ALLIANCE_PROVIDER, api_key=None, token=None):
|
||||
sources = [character_source, corp_source, alliance_source]
|
||||
providers = []
|
||||
|
||||
xml = EveXmlProvider(api_key=api_key)
|
||||
esi = EveSwaggerProvider(token=token)
|
||||
|
||||
for source in sources:
|
||||
if source == 'xml':
|
||||
providers.append(xml)
|
||||
elif source == 'esi':
|
||||
providers.append(esi)
|
||||
else:
|
||||
raise ValueError('Unrecognized data source "%s"' % source)
|
||||
return EveAdapter(providers[0], providers[1], providers[2])
|
@ -12,6 +12,7 @@ from services.managers.eve_api_manager import EveApiManager
|
||||
from eveonline.models import EveCharacter
|
||||
from eveonline.models import EveCorporationInfo
|
||||
from eveonline.models import EveAllianceInfo
|
||||
from eveonline.providers import eve_adapter_factory
|
||||
from authentication.tasks import set_state
|
||||
import logging
|
||||
import evelink
|
||||
@ -26,21 +27,16 @@ def refresh_api(api):
|
||||
try:
|
||||
EveApiManager.validate_api(api.api_id, api.api_key, api.user)
|
||||
# Update characters
|
||||
characters = EveApiManager.get_characters_from_api(api.api_id, api.api_key)
|
||||
EveManager.update_characters_from_list(characters)
|
||||
new_character = False
|
||||
for char in characters.result:
|
||||
# Ensure we have a model for all characters on key
|
||||
if not EveManager.check_if_character_exist(characters.result[char]['name']):
|
||||
logger.debug(
|
||||
"API key %s has a new character on the account: %s" % (api.api_id, characters.result[char]['name']))
|
||||
new_character = True
|
||||
if new_character:
|
||||
logger.debug("Creating new character %s from api key %s" % (characters.result[char]['name'], api.api_id))
|
||||
EveManager.create_characters_from_list(characters, api.user, api.api_id)
|
||||
characters = EveManager.get_characters_from_api(api)
|
||||
for c in characters:
|
||||
try:
|
||||
EveManager.update_character_obj(c)
|
||||
except EveCharacter.DoesNotExist:
|
||||
logger.debug("API key %s has a new character on the account: %s" % (api.api_id, c))
|
||||
EveManager.create_character_obj(c, api.user, api.api_id)
|
||||
current_chars = EveCharacter.objects.filter(api_id=api.api_id)
|
||||
for c in current_chars:
|
||||
if not int(c.character_id) in characters.result:
|
||||
if not int(c.character_id) in [c.id for c in characters]:
|
||||
logger.info("Character %s no longer found on API ID %s" % (c, api.api_id))
|
||||
c.delete()
|
||||
except evelink.api.APIError as e:
|
||||
@ -105,65 +101,14 @@ def run_api_refresh():
|
||||
refresh_user_apis.delay(u)
|
||||
|
||||
|
||||
def populate_alliance(id, blue=False):
|
||||
logger.debug("Populating alliance model with id %s blue %s" % (id, blue))
|
||||
alliance_info = EveApiManager.get_alliance_information(id)
|
||||
|
||||
if not alliance_info:
|
||||
raise ValueError("Supplied alliance id %s is invalid" % id)
|
||||
|
||||
if not EveAllianceInfo.objects.filter(alliance_id=id).exists():
|
||||
EveManager.create_alliance_info(alliance_info['id'], alliance_info['name'], alliance_info['ticker'],
|
||||
alliance_info['executor_id'], alliance_info['member_count'], blue)
|
||||
alliance = EveAllianceInfo.objects.get(alliance_id=id)
|
||||
for member_corp in alliance_info['member_corps']:
|
||||
if EveCorporationInfo.objects.filter(corporation_id=member_corp).exists():
|
||||
corp = EveCorporationInfo.objects.get(corporation_id=member_corp)
|
||||
if corp.alliance != alliance:
|
||||
corp.alliance = alliance
|
||||
corp.save()
|
||||
else:
|
||||
logger.info("Creating new alliance member corp id %s" % member_corp)
|
||||
corpinfo = EveApiManager.get_corporation_information(member_corp)
|
||||
EveManager.create_corporation_info(corpinfo['id'], corpinfo['name'], corpinfo['ticker'],
|
||||
corpinfo['members']['current'], blue, alliance)
|
||||
|
||||
@task
|
||||
def update_corp(id):
|
||||
EveManager.update_corporation(id)
|
||||
|
||||
@task
|
||||
def update_alliance(id):
|
||||
alliance = EveAllianceInfo.objects.get(alliance_id=id)
|
||||
corps = EveCorporationInfo.objects.filter(alliance=alliance)
|
||||
logger.debug("Updating alliance %s with %s member corps" % (alliance, len(corps)))
|
||||
allianceinfo = EveApiManager.get_alliance_information(alliance.alliance_id)
|
||||
if allianceinfo:
|
||||
EveManager.update_alliance_info(allianceinfo['id'], allianceinfo['executor_id'],
|
||||
allianceinfo['member_count'], alliance.is_blue)
|
||||
for corp in corps:
|
||||
if corp.corporation_id in allianceinfo['member_corps'] is False:
|
||||
logger.info("Corp %s no longer in alliance %s" % (corp, alliance))
|
||||
corp.alliance = None
|
||||
corp.save()
|
||||
populate_alliance(alliance.alliance_id, blue=alliance.is_blue)
|
||||
elif EveApiManager.check_if_alliance_exists(alliance.alliance_id) is False:
|
||||
logger.info("Alliance %s has closed. Deleting model" % alliance)
|
||||
alliance.delete()
|
||||
|
||||
|
||||
@task
|
||||
def update_corp(id):
|
||||
corp = EveCorporationInfo.objects.get(corporation_id=id)
|
||||
logger.debug("Updating corp %s" % corp)
|
||||
corpinfo = EveApiManager.get_corporation_information(corp.corporation_id)
|
||||
if corpinfo:
|
||||
alliance = None
|
||||
if EveAllianceInfo.objects.filter(alliance_id=corpinfo['alliance']['id']).exists():
|
||||
alliance = EveAllianceInfo.objects.get(alliance_id=corpinfo['alliance']['id'])
|
||||
EveManager.update_corporation_info(corpinfo['id'], corpinfo['members']['current'], alliance, corp.is_blue)
|
||||
elif EveApiManager.check_if_corp_exists(corp.corporation_id) is False:
|
||||
logger.info("Corp %s has closed. Deleting model" % corp)
|
||||
corp.delete()
|
||||
|
||||
# Run Every 2 hours
|
||||
EveManager.update_alliance(id)
|
||||
EveManager.populate_alliance(id)
|
||||
|
||||
|
||||
@periodic_task(run_every=crontab(minute=0, hour="*/2"))
|
||||
@ -172,80 +117,36 @@ def run_corp_update():
|
||||
logger.warn("Aborted updating corp and alliance models: API server unreachable")
|
||||
return
|
||||
standing_level = 'alliance'
|
||||
alliance_id = settings.ALLIANCE_ID
|
||||
|
||||
# get corp info for owning corp if required
|
||||
if settings.IS_CORP:
|
||||
standing_level = 'corp'
|
||||
if EveCorporationInfo.objects.filter(corporation_id=settings.CORP_ID).exists():
|
||||
update_corp(settings.CORP_ID)
|
||||
else:
|
||||
EveManager.create_corporation(settings.CORP_ID)
|
||||
|
||||
alliance_id = eve_adapter_factory().get_corp(settings.CORP_ID).alliance_id
|
||||
|
||||
# get and create alliance info for owning alliance if required
|
||||
if alliance_id:
|
||||
if EveAllianceInfo.objects.filter(alliance_id=alliance_id).exists():
|
||||
logger.debug("Updating existing owner alliance model with id %s" % alliance_id)
|
||||
update_alliance(alliance_id)
|
||||
else:
|
||||
EveManager.create_alliance(id)
|
||||
EveManager.populate_alliance(id)
|
||||
|
||||
# update existing corp models
|
||||
for corp in EveCorporationInfo.objects.all():
|
||||
update_corp.delay(corp.corporation_id)
|
||||
|
||||
# update existing alliance models
|
||||
for alliance in EveAllianceInfo.objects.all():
|
||||
update_alliance.delay(alliance.alliance_id)
|
||||
|
||||
try:
|
||||
# get corp info for owning corp if required
|
||||
ownercorpinfo = {}
|
||||
if settings.IS_CORP:
|
||||
standing_level = 'corp'
|
||||
logger.debug("Getting information for owning corp with id %s" % settings.CORP_ID)
|
||||
ownercorpinfo = EveApiManager.get_corporation_information(settings.CORP_ID)
|
||||
if not ownercorpinfo:
|
||||
logger.error("Failed to retrieve corp info for owning corp id %s - bad corp id?" % settings.CORP_ID)
|
||||
return
|
||||
|
||||
# check if we need to update an alliance model
|
||||
alliance_id = ''
|
||||
if ownercorpinfo and ownercorpinfo['alliance']['id']:
|
||||
alliance_id = ownercorpinfo['alliance']['id']
|
||||
elif settings.IS_CORP is False:
|
||||
alliance_id = settings.ALLIANCE_ID
|
||||
|
||||
# get and create alliance info for owning alliance if required
|
||||
alliance = None
|
||||
if alliance_id:
|
||||
logger.debug("Getting information for owning alliance with id %s" % alliance_id)
|
||||
ownerallianceinfo = EveApiManager.get_alliance_information(alliance_id)
|
||||
if not ownerallianceinfo:
|
||||
logger.error("Failed to retrieve corp info for owning alliance id %s - bad alliance id?" % alliance_id)
|
||||
return
|
||||
if EveAllianceInfo.objects.filter(alliance_id=ownerallianceinfo['id']).exists():
|
||||
logger.debug("Updating existing owner alliance model with id %s" % alliance_id)
|
||||
EveManager.update_alliance_info(ownerallianceinfo['id'], ownerallianceinfo['executor_id'],
|
||||
ownerallianceinfo['member_count'], False)
|
||||
else:
|
||||
populate_alliance(alliance_id)
|
||||
alliance = EveAllianceInfo.objects.get(alliance_id=alliance_id)
|
||||
|
||||
# create corp info for owning corp if required
|
||||
if ownercorpinfo:
|
||||
if EveCorporationInfo.objects.filter(corporation_id=ownercorpinfo['id']).exists():
|
||||
logger.debug("Updating existing owner corp model with id %s" % ownercorpinfo['id'])
|
||||
EveManager.update_corporation_info(ownercorpinfo['id'], ownercorpinfo['members']['current'], alliance,
|
||||
False)
|
||||
else:
|
||||
logger.info("Creating model for owning corp with id %s" % ownercorpinfo['id'])
|
||||
EveManager.create_corporation_info(ownercorpinfo['id'], ownercorpinfo['name'], ownercorpinfo['ticker'],
|
||||
ownercorpinfo['members']['current'], False, alliance)
|
||||
|
||||
# validate and create corp models for member corps of owning alliance
|
||||
if alliance:
|
||||
current_corps = EveCorporationInfo.objects.filter(alliance=alliance)
|
||||
for corp in current_corps:
|
||||
if corp.corporation_id in ownerallianceinfo['member_corps'] is False:
|
||||
logger.info("Corp %s is no longer in owning alliance %s - updating model." % (corp, alliance))
|
||||
corp.alliance = None
|
||||
corp.save()
|
||||
for member_corp in ownerallianceinfo['member_corps']:
|
||||
if EveCorporationInfo.objects.filter(corporation_id=member_corp).exists():
|
||||
corp = EveCorporationInfo.objects.get(corporation_id=member_corp)
|
||||
if corp.alliance == alliance is not True:
|
||||
logger.info("Associating corp %s with owning alliance %s" % (corp, alliance))
|
||||
corp.alliance = alliance
|
||||
corp.save()
|
||||
else:
|
||||
corpinfo = EveApiManager.get_corporation_information(member_corp)
|
||||
logger.info("Creating model for owning alliance member corp with id %s" % corpinfo['id'])
|
||||
EveManager.create_corporation_info(corpinfo['id'], corpinfo['name'], corpinfo['ticker'],
|
||||
corpinfo['members']['current'], False, alliance)
|
||||
|
||||
# update existing corp models
|
||||
for corp in EveCorporationInfo.objects.all():
|
||||
update_corp.delay(corp.corporation_id)
|
||||
|
||||
# update existing alliance models
|
||||
for alliance in EveAllianceInfo.objects.all():
|
||||
update_alliance.delay(alliance.alliance_id)
|
||||
|
||||
# create standings
|
||||
standings = EveApiManager.get_corp_standings()
|
||||
if standings:
|
||||
@ -262,7 +163,7 @@ def run_corp_update():
|
||||
alliance.is_blue = True
|
||||
alliance.save()
|
||||
else:
|
||||
populate_alliance(standing, blue=True)
|
||||
EveManager.create_alliance(standing, blue=True)
|
||||
elif EveApiManager.check_if_id_is_corp(standing):
|
||||
logger.debug("Standing %s is a corp" % standing)
|
||||
if EveCorporationInfo.objects.filter(corporation_id=standing).exists():
|
||||
@ -273,13 +174,7 @@ def run_corp_update():
|
||||
corp.save()
|
||||
else:
|
||||
logger.info("Creating model for blue corp with id %s" % standing)
|
||||
corpinfo = EveApiManager.get_corporation_information(standing)
|
||||
corp_alliance = None
|
||||
if EveAllianceInfo.objects.filter(alliance_id=corpinfo['alliance']['id']).exists():
|
||||
logger.debug("New corp model for standing %s has existing alliance model" % standing)
|
||||
corp_alliance = EveAllianceInfo.objects.get(alliance_id=corpinfo['alliance']['id'])
|
||||
EveManager.create_corporation_info(corpinfo['id'], corpinfo['name'], corpinfo['ticker'],
|
||||
corpinfo['members']['current'], True, corp_alliance)
|
||||
EveManager.create_corporation(standing, blue=True)
|
||||
|
||||
# update alliance standings
|
||||
for alliance in EveAllianceInfo.objects.filter(is_blue=True):
|
||||
@ -310,43 +205,43 @@ def run_corp_update():
|
||||
logger.info("Corp %s is no longer blue" % corp)
|
||||
corp.is_blue = False
|
||||
corp.save()
|
||||
except evelink.api.APIError as e:
|
||||
logger.error("Model update failed with error code %s" % e.code)
|
||||
|
||||
# delete unnecessary alliance models
|
||||
for alliance in EveAllianceInfo.objects.filter(is_blue=False):
|
||||
logger.debug("Checking to delete alliance %s" % alliance)
|
||||
if not settings.IS_CORP:
|
||||
if not alliance.alliance_id == settings.ALLIANCE_ID:
|
||||
logger.info("Deleting unnecessary alliance model %s" % alliance)
|
||||
alliance.delete()
|
||||
# delete unnecessary alliance models
|
||||
for alliance in EveAllianceInfo.objects.filter(is_blue=False):
|
||||
logger.debug("Checking to delete alliance %s" % alliance)
|
||||
if not settings.IS_CORP:
|
||||
if not alliance.alliance_id == settings.ALLIANCE_ID:
|
||||
logger.info("Deleting unnecessary alliance model %s" % alliance)
|
||||
alliance.delete()
|
||||
else:
|
||||
if not alliance.evecorporationinfo_set.filter(corporation_id=settings.CORP_ID).exists():
|
||||
logger.info("Deleting unnecessary alliance model %s" % alliance)
|
||||
alliance.delete()
|
||||
|
||||
# delete unnecessary corp models
|
||||
for corp in EveCorporationInfo.objects.filter(is_blue=False):
|
||||
logger.debug("Checking to delete corp %s" % corp)
|
||||
if not settings.IS_CORP:
|
||||
if corp.alliance:
|
||||
logger.debug("Corp %s has alliance %s" % (corp, corp.alliance))
|
||||
if not corp.alliance.alliance_id == settings.ALLIANCE_ID:
|
||||
logger.info("Deleting unnecessary corp model %s" % corp)
|
||||
corp.delete()
|
||||
else:
|
||||
if not alliance.evecorporationinfo_set.filter(corporation_id=settings.CORP_ID).exists():
|
||||
logger.info("Deleting unnecessary alliance model %s" % alliance)
|
||||
alliance.delete()
|
||||
|
||||
# delete unnecessary corp models
|
||||
for corp in EveCorporationInfo.objects.filter(is_blue=False):
|
||||
logger.debug("Checking to delete corp %s" % corp)
|
||||
if not settings.IS_CORP:
|
||||
logger.info("Deleting unnecessary corp model %s" % corp)
|
||||
corp.delete()
|
||||
else:
|
||||
if corp.corporation_id != settings.CORP_ID:
|
||||
logger.debug("Corp %s is not owning corp" % corp)
|
||||
if corp.alliance:
|
||||
logger.debug("Corp %s has alliance %s" % (corp, corp.alliance))
|
||||
if not corp.alliance.alliance_id == settings.ALLIANCE_ID:
|
||||
if not corp.alliance.evecorporationinfo_set.filter(corporation_id=settings.CORP_ID).exists():
|
||||
logger.info("Deleting unnecessary corp model %s" % corp)
|
||||
corp.delete()
|
||||
else:
|
||||
logger.info("Deleting unnecessary corp model %s" % corp)
|
||||
corp.delete()
|
||||
else:
|
||||
if corp.corporation_id != settings.CORP_ID:
|
||||
logger.debug("Corp %s is not owning corp" % corp)
|
||||
if corp.alliance:
|
||||
logger.debug("Corp %s has alliance %s" % (corp, corp.alliance))
|
||||
if not corp.alliance.evecorporationinfo_set.filter(corporation_id=settings.CORP_ID).exists():
|
||||
logger.info("Deleting unnecessary corp model %s" % corp)
|
||||
corp.delete()
|
||||
else:
|
||||
logger.info("Deleting unnecessary corp model %s" % corp)
|
||||
corp.delete()
|
||||
else:
|
||||
logger.debug("Corp %s is owning corp" % corp)
|
||||
except evelink.api.APIError as e:
|
||||
logger.error("Model update failed with error code %s" % e.code)
|
||||
logger.debug("Corp %s is owning corp" % corp)
|
||||
|
@ -12,7 +12,7 @@ from authentication.models import AuthServicesInfo
|
||||
from authentication.tasks import set_state
|
||||
from eveonline.tasks import refresh_api
|
||||
|
||||
from eve_sso.decorators import token_required
|
||||
from esi.decorators import token_required
|
||||
from django.conf import settings
|
||||
import logging
|
||||
|
||||
@ -46,9 +46,8 @@ def add_api_key(request):
|
||||
api_key.save()
|
||||
owner = request.user
|
||||
# Grab characters associated with the key pair
|
||||
characters = EveApiManager.get_characters_from_api(form.cleaned_data['api_id'],
|
||||
form.cleaned_data['api_key'])
|
||||
EveManager.create_characters_from_list(characters, owner, form.cleaned_data['api_id'])
|
||||
characters = EveManager.get_characters_from_api(api_key)
|
||||
[EveManager.create_character_obj(c, owner, api_key.api_id) for c in characters if not EveCharacter.objects.filter(character_id=c.id).exists()]
|
||||
logger.info("Successfully processed api add form for user %s" % request.user)
|
||||
if not settings.API_SSO_VALIDATION:
|
||||
messages.success(request, 'Added API key %s to your account.' % form.cleaned_data['api_id'])
|
||||
@ -70,7 +69,7 @@ def add_api_key(request):
|
||||
|
||||
@login_required
|
||||
@token_required(new=True)
|
||||
def api_sso_validate(request, tokens, api_id):
|
||||
def api_sso_validate(request, token, api_id):
|
||||
logger.debug('api_sso_validate called by user %s for api %s' % (request.user, api_id))
|
||||
api = get_object_or_404(EveApiKeyPair, api_id=api_id)
|
||||
if api.user and api.user != request.user:
|
||||
@ -81,7 +80,6 @@ def api_sso_validate(request, tokens, api_id):
|
||||
logger.debug('API %s has already been verified.' % api_id)
|
||||
messages.info(request, 'API %s has already been verified' % api_id)
|
||||
return redirect('auth_api_key_management')
|
||||
token = tokens[0]
|
||||
logger.debug('API %s has not been verified. Checking if token for %s matches.' % (api_id, token.character_name))
|
||||
characters = EveApiManager.get_characters_from_api(api.api_id, api.api_key).result
|
||||
if token.character_id in characters:
|
||||
|
@ -0,0 +1,25 @@
|
||||
{% extends 'public/base.html' %}
|
||||
{% block title %}Fleet Participation{% endblock %}
|
||||
{% block page_title %}Fleet Participation{% endblock %}
|
||||
<div class="col-lg-12">
|
||||
<h1 class="page-header text-center">Character not found!</h1>
|
||||
<div class="col-lg-12 container" id="example">
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">{{ character_name }}</div>
|
||||
<div class="panel-body">
|
||||
<div class="col-lg-2 col-sm-2">
|
||||
<img class="ra-avatar img-responsive" src="https://image.eveonline.com/Character/{{ character_id }}_128.jpg">
|
||||
</div>
|
||||
<div class="col-lg-10 col-sm-2">
|
||||
<div class="alert alert-danger" role="alert">Character not registered!</div>
|
||||
This character is not part of any registered API-key. You must go to <a href=" {% url 'auth_api_key_management' %}">API key management</a> and add an API with the character on before being able to click fleet attendance links.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
@ -0,0 +1,63 @@
|
||||
{% extends "public/base.html" %}
|
||||
{% load bootstrap %}
|
||||
{% load staticfiles %}
|
||||
{% load i18n %}
|
||||
{% load bootstrap_pagination %}
|
||||
{% block title %}Alliance Auth{% endblock %}
|
||||
{% block page_title %}{% trans "Fatlink view" %}{% endblock page_title %}
|
||||
|
||||
{% block content %}
|
||||
<div class="col-lg-12">
|
||||
<h1 class="page-header text-center">{% blocktrans %}Edit fatlink "{{ fatlink }}"{% endblocktrans %}
|
||||
<div class="text-right">
|
||||
<form>
|
||||
<button type="submit" onclick="return confirm('Are you sure?')" class="btn btn-danger" name="deletefat" value="True">
|
||||
{% trans "Delete fat" %}
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</h1>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">{% trans "Registered characters" %}</div>
|
||||
<div class="panel-body">
|
||||
<div class="text-center">
|
||||
{% bootstrap_paginate registered_fats range=10 %}
|
||||
</div>
|
||||
<table class="table table-responsive table-hover">
|
||||
<tr>
|
||||
<th class="text-center">{% trans "User" %}</th>
|
||||
<th class="text-center">{% trans "Character" %}</th>
|
||||
<th class="text-center">{% trans "System" %}</th>
|
||||
<th class="text-center">{% trans "Ship" %}</th>
|
||||
<th class="text-center">{% trans "Eve Time" %}</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
{% for fat in registered_fats %}
|
||||
<tr>
|
||||
<td class="text-center">{{ fat.user }}</td>
|
||||
<td class="text-center">{{ fat.character.character_name }}</td>
|
||||
{% if fat.station != "No Station" %}
|
||||
<td class="text-center">Docked in {{ fat.system }}</td>
|
||||
{% else %}
|
||||
<td class="text-center">{{ fat.system }}</td>
|
||||
{% endif %}
|
||||
<td class="text-center">{{ fat.shiptype }}</td>
|
||||
<td class="text-center">{{ fat.fatlink.fatdatetime }}</td>
|
||||
<td class="text-center">
|
||||
<form>
|
||||
<button type="submit" class="btn btn-warning" name="removechar" value="{{ fat.character.character_id }}">
|
||||
<span class="glyphicon glyphicon-remove"></span>
|
||||
</button>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<script src="/static/js/dateformat.js"></script>
|
||||
|
||||
{% endblock content %}
|
@ -6,16 +6,17 @@ from django.contrib.auth.decorators import login_required
|
||||
from django.contrib.auth.decorators import permission_required
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.utils import timezone
|
||||
|
||||
from django.contrib import messages
|
||||
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
|
||||
from eveonline.models import EveCharacter
|
||||
from eveonline.models import EveCorporationInfo
|
||||
from eveonline.managers import EveManager
|
||||
from fleetactivitytracking.forms import FatlinkForm
|
||||
from fleetactivitytracking.models import Fatlink, Fat
|
||||
|
||||
from slugify import slugify
|
||||
from esi.decorators import token_required
|
||||
|
||||
from collections import OrderedDict
|
||||
from slugify import slugify
|
||||
|
||||
import string
|
||||
import random
|
||||
@ -25,15 +26,27 @@ import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
FATS_PER_PAGE = int(getattr(settings, 'FATS_PER_PAGE', 20))
|
||||
|
||||
def get_page(model_list, page_num):
|
||||
p = Paginator(model_list, FATS_PER_PAGE)
|
||||
try:
|
||||
fats = p.page(page_num)
|
||||
except PageNotAnInteger:
|
||||
fatss = p.page(1)
|
||||
except EmptyPage:
|
||||
fatss = p.page(p.num_pages)
|
||||
return fats
|
||||
|
||||
|
||||
class CorpStat(object):
|
||||
def __init__(self, corp_id, corp=None, blue=False):
|
||||
def __init__(self, corp_id, start_of_month, start_of_next_month, corp=None):
|
||||
if corp:
|
||||
self.corp = corp
|
||||
else:
|
||||
self.corp = EveCorporationInfo.objects.get(corporation_id=corp_id)
|
||||
self.n_fats = 0
|
||||
self.blue = blue
|
||||
self.n_fats = Fat.objects.filter(character__corporation_id=self.corp.corporation_id).filter(fatlink__fatdatetime__gte=start_of_month).filter(fatlink__fatdatetime__lte=start_of_next_month).count()
|
||||
self.blue = self.corp.is_blue
|
||||
|
||||
def avg_fat(self):
|
||||
return "%.2f" % (float(self.n_fats) / float(self.corp.member_count))
|
||||
@ -69,7 +82,7 @@ def fatlink_view(request):
|
||||
else:
|
||||
context = {'user': user, 'fats': latest_fats}
|
||||
|
||||
return render(request, 'registered/fatlinkview.html', context=context)
|
||||
return render(request, 'fleetactivitytracking/fatlinkview.html', context=context)
|
||||
|
||||
|
||||
@login_required
|
||||
@ -81,37 +94,38 @@ def fatlink_statistics_view(request, year=datetime.date.today().year, month=date
|
||||
start_of_next_month = first_day_of_next_month(year, month)
|
||||
start_of_previous_month = first_day_of_previous_month(year, month)
|
||||
|
||||
fatStats = OrderedDict()
|
||||
fat_stats = {}
|
||||
|
||||
|
||||
# get FAT stats for member corps
|
||||
if settings.IS_CORP:
|
||||
fatStats[settings.CORP_NAME] = CorpStat(settings.CORP_ID)
|
||||
fat_stats[settings.CORP_ID] = CorpStat(settings.CORP_ID, start_of_month, start_of_next_month)
|
||||
else:
|
||||
alliance_corps = EveCorporationInfo.objects.filter(alliance__alliance_id=settings.ALLIANCE_ID)
|
||||
for corp in alliance_corps:
|
||||
fatStats[corp.corporation_name] = CorpStat(corp.corporation_id, corp=corp)
|
||||
fat_stats[corp.corporation_id] = CorpStat(corp.corporation_id, start_of_month, start_of_next_month)
|
||||
|
||||
fatlinks_in_span = Fatlink.objects.filter(fatdatetime__gte=start_of_month).filter(
|
||||
fatdatetime__lt=start_of_next_month)
|
||||
# get FAT stats for corps not in alliance
|
||||
fats_in_span = Fat.objects.filter(fatlink__fatdatetime__gte=start_of_month).filter(
|
||||
fatlink__fatdatetime__lt=start_of_next_month).exclude(character__corporation_id__in=fat_stats)
|
||||
|
||||
for fatlink in fatlinks_in_span:
|
||||
fats_in_fatlink = Fat.objects.filter(fatlink=fatlink)
|
||||
for fat in fats_in_fatlink:
|
||||
fatStats.setdefault(fat.character.corporation_name,
|
||||
CorpStat(fat.character.corporation_id, blue=True)
|
||||
).n_fats += 1
|
||||
for fat in fats_in_span:
|
||||
if not fat.character.corporation_id in fat_stats:
|
||||
fat_stats[fat.character.corporation_id] = CorpStat(fat.character.corporation_id, start_of_month, start_of_next_month)
|
||||
|
||||
fatStatsList = [fatStat for corp_name, fatStat in fatStats.items()]
|
||||
fatStatsList.sort(key=lambda stat: stat.corp.corporation_name)
|
||||
fatStatsList.sort(key=lambda stat: (stat.n_fats, stat.n_fats / stat.corp.member_count), reverse=True)
|
||||
# collect and sort stats
|
||||
stat_list = [fat_stats[x] for x in fat_stats]
|
||||
stat_list.sort(key=lambda stat: stat.corp.corporation_name)
|
||||
stat_list.sort(key=lambda stat: (stat.n_fats, stat.n_fats / stat.corp.member_count), reverse=True)
|
||||
|
||||
if datetime.datetime.now() > start_of_next_month:
|
||||
context = {'fatStats': fatStatsList, 'month': start_of_month.strftime("%B"), 'year': year,
|
||||
context = {'fatStats': stat_list, 'month': start_of_month.strftime("%B"), 'year': year,
|
||||
'previous_month': start_of_previous_month, 'next_month': start_of_next_month}
|
||||
else:
|
||||
context = {'fatStats': fatStatsList, 'month': start_of_month.strftime("%B"), 'year': year,
|
||||
context = {'fatStats': stat_list, 'month': start_of_month.strftime("%B"), 'year': year,
|
||||
'previous_month': start_of_previous_month}
|
||||
|
||||
return render(request, 'registered/fatlinkstatisticsview.html', context=context)
|
||||
return render(request, 'fleetactivitytracking/fatlinkstatisticsview.html', context=context)
|
||||
|
||||
|
||||
@login_required
|
||||
@ -139,7 +153,7 @@ def fatlink_personal_statistics_view(request, year=datetime.date.today().year, m
|
||||
else:
|
||||
context = {'user': user, 'monthlystats': monthlystats, 'year': year, 'previous_year': year - 1}
|
||||
|
||||
return render(request, 'registered/fatlinkpersonalstatisticsview.html', context=context)
|
||||
return render(request, 'fleetactivitytracking/fatlinkpersonalstatisticsview.html', context=context)
|
||||
|
||||
|
||||
@login_required
|
||||
@ -173,55 +187,58 @@ def fatlink_monthly_personal_statistics_view(request, year, month, char_id=None)
|
||||
context["created_fats"] = created_fats
|
||||
context["n_created_fats"] = len(created_fats)
|
||||
|
||||
return render(request, 'registered/fatlinkpersonalmonthlystatisticsview.html', context=context)
|
||||
return render(request, 'fleetactivitytracking/fatlinkpersonalmonthlystatisticsview.html', context=context)
|
||||
|
||||
|
||||
@login_required
|
||||
def click_fatlink_view(request, hash, fatname):
|
||||
# Take IG-header data and register the fatlink if not existing already.
|
||||
# use obj, created = Fat.objects.get_or_create()
|
||||
# onload="CCPEVE.requestTrust('http://www.mywebsite.com')"
|
||||
@token_required(scopes=['esi-location.read_location.v1', 'esi-location.read_ship_type.v1', 'esi-universe.read_structures.v1'])
|
||||
def click_fatlink_view(request, token, hash, fatname):
|
||||
try:
|
||||
fatlink = Fatlink.objects.filter(hash=hash)[0]
|
||||
|
||||
if 'HTTP_EVE_TRUSTED' in request.META and request.META['HTTP_EVE_TRUSTED'] == "Yes":
|
||||
# Retrieve the latest fatlink using the hash.
|
||||
try:
|
||||
fatlink = Fatlink.objects.filter(hash=hash)[0]
|
||||
if (timezone.now() - fatlink.fatdatetime) < datetime.timedelta(seconds=(fatlink.duration * 60)):
|
||||
|
||||
if (timezone.now() - fatlink.fatdatetime) < datetime.timedelta(seconds=(fatlink.duration * 60)):
|
||||
character = EveManager.get_character_by_id(token.character_id)
|
||||
|
||||
character = EveManager.get_character_by_id(request.META['HTTP_EVE_CHARID'])
|
||||
|
||||
if character:
|
||||
fat = Fat()
|
||||
fat.system = request.META['HTTP_EVE_SOLARSYSTEMNAME']
|
||||
if 'HTTP_EVE_STATIONNAME' in request.META:
|
||||
fat.station = request.META['HTTP_EVE_STATIONNAME']
|
||||
else:
|
||||
fat.station = "No Station"
|
||||
fat.shiptype = request.META['HTTP_EVE_SHIPTYPENAME']
|
||||
fat.fatlink = fatlink
|
||||
fat.character = character
|
||||
fat.user = character.user
|
||||
try:
|
||||
fat.full_clean()
|
||||
fat.save()
|
||||
context = {'trusted': True, 'registered': True}
|
||||
except ValidationError as e:
|
||||
messages = []
|
||||
for errorname, message in e.message_dict.items():
|
||||
messages.append(message[0].decode())
|
||||
context = {'trusted': True, 'errormessages': messages}
|
||||
if character:
|
||||
# get data
|
||||
c = token.get_esi_client()
|
||||
location = c.Location.get_characters_character_id_location(character_id=token.character_id).result()
|
||||
ship = c.Location.get_characters_character_id_ship(character_id=token.character_id).result()
|
||||
location['solar_system_name'] = c.Universe.get_universe_systems_system_id(system_id=location['solar_system_id']).result()['solar_system_name']
|
||||
if location['structure_id']:
|
||||
location['station_name'] = c.Universe.get_universe_structures_structure_id(structure_id=location['structure_id']).result()['name']
|
||||
elif location['station_id']:
|
||||
location['station_name'] = c.Universe.get_universe_stations_station_id(station_id=location['station_id']).result()['station_name']
|
||||
else:
|
||||
context = {'character_id': request.META['HTTP_EVE_CHARID'],
|
||||
'character_name': request.META['HTTP_EVE_CHARNAME']}
|
||||
return render(request, 'public/characternotexisting.html', context=context)
|
||||
location['station_name'] = "No Station"
|
||||
ship['ship_type_name'] = c.Universe.get_universe_types_type_id(type_id=ship['ship_type_id']).result()['type_name']
|
||||
|
||||
fat = Fat()
|
||||
fat.system = location['solar_system_name']
|
||||
fat.station = location['station_name']
|
||||
fat.shiptype = ship['ship_type_name']
|
||||
fat.fatlink = fatlink
|
||||
fat.character = character
|
||||
fat.user = character.user
|
||||
try:
|
||||
fat.full_clean()
|
||||
fat.save()
|
||||
messages.success(request, 'Fleet participation registered.')
|
||||
except ValidationError as e:
|
||||
err_messages = []
|
||||
for errorname, message in e.message_dict.items():
|
||||
err_messages.append(message[0].decode())
|
||||
messages.error(request, ' '.join(err_messages))
|
||||
else:
|
||||
context = {'trusted': True, 'expired': True}
|
||||
except ObjectDoesNotExist:
|
||||
context = {'trusted': True}
|
||||
else:
|
||||
context = {'trusted': False, 'fatname': fatname}
|
||||
return render(request, 'public/clickfatlinkview.html', context=context)
|
||||
context = {'character_id': token.character_id,
|
||||
'character_name': token.character_name}
|
||||
return render(request, 'fleetactivitytracking/characternotexisting.html', context=context)
|
||||
else:
|
||||
messages.error(request, 'FAT link has expired.')
|
||||
except (ObjectDoesNotExist, KeyError):
|
||||
messages.error(request, 'Invalid FAT link.')
|
||||
return redirect('auth_fatlink_view')
|
||||
|
||||
|
||||
@login_required
|
||||
@ -250,7 +267,7 @@ def create_fatlink_view(request):
|
||||
for errorname, message in e.message_dict.items():
|
||||
messages.append(message[0].decode())
|
||||
context = {'form': form, 'errormessages': messages}
|
||||
return render(request, 'registered/fatlinkformatter.html', context=context)
|
||||
return render(request, 'fleetactivitytracking/fatlinkformatter.html', context=context)
|
||||
else:
|
||||
form = FatlinkForm()
|
||||
context = {'form': form, 'badrequest': True}
|
||||
@ -263,7 +280,7 @@ def create_fatlink_view(request):
|
||||
|
||||
context = {'form': form}
|
||||
|
||||
return render(request, 'registered/fatlinkformatter.html', context=context)
|
||||
return render(request, 'fleetactivitytracking/fatlinkformatter.html', context=context)
|
||||
|
||||
|
||||
@login_required
|
||||
@ -271,24 +288,26 @@ def create_fatlink_view(request):
|
||||
def modify_fatlink_view(request, hash=""):
|
||||
logger.debug("modify_fatlink_view called by user %s" % request.user)
|
||||
if not hash:
|
||||
return redirect('/fat/')
|
||||
return redirect('auth_fatlink_view')
|
||||
|
||||
fatlink = Fatlink.objects.filter(hash=hash)[0]
|
||||
|
||||
if request.GET.get('removechar'):
|
||||
if request.GET.get('removechar', None):
|
||||
character_id = request.GET.get('removechar')
|
||||
character = EveCharacter.objects.get(character_id=character_id)
|
||||
logger.debug("Removing character %s from fleetactivitytracking %s" % (character.character_name, fatlink.name))
|
||||
|
||||
Fat.objects.filter(fatlink=fatlink).filter(character=character).delete()
|
||||
|
||||
if request.GET.get('deletefat'):
|
||||
if request.GET.get('deletefat', None):
|
||||
logger.debug("Removing fleetactivitytracking %s" % fatlink.name)
|
||||
fatlink.delete()
|
||||
return redirect('/fat/')
|
||||
return redirect('auth_fatlink_view')
|
||||
|
||||
registered_fats = Fat.objects.filter(fatlink=fatlink).order_by('character')
|
||||
registered_fats = Fat.objects.filter(fatlink=fatlink).order_by('character__character_name')
|
||||
|
||||
context = {'fatlink': fatlink, 'registered_fats': registered_fats}
|
||||
fat_page = get_page(registered_fats, request.GET.get('page', 1))
|
||||
|
||||
return render(request, 'registered/fatlinkmodify.html', context=context)
|
||||
context = {'fatlink': fatlink, 'registered_fats': fat_page}
|
||||
|
||||
return render(request, 'fleetactivitytracking/fatlinkmodify.html', context=context)
|
||||
|
@ -15,6 +15,7 @@ redis
|
||||
django>=1.10,<2.0
|
||||
django-bootstrap-form
|
||||
django-navhelper
|
||||
django-bootstrap-pagination
|
||||
|
||||
# awating release for fix to celery/django-celery#447
|
||||
# django-celery
|
||||
@ -23,4 +24,4 @@ git+https://github.com/celery/django-celery
|
||||
git+git://github.com/nikdoof/python-ts3.git
|
||||
git+https://github.com/pyghassen/openfire-restapi
|
||||
|
||||
git+https://github.com/adarnof/adarnauth-eve-sso
|
||||
git+https://github.com/adarnof/adarnauth-esi
|
||||
|
@ -319,7 +319,6 @@ class EveApiManager:
|
||||
def validate_api(api_id, api_key, user):
|
||||
try:
|
||||
info = EveApiManager.get_api_info(api_id, api_key).result
|
||||
chars = EveApiManager.get_characters_from_api(api_id, api_key).result
|
||||
except evelink.api.APIError as e:
|
||||
if int(e.code) == 222:
|
||||
raise EveApiManager.ApiInvalidError(api_id)
|
||||
@ -329,6 +328,7 @@ class EveApiManager:
|
||||
auth, c = AuthServicesInfo.objects.get_or_create(user=user)
|
||||
states = [auth.state]
|
||||
from authentication.tasks import determine_membership_by_character # circular import issue
|
||||
chars = info['characters']
|
||||
for char in chars:
|
||||
evechar = EveCharacter()
|
||||
evechar.character_name = chars[char]['name']
|
||||
|
@ -1,25 +0,0 @@
|
||||
from __future__ import unicode_literals
|
||||
import requests
|
||||
import json
|
||||
|
||||
|
||||
class EveWhoManager:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@staticmethod
|
||||
def get_corporation_members(corpid):
|
||||
url = "http://evewho.com/api.php?type=corplist&id=%s" % corpid
|
||||
jsondata = requests.get(url).content
|
||||
data = json.loads(jsondata.decode())
|
||||
|
||||
members = {}
|
||||
page_count = 0
|
||||
while len(data["characters"]):
|
||||
for row in data["characters"]:
|
||||
members[int(row["character_id"])] = {"name": row["name"], "id": int(row["character_id"])}
|
||||
page_count += 1
|
||||
jsondata = requests.get(url + "&page=%i" % page_count).content
|
||||
data = json.loads(jsondata.decode())
|
||||
|
||||
return members
|
@ -12,7 +12,7 @@
|
||||
<meta name="description" content="">
|
||||
<meta name="author" content="">
|
||||
|
||||
<title>{% block title %}Empty title{% endblock title %}</title>
|
||||
<title>{% block title %}Alliance Auth{% endblock title %}</title>
|
||||
|
||||
<!-- Bootstrap Core CSS -->
|
||||
<link href="{% static 'css/bootstrap.min.css' %}" rel="stylesheet">
|
||||
@ -153,9 +153,9 @@
|
||||
</li>
|
||||
{% endif %}
|
||||
|
||||
{% if perms.auth.corp_apis or perms.auth.alliance_apis %}
|
||||
{% if perms.corputils.view_corp_corpstats or perms.corputils.view_alliance_corpstats or perms.corputils.view_blue_corpstats %}
|
||||
<li>
|
||||
<a class="{% navactive request 'auth_corputils auth_corputils_search auth_corputils_corp_view auth_corputils_month' %}" href="{% url 'auth_corputils' %}">
|
||||
<a class="{% navactive request 'corputils:view corputils:search' %}" href="{% url 'corputils:view' %}">
|
||||
<i class="fa fa-share-alt fa-fw grayiconecolor"></i>{% trans " Corporation Stats" %}
|
||||
</a>
|
||||
</li>
|
||||
|
@ -1,90 +0,0 @@
|
||||
{% load staticfiles %}
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="description" content="">
|
||||
<meta name="author" content="">
|
||||
|
||||
<title>Fleet participation</title>
|
||||
|
||||
<!-- Bootstrap Core CSS -->
|
||||
<link href="{% static 'css/bootstrap.min.css' %}" rel="stylesheet">
|
||||
<!-- Custom Fonts -->
|
||||
<link href="{% static 'css/font-awesome.min.css' %}" rel="stylesheet" type="text/css">
|
||||
<link href="{% static 'css/sb-admin-2.css' %}" rel="stylesheet">
|
||||
{% block extra_css %}{% endblock extra_css %}
|
||||
<style>
|
||||
.grayiconecolor {
|
||||
color: #505050;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body onload=CCPEVE.requestTrust('{{ DOMAIN }}')>
|
||||
<div id="wrapper">
|
||||
<!-- Navigation -->
|
||||
|
||||
<nav class="navbar navbar-inverse navbar-static-top" role="navigation">
|
||||
|
||||
<div class="navbar-header ">
|
||||
<a class="navbar-brand " href="/dashboard/">
|
||||
<div class="fa fa-cog fa-spin"></div>
|
||||
{% if IS_CORP %}
|
||||
{{ CORP_NAME }}
|
||||
{% else %}
|
||||
{{ ALLIANCE_NAME }}
|
||||
{% endif %}
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- /.navbar-header -->
|
||||
|
||||
<ul class="nav navbar-top-links navbar-right">
|
||||
{% if user.is_authenticated %}
|
||||
<li><a href="{% url 'auth_logout_user' %}">Logout</a></li>
|
||||
{% else %}
|
||||
<li><a href="{% url 'auth_login_user' %}">Login</a></li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
<!-- /.navbar-static-side -->
|
||||
</nav>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div class="col-lg-12">
|
||||
<h1 class="page-header text-center">Character not found!</h1>
|
||||
<div class="col-lg-12 container" id="example">
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">{{ character_name }}</div>
|
||||
<div class="panel-body">
|
||||
<div class="col-lg-2 col-sm-2">
|
||||
<img class="ra-avatar img-responsive" src="https://image.eveonline.com/Character/{{ character_id }}_128.jpg">
|
||||
</div>
|
||||
<div class="col-lg-10 col-sm-2">
|
||||
<div class="alert alert-danger" role="alert">Character not registered!</div>
|
||||
This character is not part of any registered API-key. You must go to <a href=" {% url 'auth_api_key_management' %}">API key management</a> and add an API with the character on before being able to click fleet attendance links.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
<script src="{% static 'js/jquery.min.js' %}"></script>
|
||||
<script src="{% static 'js/jquery.datetimepicker.js' %}"></script>
|
||||
<script src="{% static 'js/bootstrap.min.js' %}"></script>
|
||||
</body>
|
||||
</html>
|
@ -1,96 +0,0 @@
|
||||
{% load staticfiles %}
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="description" content="">
|
||||
<meta name="author" content="">
|
||||
|
||||
<title>Fleet participation</title>
|
||||
|
||||
<!-- Bootstrap Core CSS -->
|
||||
<link href="{% static 'css/bootstrap.min.css' %}" rel="stylesheet">
|
||||
<!-- Custom Fonts -->
|
||||
<link href="{% static 'css/font-awesome.min.css' %}" rel="stylesheet" type="text/css">
|
||||
<link href="{% static 'css/sb-admin-2.css' %}" rel="stylesheet">
|
||||
{% block extra_css %}{% endblock extra_css %}
|
||||
<style>
|
||||
.grayiconecolor {
|
||||
color: #505050;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body onload=CCPEVE.requestTrust('{{ DOMAIN }}')>
|
||||
<div id="wrapper">
|
||||
<!-- Navigation -->
|
||||
|
||||
<nav class="navbar navbar-inverse navbar-static-top" role="navigation">
|
||||
|
||||
<div class="navbar-header ">
|
||||
<a class="navbar-brand " href="/dashboard/">
|
||||
<div class="fa fa-cog fa-spin"></div>
|
||||
{% if IS_CORP %}
|
||||
{{ CORP_NAME }}
|
||||
{% else %}
|
||||
{{ ALLIANCE_NAME }}
|
||||
{% endif %}
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- /.navbar-header -->
|
||||
|
||||
<ul class="nav navbar-top-links navbar-right">
|
||||
{% if user.is_authenticated %}
|
||||
<li><a href="{% url 'auth_logout_user' %}">Logout</a></li>
|
||||
{% else %}
|
||||
<li><a href="{% url 'auth_login_user' %}">Login</a></li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
<!-- /.navbar-static-side -->
|
||||
</nav>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div class="col-lg-12">
|
||||
{% if registered %}<h1 class="page-header text-center">Fleet registered!</h1> {% elif expired%}<h1 class="page-header text-center">This link has expired.</h1> {% elif errormessages%}<h1 class="page-header text-center">Something horrible happened. Shoot your FC!</h1>{% else %}<h1 class="page-header text-center">Invalid link.</h1>{% endif %}
|
||||
<div class="col-lg-12 container" id="example">
|
||||
{% for message in errormessages %}
|
||||
<div class="alert alert-danger" role="alert">{{ message }}</div>
|
||||
{% endfor %}
|
||||
{% if trusted %}
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">Fleet stats</div>
|
||||
<div class="panel-body">
|
||||
<div class="col-lg-2 col-sm-2">
|
||||
<img class="ra-avatar img-responsive" src="https://image.eveonline.com/{% if IS_CORP %}Corporation/{{ CORPORATION_ID }}{% else %}Alliance/{{ ALLIANCE_ID }}{% endif %}_128.png">
|
||||
</div>
|
||||
<div class="col-lg-7 col-sm-2">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% else %}
|
||||
<div class="alert alert-danger" role="alert">This page requires trust to operate.</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
<script src="{% static 'js/jquery.min.js' %}"></script>
|
||||
<script src="{% static 'js/jquery.datetimepicker.js' %}"></script>
|
||||
<script src="{% static 'js/bootstrap.min.js' %}"></script>
|
||||
</body>
|
||||
</html>
|
@ -1,229 +0,0 @@
|
||||
{% extends "public/base.html" %}
|
||||
{% load bootstrap %}
|
||||
{% load staticfiles %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block title %}Alliance Auth{% endblock %}
|
||||
{% block page_title %}{% trans "Corporation Member Tracking" %}{% endblock page_title %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<div class="col-lg-12">
|
||||
<h1 class="page-header text-center">{% trans "Corporation Member Data" %}</h1>
|
||||
<div class="col-lg-12 container" id="example">
|
||||
{% if corp %}
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">{% trans "Corporation" %}</div>
|
||||
<div class="panel-body">
|
||||
<div class="col-lg-5 col-sm-2">
|
||||
<img class="ra-avatar img-responsive" src="https://image.eveonline.com/Corporation/{{ corp.corporation_id }}_128.png">
|
||||
</div>
|
||||
<div class="col-lg-7 col-sm-2">
|
||||
<h4 class="">{{ corp.corporation_name }}</h4>
|
||||
|
||||
<p>{% trans "Ticker:" %} {{ corp.corporation_ticker }}</p>
|
||||
|
||||
<p>{% trans "Member count:" %} {{ corp.member_count }}</p>
|
||||
|
||||
<p>{% trans "Player count:" %} {{characters_with_api|length}}</p>
|
||||
|
||||
<p>{% trans "Unregistered characters:" %} {{characters_without_api|length|add:n_unacounted}}</p>
|
||||
</div>
|
||||
<div class="col-lg-12 col-sm-5">
|
||||
<b>{% trans "API Index:" %}</b>
|
||||
<div class="progress">
|
||||
<div class="progress-bar progress-bar-striped" role="progressbar" aria-valuenow="{{ n_registered }}" aria-valuemin="0" aria-valuemax="{{ corp.member_count }}" style="width: {% widthratio characters_with_api|length corp.member_count 100 %}%;">
|
||||
{{n_registered}}/{{ corp.member_count }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<nav class="navbar navbar-default">
|
||||
<div class="container-fluid">
|
||||
<ul class="nav navbar-nav navbar-wide">
|
||||
{% if membercorplist and perms.auth.alliance_apis %}
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">{% trans "Alliance corporations" %} <span class="caret"></span></a>
|
||||
<ul class="dropdown-menu scrollable">
|
||||
{% for membercorpid, membercorpname in membercorplist %}
|
||||
<li>
|
||||
<a href="{% url 'auth_corputils_corp_view' membercorpid %}">{{ membercorpname }}</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</li>
|
||||
{% endif %}
|
||||
<li style="float: right">
|
||||
<p class="navbar-form">
|
||||
Statistics for:
|
||||
<a href="{% url 'auth_corputils_month' corp.corporation_id previous_month|date:"Y" previous_month|date:"m" %}">
|
||||
<i class="fa fa-arrow-circle-left fa-fw grayiconecolor"></i>
|
||||
</a>
|
||||
{{ this_month|date:"M" }}, {{ this_month|date:"Y" }}
|
||||
{% if next_month %}
|
||||
<a href="{% url 'auth_corputils_month' corp.corporation_id next_month|date:"Y" next_month|date:"m" %}" >
|
||||
<i class="fa fa-arrow-circle-right fa-fw grayiconecolor"></i>
|
||||
</a>
|
||||
<a href="{% url 'auth_corputils' %}" >
|
||||
<i class="fa fa-angle-double-right fa-fw grayiconecolor"></i>
|
||||
</a>
|
||||
{% endif %}
|
||||
</p>
|
||||
</li>
|
||||
<li style="float: right">
|
||||
<p class="navbar-btn">
|
||||
<a href="https://zkillboard.com/corporation/{{ corp.corporation_id }}/" class="btn btn-default" target="_blank">{{ corp.corporation_name }} {% trans "Killboard" %}</a>
|
||||
</p>
|
||||
</li>
|
||||
<li style="float: right">
|
||||
<form class="navbar-form navbar-left" role="search" action={% url 'auth_corputils_search' %}{{ corp.corporation_id }}/ method="POST">
|
||||
<div class="form-group">
|
||||
{% csrf_token %}
|
||||
{{ search_form.as_table }}
|
||||
</div>
|
||||
<button class="btn btn-default" type="submit">{% trans "Search" %}</button>
|
||||
</form>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
<ul class="nav nav-tabs">
|
||||
<li class="active"><a data-toggle="tab" href="#gotapi">{% blocktrans %}Registered Main Characters{% endblocktrans %} <b>({{characters_with_api|length}})</b></a></li>
|
||||
<li><a data-toggle="tab" href="#noapi">{% blocktrans %}Characters without API{% endblocktrans %} <b>({{characters_without_api|length|add:n_unacounted}})</b></a></li>
|
||||
</ul>
|
||||
<div class="tab-content">
|
||||
<div id="gotapi" class="tab-pane fade in active">
|
||||
{% if characters_with_api %}
|
||||
<div class="panel-body">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-condensed table-hover table-striped">
|
||||
<tr>
|
||||
<th class="col-md-1"></th>
|
||||
<th class="col-md-2">{% trans "Main character" %}</th>
|
||||
<th class="col-md-2">{% trans "Main corporation" %}</th>
|
||||
<th class="col-md-2">{% trans "Character list" %}</th>
|
||||
<th class="col-md-1">{% trans "Fats" %}</th>
|
||||
{% if perms.auth.fleetactivitytracking_statistics %}
|
||||
<th class="col-md-3">{% trans "Killboard" %}</th>
|
||||
<th class="col-md-2">{% trans "Fleet statistics" %}</th>
|
||||
{% else %}
|
||||
<th class="col-md-3">{% trans "Killboard" %}</th>
|
||||
{% endif %}
|
||||
<th class="col-md-2">{% trans "API JackKnife" %}</th>
|
||||
</tr>
|
||||
{% for maincharname, player in characters_with_api %}
|
||||
<tr >
|
||||
<td>
|
||||
<img src="http://image.eveonline.com/Character/{{ player.main.character_id }}_32.jpg" class="img-circle">
|
||||
</td>
|
||||
<td>
|
||||
<p>{{ maincharname }}</p>
|
||||
</td>
|
||||
<td>
|
||||
{% if not corp.corporation_name == player.maincorp%}
|
||||
<span class="label label-danger">
|
||||
{{ player.maincorp }}
|
||||
</span>
|
||||
{% else %}
|
||||
<span class="label label-success">
|
||||
{{ player.maincorp }}
|
||||
</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{% for char in player.altlist %}
|
||||
<p>{{ char.character_name }}</p>
|
||||
{% endfor %}
|
||||
</td>
|
||||
<td>
|
||||
{{ player.n_fats }}
|
||||
</td>
|
||||
<td>
|
||||
{% for char in player.altlist %}
|
||||
<p><a href="https://zkillboard.com/character/{{ char.character_id }}/" class="label label-danger" target="_blank">{% trans "Killboard" %}</a></p>
|
||||
{% endfor %}
|
||||
</td>
|
||||
{% if perms.auth.fleetactivitytracking %}
|
||||
<td>
|
||||
<a href="{% url 'auth_fatlink_view_user_statistics_month' player.main.character_id this_month|date:"Y" this_month|date:"m" %}">
|
||||
<button type="button" class="btn btn-primary">Statistics
|
||||
</button>
|
||||
</a>
|
||||
</td>
|
||||
{% endif %}
|
||||
<td>
|
||||
{% for apiinfo in player.apilist %}
|
||||
<p>
|
||||
<a href="{{ JACK_KNIFE_URL }}?usid={{ apiinfo.api_id }}&apik={{ apiinfo.api_key }}" target="_blank" class="btn btn-primary">
|
||||
{% trans "API JackKnife" %}
|
||||
</a>
|
||||
</p>
|
||||
{% endfor %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="alert alert-danger" role="alert">
|
||||
<h3>{% blocktrans %}Seems there are no characters in {{ corp.corporation_name }} tied to a registered API!{% endblocktrans %}</h3>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div id="noapi" class="tab-pane fade">
|
||||
{% if characters_without_api %}
|
||||
<div class="panel-body">
|
||||
<div class="table-responsive">
|
||||
{% if 0 < n_unacounted %}
|
||||
<div class="alert alert-danger" role="alert">
|
||||
<h3>{% blocktrans %}There are atleast {{ n_unacounted }} characters not accounted for in EveWho.{% endblocktrans %}</h3>
|
||||
</div>
|
||||
{% endif %}
|
||||
<table class="table table-condensed table-hover table-striped">
|
||||
<tr>
|
||||
<th class="col-md-1"></th>
|
||||
<th class="col-md-2">{% trans "Character" %}</th>
|
||||
<th class="col-md-5">{% trans "Killboard" %}</th>
|
||||
</tr>
|
||||
{% for character_name, character_id in characters_without_api %}
|
||||
<tr>
|
||||
<td>
|
||||
<img src="http://image.eveonline.com/Character/{{ character_id }}_32.jpg" class="img-circle">
|
||||
</td>
|
||||
<td>
|
||||
<p>{{ character_name }}</p>
|
||||
</td>
|
||||
<td>
|
||||
<a href="https://zkillboard.com/character/{{ character_id }}/" class="label label-danger" target="_blank">{% trans "Killboard" %}</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="alert alert-success" role="alert">
|
||||
<h3>{% blocktrans %}Good job! Every character in {{ corp.corporation_name }} seem to be tied to an API!{% endblocktrans %}</h3>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="container-fluid">
|
||||
<div class="col-md-4 col-md-offset-4">
|
||||
<div class="row">
|
||||
<div class="alert alert-danger text-center" role="alert">{% trans "No corporation model found. Contact your admin." %}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock content %}
|
@ -1,93 +0,0 @@
|
||||
{% extends "public/base.html" %}
|
||||
{% load bootstrap %}
|
||||
{% load staticfiles %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block title %}Alliance Auth{% endblock %}
|
||||
|
||||
{% block page_title %}{% trans "Corporation Member Tracking" %}{% endblock page_title %}
|
||||
{% block extra_css %}{% endblock extra_css %}
|
||||
|
||||
{% block content %}
|
||||
<div class="col-lg-12">
|
||||
<h1 class="page-header text-center">{% trans "Member Search Results" %}</h1>
|
||||
<h2 class="text-center"><a href="{% url 'auth_corputils_corp_view' corp.corporation_id %}">{{ corp.corporation_name }}</a></h2>
|
||||
<div class="container-fluid">
|
||||
|
||||
<div class="panel panel-default">
|
||||
<nav class="navbar navbar-default">
|
||||
<div class="container-fluid">
|
||||
<ul class="nav navbar-nav navbar-wide">
|
||||
<li style="float: right">
|
||||
<form class="navbar-form navbar-right" role="search" action="{% url 'auth_corputils_search_corp' corp.corporation_id %}" method="POST">
|
||||
<div class="form-group">
|
||||
{% csrf_token %}
|
||||
{{ search_form|bootstrap }}
|
||||
</div>
|
||||
<button class="btn btn-default" type="submit">{% trans "Search" %}</button>
|
||||
</form>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
<div class="panel-body">
|
||||
<table class="table table-condensed table-hover table-striped">
|
||||
<tr>
|
||||
<th class="col-md-1"></th>
|
||||
<th class="col-md-2">{% trans "Character" %}</th>
|
||||
<th class="col-md-2">{% trans "Main character" %}</th>
|
||||
{% if perms.auth.fleetactivitytracking%}
|
||||
<th class="col-md-5">{% trans "Killboard" %}</th>
|
||||
<th class="col-md-2">{% trans "Fleet statistics" %}</th>
|
||||
{% else %}
|
||||
<th class="col-md-5">{% trans "Killboard" %}</th>
|
||||
{% endif %}
|
||||
<th class="col-md-2">{% trans "API JackKnife" %}</th>
|
||||
</tr>
|
||||
{% for result in results %}
|
||||
<tr >
|
||||
<td>
|
||||
<img src="http://image.eveonline.com/Character/{{ result.id }}_32.jpg" class="img-circle">
|
||||
</td>
|
||||
<td>{{ result.name }}</td>
|
||||
<td>
|
||||
{% if result.api_registered%}
|
||||
{{ result.main.character_name }}
|
||||
{% else %}
|
||||
<span class="label label-danger">{% trans "No API registered!" %}</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
<p><a href="https://zkillboard.com/character/{{ result.char.character_id }}/" class="label label-danger" target="_blank">{% trans "Killboard" %}</a></p>
|
||||
</td>
|
||||
|
||||
{% if perms.auth.fleetactivitytracking %}
|
||||
{% if result.main %}
|
||||
<td>
|
||||
<a href="{% url 'auth_fatlink_view_user_statistics_month' result.main.character_id year month%}">
|
||||
<button type="button" class="btn btn-primary">Statistics
|
||||
</button>
|
||||
</a>
|
||||
</td>
|
||||
{% else %}
|
||||
<td></td>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
<td>
|
||||
{% if result.api_registered %}
|
||||
<a href="{{ JACK_KNIFE_URL }}?usid={{ result.apiinfo.api_id }}&apik={{ result.apiinfo.api_key }}"
|
||||
target="_blank">
|
||||
<button type="button" class="btn btn-primary">{% trans "API JackKnife" %}
|
||||
</button>
|
||||
</a>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock content %}
|
@ -1,55 +0,0 @@
|
||||
{% extends "public/base.html" %}
|
||||
{% load bootstrap %}
|
||||
{% load staticfiles %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block title %}Alliance Auth{% endblock %}
|
||||
{% block page_title %}{% trans "Fatlink view" %}{% endblock page_title %}
|
||||
|
||||
{% block content %}
|
||||
<div class="col-lg-12">
|
||||
<h1 class="page-header text-center">{% blocktrans %}Edit fatlink "{{ fatlink.name }}"{% endblocktrans %}
|
||||
<div class="text-right">
|
||||
<form>
|
||||
<button type="submit" onclick="return confirm('Are you sure?')" class="btn btn-danger" name="deletefat" value="True">
|
||||
{% trans "Delete fat" %}
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</h1>
|
||||
<h4><b>{% trans "Registered characters" %}</b></h4>
|
||||
<table class="table table-responsive table-bordered">
|
||||
<tr>
|
||||
<th class="text-center">{% trans "User" %}</th>
|
||||
<th class="text-center">{% trans "Character" %}</th>
|
||||
<th class="text-center">{% trans "System" %}</th>
|
||||
<th class="text-center">{% trans "Ship" %}</th>
|
||||
<th class="text-center">{% trans "Eve Time" %}</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
{% for fat in registered_fats %}
|
||||
<tr>
|
||||
<td class="text-center">{{ fat.user }}</td>
|
||||
<td class="text-center">{{ fat.character.character_name }}</td>
|
||||
{% if fat.station != "No Station" %}
|
||||
<td class="text-center">Docked in {{ fat.system }}</td>
|
||||
{% else %}
|
||||
<td class="text-center">{{ fat.system }}</td>
|
||||
{% endif %}
|
||||
<td class="text-center">{{ fat.shiptype }}</td>
|
||||
<td class="text-center">{{ fat.fatlink.fatdatetime }}</td>
|
||||
<td class="text-center">
|
||||
<form>
|
||||
<button type="submit" class="btn btn-warning" name="removechar" value="{{ fat.character.character_id }}"><span
|
||||
class="glyphicon glyphicon-remove"></span></button>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
</div>
|
||||
|
||||
|
||||
<script src="/static/js/dateformat.js"></script>
|
||||
|
||||
{% endblock content %}
|
Loading…
x
Reference in New Issue
Block a user