Adding "Paplink" feature (#401)

* Initial testing of paplink functionality. More fancy interfaces coming.

* Removed a invalid view reference.

* Added a link on the front page.

* Fixed some bad references and incorrect in game browser header usages.

* Started work on statistics-pages.

* Added an initial modify-paplink page where the pap itself can be deleted and characters removed.

* Added a very simple statistics page. Also some name change for ~reasons~.

* Small but crucial fix of syntax.

* Added personal statistics page.

* Corputils page now include fatlinkstats.

* Added link to the personal statistics page. Moved other buttons for clarity.

* Removed some unused code and imports

* Added more statistics, and all corps in alliance are now visible even if no paps are registered.

* Now requesting trust for the right domain. And some redundant imports and commented lines are removed.
This commit is contained in:
Joakim Strandberg 2016-04-30 01:00:45 +02:00 committed by Mr McClain
parent 1abeba5658
commit b190b8e191
19 changed files with 874 additions and 7 deletions

View File

@ -61,6 +61,7 @@ INSTALLED_APPS = (
'sigtracker', 'sigtracker',
'optimer', 'optimer',
'corputils', 'corputils',
'fleetactivitytracking',
'notifications', 'notifications',
) )
@ -560,6 +561,10 @@ LOGGING = {
'handlers': ['log_file', 'console', 'notifications'], 'handlers': ['log_file', 'console', 'notifications'],
'level': 'DEBUG', 'level': 'DEBUG',
}, },
'fleetactivitytracking': {
'handlers': ['log_file', 'console'],
'level': 'ERROR',
},
'util': { 'util': {
'handlers': ['log_file', 'console', 'notifications'], 'handlers': ['log_file', 'console', 'notifications'],
'level': 'DEBUG', 'level': 'DEBUG',

View File

@ -206,6 +206,7 @@ urlpatterns = patterns('',
#corputils #corputils
url(r'^corputils/$', 'corputils.views.corp_member_view', name='auth_corputils'), url(r'^corputils/$', 'corputils.views.corp_member_view', name='auth_corputils'),
url(r'^corputils/(?P<corpid>[0-9]+)/$', 'corputils.views.corp_member_view'), url(r'^corputils/(?P<corpid>[0-9]+)/$', 'corputils.views.corp_member_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/$', 'corputils.views.corputils_search', name="auth_corputils_search"),
url(r'^corputils/search/(?P<corpid>[0-9]+)/$', 'corputils.views.corputils_search'), url(r'^corputils/search/(?P<corpid>[0-9]+)/$', 'corputils.views.corputils_search'),
@ -235,4 +236,18 @@ urlpatterns = patterns('',
url(r'^notifications/$', 'notifications.views.notification_list', name='auth_notification_list'), url(r'^notifications/$', 'notifications.views.notification_list', name='auth_notification_list'),
url(r'^notifications/(\w+)/$', 'notifications.views.notification_view', name='auth_notification_view'), url(r'^notifications/(\w+)/$', 'notifications.views.notification_view', name='auth_notification_view'),
url(r'^remove_notifications/(\w+)/$', 'notifications.views.remove_notification', name='auth_remove_notification'), url(r'^remove_notifications/(\w+)/$', 'notifications.views.remove_notification', name='auth_remove_notification'),
)
# FleetActivityTracking (FAT)
url(r'^fat/$', 'fleetactivitytracking.views.fatlink_view', name='auth_fatlink_view'),
url(r'^fat/statistics/$', 'fleetactivitytracking.views.fatlink_statistics_view', name='auth_fatlink_view_statistics'),
url(r'^fat/statistics/(?P<year>[0-9]+)/(?P<month>[0-9]+)/$', 'fleetactivitytracking.views.fatlink_statistics_view', name='auth_fatlink_view_statistics_month'),
url(r'^fat/user/statistics/$', 'fleetactivitytracking.views.fatlink_personal_statistics_view'),
url(r'^fat/user/statistics/(?P<year>[0-9]+)/$', 'fleetactivitytracking.views.fatlink_personal_statistics_view', name='auth_fatlink_view_personal_statistics'),
url(r'^fat/create/$', 'fleetactivitytracking.views.create_fatlink_view', name='auth_create_fatlink_view'),
url(r'^fat/modify/$', 'fleetactivitytracking.views.modify_fatlink_view', name='auth_modify_fatlink_view'),
url(r'^fat/modify/(?P<hash>[a-zA-Z0-9_-]+)/([a-z0-9_-]+)$',
'fleetactivitytracking.views.modify_fatlink_view'),
url(r'^fat/link/$', 'fleetactivitytracking.views.fatlink_view', name='auth_click_fatlink_view'),
url(r'^fat/link/(?P<hash>[a-zA-Z0-9]+)/(?P<fatname>[a-z0-9_-]+)/$',
'fleetactivitytracking.views.click_fatlink_view'),
)

View File

@ -2,7 +2,6 @@ from django.conf import settings
from django.shortcuts import render_to_response from django.shortcuts import render_to_response
from django.template import RequestContext from django.template import RequestContext
from django.contrib.auth.decorators import login_required from django.contrib.auth.decorators import login_required
from django.contrib.auth.decorators import permission_required
from django.shortcuts import HttpResponseRedirect from django.shortcuts import HttpResponseRedirect
from collections import namedtuple from collections import namedtuple
@ -14,17 +13,45 @@ from eveonline.models import EveCorporationInfo
from eveonline.models import EveAllianceInfo from eveonline.models import EveAllianceInfo
from eveonline.models import EveCharacter from eveonline.models import EveCharacter
from eveonline.models import EveApiKeyPair from eveonline.models import EveApiKeyPair
from authentication.models import AuthServicesInfo from fleetactivitytracking.models import Fat
from util import check_if_user_has_permission from util import check_if_user_has_permission
from forms import CorputilsSearchForm from forms import CorputilsSearchForm
from evelink.api import APIError from evelink.api import APIError
import logging import logging
import datetime
logger = logging.getLogger(__name__) 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)
@login_required @login_required
def corp_member_view(request, corpid = None): 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) logger.debug("corp_member_view called by user %s" % request.user)
try: try:
@ -58,7 +85,6 @@ def corp_member_view(request, corpid = None):
corpid = membercorplist[0][0] corpid = membercorplist[0][0]
corp = EveCorporationInfo.objects.get(corporation_id=corpid) corp = EveCorporationInfo.objects.get(corporation_id=corpid)
Player = namedtuple("Player", ["main", "maincorp", "maincorpid", "altlist", "apilist"])
if check_if_user_has_permission(request.user, 'alliance_apis') or (check_if_user_has_permission(request.user, 'corp_apis') and (user_corp_id == corpid)): if check_if_user_has_permission(request.user, 'alliance_apis') or (check_if_user_has_permission(request.user, 'corp_apis') and (user_corp_id == corpid)):
logger.debug("Retreiving and sending API-information") logger.debug("Retreiving and sending API-information")
@ -96,10 +122,12 @@ def corp_member_view(request, corpid = None):
api_pair = None api_pair = None
num_registered_characters = num_registered_characters + 1 num_registered_characters = num_registered_characters + 1
characters_with_api.setdefault(mainname, Player(main=mainchar, characters_with_api.setdefault(mainname, Player(main=mainchar,
user=char_owner,
maincorp=maincorp, maincorp=maincorp,
maincorpid=maincorpid, maincorpid=maincorpid,
altlist=[], altlist=[],
apilist=[]) apilist=[],
n_fats=0)
).altlist.append(char) ).altlist.append(char)
if api_pair: if api_pair:
characters_with_api[mainname].apilist.append(api_pair) characters_with_api[mainname].apilist.append(api_pair)
@ -127,16 +155,26 @@ def corp_member_view(request, corpid = None):
api_pair = None api_pair = None
num_registered_characters = num_registered_characters + 1 num_registered_characters = num_registered_characters + 1
characters_with_api.setdefault(mainname, Player(main=mainchar, characters_with_api.setdefault(mainname, Player(main=mainchar,
user=char_owner,
maincorp=maincorp, maincorp=maincorp,
maincorpid=maincorpid, maincorpid=maincorpid,
altlist=[], altlist=[],
apilist=[]) apilist=[],
n_fats=0)
).altlist.append(char) ).altlist.append(char)
if api_pair: if api_pair:
characters_with_api[mainname].apilist.append(api_pair) characters_with_api[mainname].apilist.append(api_pair)
n_unacounted = corp.member_count - (num_registered_characters + len(characters_without_api)) 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: if not settings.IS_CORP:
context = {"membercorplist": membercorplist, context = {"membercorplist": membercorplist,
"corp": corp, "corp": corp,
@ -154,6 +192,10 @@ def corp_member_view(request, corpid = None):
"characters_without_api": sorted(characters_without_api.items()), "characters_without_api": sorted(characters_without_api.items()),
"search_form": CorputilsSearchForm()} "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_to_response('registered/corputils.html',context, context_instance=RequestContext(request) ) return render_to_response('registered/corputils.html',context, context_instance=RequestContext(request) )
return HttpResponseRedirect("/dashboard/") return HttpResponseRedirect("/dashboard/")

View File

View File

@ -0,0 +1,6 @@
from django.contrib import admin
from models import Fatlink, Fat
admin.site.register(Fatlink)
admin.site.register(Fat)

View File

@ -0,0 +1,16 @@
from django import forms
from optimer.models import optimer
def get_fleet_list():
fleets = optimer.objects.all()
fleetlist = [("None", "None")]
for fleet in fleets:
fleetlist.append((fleet.operation_name, fleet.operation_name))
fleetlist.sort()
return fleetlist
class FatlinkForm(forms.Form):
fatname = forms.CharField(label='Name of fat-link', required=True)
duration = forms.IntegerField(label="Duration of fat-link", required=True, initial=30, min_value=1, max_value=2147483647)
fleet = forms.ChoiceField(label="Fleet", choices=get_fleet_list())

View File

@ -0,0 +1,37 @@
from django.db import models
from django.contrib.auth.models import User
from optimer.models import optimer
from eveonline.models import EveCharacter
from datetime import datetime
from datetime import date
from django.utils import timezone
def get_sentinel_user():
return User.objects.get_or_create(username='deleted')[0]
class Fatlink(models.Model):
fatdatetime = models.DateTimeField(default=timezone.now())
duration = models.PositiveIntegerField()
fleet = models.CharField(max_length=254, default="")
name = models.CharField(max_length=254)
hash = models.CharField(max_length=254, unique=True)
creator = models.ForeignKey(User, on_delete=models.SET(get_sentinel_user))
def __str__(self):
return self.name
class Fat(models.Model):
character = models.ForeignKey(EveCharacter, on_delete=models.CASCADE)
fatlink = models.ForeignKey(Fatlink)
system = models.CharField(max_length=30)
shiptype = models.CharField(max_length=30)
station = models.CharField(max_length=125)
user = models.ForeignKey(User)
class Meta:
unique_together = (('character', 'fatlink'),)
def __str__(self):
output = "Fat-link for %s" % self.character.character_name
return output.encode('utf-8')

View File

@ -0,0 +1,254 @@
from django.conf import settings
from django.shortcuts import HttpResponseRedirect
from django.shortcuts import render_to_response
from django.core.exceptions import ObjectDoesNotExist
from django.contrib.auth.decorators import login_required
from django.contrib.auth.decorators import permission_required
from django.template import RequestContext
from django.core.exceptions import ValidationError
from django.utils import timezone
from eveonline.models import EveCharacter
from eveonline.models import EveCorporationInfo
from eveonline.managers import EveManager
from util import check_if_user_has_permission
from forms import FatlinkForm
from models import Fatlink, Fat
from slugify import slugify
from collections import OrderedDict
import string
import random
import datetime
import logging
logger = logging.getLogger(__name__)
class CorpStat(object):
def __init__(self, corp_id, corp=None, blue=False):
if corp:
self.corp = corp
else:
self.corp = EveCorporationInfo.objects.get(corporation_id=corp_id)
self.n_fats = 0
self.blue = blue
def avg_fat(self):
return "%.2f" % (float(self.n_fats)/float(self.corp.member_count))
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)
@login_required
def fatlink_view(request):
# Will show the last 5 or so fatlinks clicked by user.
# If the user has the right privileges the site will also show the latest fatlinks with the options to add VIPs and
# manually add players.
user = request.user
logger.debug("fatlink_view called by user %s" % request.user)
latest_fats = Fat.objects.filter(user=user).order_by('-id')[:5]
if check_if_user_has_permission(user, 'fleetactivitytracking'):
latest_links = Fatlink.objects.all().order_by('-id')[:5]
context = {'user':user, 'fats': latest_fats, 'fatlinks': latest_links}
else:
context = {'user':user, 'fats': latest_fats}
return render_to_response('registered/fatlinkview.html', context, context_instance=RequestContext(request))
@login_required
@permission_required('auth.fleetactivitytracking_statistics')
def fatlink_statistics_view(request, 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)
fatStats = OrderedDict()
if settings.IS_CORP:
fatStats[settings.CORP_NAME] = CorpStat(settings.CORP_ID)
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)
fatlinks_in_span = Fatlink.objects.filter(fatdatetime__gte = start_of_month).filter(fatdatetime__lt = start_of_next_month)
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
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)
if datetime.datetime.now() > start_of_next_month:
context = {'fatStats':fatStatsList, '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, 'previous_month': start_of_previous_month}
return render_to_response('registered/fatlinkstatisticsview.html', context, context_instance=RequestContext(request))
@login_required
def fatlink_personal_statistics_view(request, year=datetime.date.today().year):
year = int(year)
user = request.user
logger.debug("fatlink_personal_statistics_view called by user %s" % request.user)
personal_fats = Fat.objects.filter(user=user).order_by('id')
monthlystats = {datetime.date(year, month, 1).strftime("%h"):0 for month in range(1,13)}
for fat in personal_fats:
fatdate = fat.fatlink.fatdatetime
if fatdate.year == year:
monthlystats[fatdate.strftime("%h")] += 1
if datetime.datetime.now() > datetime.datetime(year+1, 1, 1):
context = {'user':user, 'monthlystats': monthlystats, 'year':year, 'previous_year':year-1, 'next_year':year+1}
else:
context = {'user':user, 'monthlystats': monthlystats, 'year':year, 'previous_year':year-1}
return render_to_response('registered/fatlinkpersonalstatisticsview.html', context, context_instance=RequestContext(request))
@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')"
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]
valid = True
if (timezone.now() - fatlink.fatdatetime) < datetime.timedelta(seconds=(fatlink.duration*60)):
active = True
character = EveManager.get_character_by_id(request.META['HTTP_EVE_CHARID'])
if character:
fat = Fat()
fat.system = request.META['HTTP_EVE_SOLARSYSTEMNAME']
fat.station = request.META['HTTP_EVE_STATIONNAME']
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}
else:
context = {'character_id': request.META['HTTP_EVE_CHARID'], 'character_name': request.META['HTTP_EVE_CHARNAME']}
return render_to_response('public/characternotexisting.html', context, context_instance=RequestContext(request))
else:
context = {'trusted': True, 'expired': True}
except ObjectDoesNotExist:
context = {'trusted': True}
else:
context = {'trusted': False, 'fatname': fatname}
return render_to_response('public/clickfatlinkview.html', context, context_instance=RequestContext(request))
@login_required
@permission_required('auth.fleetactivitytracking')
def create_fatlink_view(request):
logger.debug("create_fatlink_view called by user %s" % request.user)
if request.method == 'POST':
logger.debug("Post request to create_fatlink_view by user %s" % request.user)
form = FatlinkForm(request.POST)
if 'submit_fat' in request.POST:
logger.debug("Submitting fleetactivitytracking by user %s" % request.user)
if form.is_valid():
fatlink = Fatlink()
fatlink.name = slugify(form.cleaned_data["fatname"])
fatlink.fleet = form.cleaned_data["fleet"]
fatlink.duration = form.cleaned_data["duration"]
fatlink.creator = request.user
fatlink.hash = ''.join(random.choice(string.ascii_letters+string.digits) for i in range(10))
try:
fatlink.full_clean()
fatlink.save()
except ValidationError as e:
form = FatlinkForm()
messages = []
for errorname, message in e.message_dict.items():
messages.append(message[0].decode())
context = {'form': form, 'errormessages': messages}
return render_to_response('registered/fatlinkformatter.html', context, context_instance=RequestContext(request))
else:
form = FatlinkForm()
context = {'form': form, 'badrequest': True}
return render_to_response('registered/fatlinkformatter.html', context, context_instance=RequestContext(request))
return HttpResponseRedirect('/fat/')
else:
form = FatlinkForm()
logger.debug("Returning empty form to user %s" % request.user)
context = {'form': form}
return render_to_response('registered/fatlinkformatter.html', context, context_instance=RequestContext(request))
@login_required
@permission_required('auth.fleetactivitytracking')
def modify_fatlink_view(request, hash=""):
logger.debug("modify_fatlink_view called by user %s" % request.user)
if not hash:
return HttpResponseRedirect('/fat/')
fatlink = Fatlink.objects.filter(hash=hash)[0]
if(request.GET.get('removechar')):
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')):
logger.debug("Removing fleetactivitytracking %s" % fatlink.name)
fatlink.delete()
return HttpResponseRedirect('/fat/')
registered_fats = Fat.objects.filter(fatlink=fatlink).order_by('character')
context = {'fatlink':fatlink, 'registered_fats':registered_fats}
return render_to_response('registered/fatlinkmodify.html', context, context_instance=RequestContext(request))

View File

@ -7,6 +7,7 @@ passlib
requests>=2.9.1 requests>=2.9.1
bcrypt bcrypt
zeroc-ice zeroc-ice
slugify
# Django Stuff # # Django Stuff #
django==1.6.5 django==1.6.5

View File

@ -176,6 +176,12 @@
</li> </li>
{% endif %} {% endif %}
<li>
<a {% ifequal request.path "/fat/" %} class="active" {% endifequal %}
href="{% url 'auth_fatlink_view' %}"><i
class="fa fa-users fa-lightbulb-o grayiconecolor"></i> Fleet Activity Tracking</a>
</li>
<li> <li>
<a {% ifequal request.path "/srp/" %} class="active" {% endifequal %} <a {% ifequal request.path "/srp/" %} class="active" {% endifequal %}
href="{% url 'auth_srp_management_view' %}"><i href="{% url 'auth_srp_management_view' %}"><i

View File

@ -0,0 +1,90 @@
{% 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>

View File

@ -0,0 +1,96 @@
{% 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 unhappened occured.</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>

View File

@ -57,6 +57,23 @@
</ul> </ul>
</li> </li>
{% endif %} {% 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"> <li style="float: right">
<p class="navbar-btn"> <p class="navbar-btn">
<a href="https://zkillboard.com/corporation/{{ corp.corporation_id }}/" class="btn btn-default" target="_blank">{{ corp.corporation_name }} Killboard</a> <a href="https://zkillboard.com/corporation/{{ corp.corporation_id }}/" class="btn btn-default" target="_blank">{{ corp.corporation_name }} Killboard</a>
@ -89,6 +106,7 @@
<th class="col-md-2">Main character</th> <th class="col-md-2">Main character</th>
<th class="col-md-2">Main corporation</th> <th class="col-md-2">Main corporation</th>
<th class="col-md-2">Character list</th> <th class="col-md-2">Character list</th>
<th class="col-md-1">Fats</th>
<th class="col-md-3">Killboard</th> <th class="col-md-3">Killboard</th>
<th class="col-md-2">API JackKnife</th> <th class="col-md-2">API JackKnife</th>
</tr> </tr>
@ -116,6 +134,9 @@
<p>{{ char.character_name }}</p> <p>{{ char.character_name }}</p>
{% endfor %} {% endfor %}
</td> </td>
<td>
{{ player.n_fats }}
</td>
<td> <td>
{% for char in player.altlist %} {% for char in player.altlist %}
<p><a href="https://zkillboard.com/character/{{ char.character_id }}/" class="label label-danger" target="_blank">Killboard</a></p> <p><a href="https://zkillboard.com/character/{{ char.character_id }}/" class="label label-danger" target="_blank">Killboard</a></p>

View File

@ -0,0 +1,36 @@
{% extends "public/base.html" %}
{% load bootstrap %}
{% load staticfiles %}
{% block title %}Alliance Auth - Fatlink Create{% endblock %}
{% block page_title %}Create Fatlink{% endblock page_title %}
{% block extra_css %}
<link href="{% static 'css/jquery.datetimepicker.css' %}" rel="stylesheet" type="text/css">{% endblock extra_css %}
{% block content %}
<div class="col-lg-12">
<h1 class="page-header text-center">Create Fleet Operation</h1>
<div class="container-fluid">
{% if badrequest %}
<div class="alert alert-danger" role="alert">Bad request!</div>
{% endif %}
{% for message in errormessages %}
<div class="alert alert-danger" role="alert">{{ message }}</div>
{% endfor %}
<div class="col-md-4 col-md-offset-4">
<div class="row">
<form class="form-signin" role="form" action="" method="POST">
{% csrf_token %}
{{ form|bootstrap }}
<br/>
<button class="btn btn-lg btn-primary btn-block" type="submit" name="submit_fat">Create fatlink</button>
</form>
</div>
</div>
</div>
</div>
{% endblock content %}

View File

@ -0,0 +1,54 @@
{% extends "public/base.html" %}
{% load bootstrap %}
{% load staticfiles %}
{% block title %}Alliance Auth{% endblock %}
{% block page_title %}Fatlink view{% endblock page_title %}
{% block content %}
<div class="col-lg-12">
<h1 class="page-header text-center">Edit fatlink "{{ fatlink.name }}"
<div class="text-right">
<form>
<button type="submit" onclick="return confirm('Are you sure?')" class="btn btn-danger" name="deletefat" value="True">
Delete fat
</button>
</form>
</div>
</h1>
<h4><b>Registered characters</b></h4>
<table class="table table-responsive table-bordered">
<tr>
<th class="text-center">User</th>
<th class="text-center">Character</th>
<th class="text-center">System</th>
<th class="text-center">Ship</th>
<th class="text-center">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 != "None" %}
<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 %}

View File

@ -0,0 +1,39 @@
{% extends "public/base.html" %}
{% load bootstrap %}
{% load staticfiles %}
{% block title %}Alliance Auth{% endblock %}
{% block page_title %}Personal fatlink statistics{% endblock page_title %}
{% block content %}
<div class="col-lg-12">
<h1 class="page-header text-center">Participation data statistics for {{ year }}
<div class="text-right">
<a href="{% url 'auth_fatlink_view_personal_statistics' previous_year %}">
<button type="button" class="btn btn-info">Previous year</button>
</a>
{% if next_year %}
<a href="{% url 'auth_fatlink_view_personal_statistics' next_year %}">
<button type="button" class="btn btn-info">Next year</button>
</a>
{% endif %}
</div>
</h1>
<table class="table table-responsive table-bordered">
<tr>
<th class="col-md-2 text-center">Month</th>
<th class="col-md-2 text-center">Fats</th>
</tr>
{% for month, n_fats in monthlystats.items %}
<tr>
<td class="text-center">{{ month }}</td>
<td class="text-center">{{ n_fats }}</td>
</tr>
{% endfor %}
</table>
</div>
<script src="/static/js/dateformat.js"></script>
{% endblock content %}

View File

@ -0,0 +1,49 @@
{% extends "public/base.html" %}
{% load bootstrap %}
{% load staticfiles %}
{% block title %}Alliance Auth{% endblock %}
{% block page_title %}Fatlink statistics{% endblock page_title %}
{% block content %}
<div class="col-lg-12">
<h1 class="page-header text-center">Participation data statistics for {{ month }}, {{ year }}
<div class="text-right">
<a href="{% url 'auth_fatlink_view_statistics_month' previous_month|date:"Y" previous_month|date:"m" %}">
<button type="button" class="btn btn-info">Previous month</button>
</a>
{% if next_month %}
<a href="{% url 'auth_fatlink_view_statistics_month' next_month|date:"Y" next_month|date:"m" %}">
<button type="button" class="btn btn-info">Next month</button>
</a>
{% endif %}
</div>
</h1>
<table class="table table-responsive table-bordered">
<tr>
<th class="col-md-1"></th>
<th class="col-md-2 text-center">Ticker</th>
<th class="col-md-5 text-center">Corp</th>
<th class="col-md-2 text-center">Members</th>
<th class="col-md-2 text-center">Fats</th>
<th class="col-md-2 text-center">Average fats</th>
</tr>
{% for corpStat in fatStats %}
<tr>
<td>
<img src="https://image.eveonline.com/Corporation/{{ corpStat.corp.corporation_id }}_32.png" class="ra-avatar img-responsive">
</td>
<td class="text-center">[{{ corpStat.corp.corporation_ticker }}]</td>
<td class="text-center">{{ corpStat.corp.corporation_name }}</td>
<td class="text-center">{{ corpStat.corp.member_count }}</td>
<td class="text-center">{{ corpStat.n_fats }}</td>
<td class="text-center">{{ corpStat.avg_fat }}</td>
</tr>
{% endfor %}
</table>
</div>
<script src="/static/js/dateformat.js"></script>
{% endblock content %}

View File

@ -0,0 +1,98 @@
{% extends "public/base.html" %}
{% load bootstrap %}
{% load staticfiles %}
{% block title %}Alliance Auth{% endblock %}
{% block page_title %}Fatlink view{% endblock page_title %}
{% block content %}
<div class="col-lg-12">
<h1 class="page-header text-center">Participation data</h1>
<table class="table">
<tr>
<th class="col-md-11">
<h4><b>Most recent clicked fatlinks</b>
</h4>
</th>
<th class="col-md-1">
<a href="{% url 'auth_fatlink_view_statistics' %}">
<button type="button" class="btn btn-info">Personal statistics</button>
</a>
</th>
</tr>
</table>
<table class="table table-responsive table-bordered">
<tr>
<th class="text-center">fatname</th>
<th class="text-center">Character</th>
<th class="text-center">System</th>
<th class="text-center">Ship</th>
<th class="text-center">Eve Time</th>
</tr>
{% for fat in fats %}
<tr>
<td class="text-center">{{ fat.fatlink.name }}</td>
<td class="text-center">{{ fat.character.character_name }}</td>
{% if fat.station != "None" %}
<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>
</tr>
{% endfor %}
</table>
{% if perms.auth.fleetactivitytracking%}
<table class="table">
<tr>
<th class="col-md-10">
<h4><b>Most recent fatlinks</b>
</h4>
</th>
<th class="col-md-1">
<a href="{% url 'auth_fatlink_view_statistics' %}">
<button type="button" class="btn btn-info">View statistics</button>
</a>
</th>
<th class="col-md-1">
<a href="{% url 'auth_create_fatlink_view' %}">
<button type="button" class="btn btn-success">Create fatlink</button>
</a>
</th>
</tr>
</table>
<table class="table table-bordered">
<tr>
<th class="text-center">Name</th>
<th class="text-center">Creator</th>
<th class="text-center">Fleet</th>
<th class="text-center">Eve Time</th>
<th class="text-center">Duration</th>
<th class="text-center">Edit</th>
</tr>
{% for link in fatlinks %}
<tr>
<td class="text-center"><a href="{% url 'auth_click_fatlink_view' %}{{ link.hash }}/{{ link.name }}">{{ link.name }}</a></td>
<td class="text-center">{{ link.creator.username }}</td>
<td class="text-center">{{ link.fleet }}</td>
<td class="text-center">{{ link.fatdatetime }}</td>
<td class="text-center">{{ link.duration }}</td>
<td class="text-center">
<a href="{% url 'auth_modify_fatlink_view' %}{{ link.hash }}/{{ link.name }}">
<button type="button" class="btn btn-info"><span
class="glyphicon glyphicon-edit"></span></button>
</a>
</td>
</tr>
{% endfor %}
</table>
{% endif %}
</div>
<script src="/static/js/dateformat.js"></script>
{% endblock content %}

View File

@ -16,6 +16,8 @@ def bootstrap_permissions():
Permission.objects.get_or_create(codename="group_management", content_type=ct, name="group_management") Permission.objects.get_or_create(codename="group_management", content_type=ct, name="group_management")
Permission.objects.get_or_create(codename="jabber_broadcast", content_type=ct, name="jabber_broadcast") Permission.objects.get_or_create(codename="jabber_broadcast", content_type=ct, name="jabber_broadcast")
Permission.objects.get_or_create(codename="jabber_broadcast_all", content_type=ct, name="jabber_broadcast_all") Permission.objects.get_or_create(codename="jabber_broadcast_all", content_type=ct, name="jabber_broadcast_all")
Permission.objects.get_or_create(codename="fleetactivitytracking", content_type=ct, name="fleetactivitytracking")
Permission.objects.get_or_create(codename="fleetactivitytracking_statistics", content_type=ct, name="fleetactivitytracking_statistics")
Permission.objects.get_or_create(codename="human_resources", content_type=ct, name="human_resources") Permission.objects.get_or_create(codename="human_resources", content_type=ct, name="human_resources")
Permission.objects.get_or_create(codename="blue_member", content_type=ct, name="blue_member") Permission.objects.get_or_create(codename="blue_member", content_type=ct, name="blue_member")
Permission.objects.get_or_create(codename="alliance_apis", content_type=ct, name="alliance_apis") Permission.objects.get_or_create(codename="alliance_apis", content_type=ct, name="alliance_apis")