Restructure Alliance Auth package (#867)

* Refactor allianceauth into its own package

* Add setup

* Add missing default_app_config declarations

* Fix timerboard namespacing

* Remove obsolete future imports

* Remove py2 mock support

* Remove six

* Add experimental 3.7 support and multiple Dj versions

* Remove python_2_unicode_compatible

* Add navhelper as local package

* Update requirements
This commit is contained in:
Basraah
2017-09-19 09:46:40 +10:00
committed by GitHub
parent d10580b56b
commit 786859294d
538 changed files with 1197 additions and 1523 deletions

View File

@@ -0,0 +1 @@
default_app_config = 'allianceauth.fleetactivitytracking.apps.FatConfig'

View File

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

View File

@@ -0,0 +1,7 @@
from django.apps import AppConfig
class FatConfig(AppConfig):
name = 'allianceauth.fleetactivitytracking'
label = 'fleetactivitytracking'

View File

@@ -0,0 +1,15 @@
from . import urls
from allianceauth import hooks
from allianceauth.services.hooks import MenuItemHook, UrlHook
@hooks.register('menu_item_hook')
def register_menu():
return MenuItemHook('Fleet Activity Tracking', 'fa fa-users fa-lightbulb-o fa-fw grayiconecolor', 'fatlink:view',
navactive=['fatlink:'])
@hooks.register('url_hook')
def register_url():
return UrlHook(urls, 'fatlink', r'^fat/')

View File

@@ -0,0 +1,12 @@
from django import forms
from django.utils.translation import ugettext_lazy as _
from allianceauth.optimer.models import OpTimer
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.ModelChoiceField(label=_("Fleet"), queryset=OpTimer.objects.all().order_by('operation_name'))

View File

@@ -0,0 +1,62 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10.1 on 2016-09-05 21:39
from __future__ import unicode_literals
import datetime
import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
from django.utils.timezone import utc
import allianceauth.fleetactivitytracking.models
class Migration(migrations.Migration):
initial = True
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('eveonline', '0001_initial'),
]
operations = [
migrations.CreateModel(
name='Fat',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('system', models.CharField(max_length=30)),
('shiptype', models.CharField(max_length=30)),
('station', models.CharField(max_length=125)),
('character', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='eveonline.EveCharacter')),
],
),
migrations.CreateModel(
name='Fatlink',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('fatdatetime', models.DateTimeField(default=datetime.datetime(2016, 9, 5, 21, 39, 17, 307954, tzinfo=utc))),
('duration', models.PositiveIntegerField()),
('fleet', models.CharField(default=b'', max_length=254)),
('name', models.CharField(max_length=254)),
('hash', models.CharField(max_length=254, unique=True)),
('creator', models.ForeignKey(on_delete=models.SET(
allianceauth.fleetactivitytracking.models.get_sentinel_user), to=settings.AUTH_USER_MODEL)),
],
),
migrations.AddField(
model_name='fat',
name='fatlink',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='fleetactivitytracking.Fatlink'),
),
migrations.AddField(
model_name='fat',
name='user',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL),
),
migrations.AlterUniqueTogether(
name='fat',
unique_together=set([('character', 'fatlink')]),
),
]

View File

@@ -0,0 +1,22 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10.1 on 2016-09-05 22:20
from __future__ import unicode_literals
import datetime
from django.db import migrations, models
from django.utils.timezone import utc
class Migration(migrations.Migration):
dependencies = [
('fleetactivitytracking', '0001_initial'),
]
operations = [
migrations.AlterField(
model_name='fatlink',
name='fatdatetime',
field=models.DateTimeField(default=datetime.datetime(2016, 9, 5, 22, 20, 2, 999041, tzinfo=utc)),
),
]

View File

@@ -0,0 +1,21 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10.1 on 2016-09-06 23:54
from __future__ import unicode_literals
from django.db import migrations, models
import django.utils.timezone
class Migration(migrations.Migration):
dependencies = [
('fleetactivitytracking', '0002_auto_20160905_2220'),
]
operations = [
migrations.AlterField(
model_name='fatlink',
name='fatdatetime',
field=models.DateTimeField(default=django.utils.timezone.now),
),
]

View File

@@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10.5 on 2017-03-22 23:35
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('fleetactivitytracking', '0003_auto_20160906_2354'),
]
operations = [
migrations.AlterField(
model_name='fatlink',
name='fleet',
field=models.CharField(default='', max_length=254),
),
]

View File

@@ -0,0 +1,36 @@
from django.contrib.auth.models import User
from django.db import models
from django.utils import timezone
from allianceauth.eveonline.models import EveCharacter
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):
return "Fat-link for %s" % self.character.character_name

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,28 @@
{% extends 'registered/base.html' %}
{% load i18n %}
{% block title %}Fleet Participation{% endblock %}
{% block page_title %}{% trans "Fleet Participation" %}{% endblock %}
{% block content %}
<div class="col-lg-12">
<h1 class="page-header text-center">{% trans "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">{% trans "Character not registered!" %}</div>
{% trans "This character is not part of any registered API-key. You must go to" %} <a href=" {% url 'auth_api_key_management' %}">{% trans "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 %}

View File

@@ -0,0 +1,35 @@
{% extends "registered/base.html" %}
{% load bootstrap %}
{% load staticfiles %}
{% load i18n %}
{% block title %}Alliance Auth - Fatlink Create{% endblock %}
{% block page_title %}{% trans "Create Fatlink" %}{% endblock page_title %}
{% block content %}
<div class="col-lg-12">
<h1 class="page-header text-center">{% trans "Create Fleet Operation" %}</h1>
<div class="container-fluid">
{% if badrequest %}
<div class="alert alert-danger" role="alert">{% trans "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">{% trans "Create fatlink" %}</button>
</form>
</div>
</div>
</div>
</div>
{% endblock content %}

View File

@@ -0,0 +1,59 @@
{% extends "registered/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">{% trans "Edit fatlink" %} "{{ fatlink }}"
<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">{% blocktrans %}Docked in {% endblocktrans %}{{ 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>
{% endblock content %}

View File

@@ -0,0 +1,64 @@
{% extends "registered/base.html" %}
{% load bootstrap %}
{% load staticfiles %}
{% load i18n %}
{% block title %}Alliance Auth{% endblock %}
{% block page_title %}{% trans "Personal fatlink statistics" %}{% endblock page_title %}
{% block content %}
<div class="col-lg-12">
<h1 class="page-header text-center">{% blocktrans %}Participation data statistics for {{ month }}, {{ year }}{% endblocktrans %}
{% if char_id %}
<div class="text-right">
<a href="{% url 'fatlink:user_statistics_month' char_id previous_month|date:"Y" previous_month|date:"m" %}" class="btn btn-info">{% trans "Previous month" %}</a>
<a href="{% url 'fatlink:user_statistics_month' char_id next_month|date:"Y" next_month|date:"m" %}" class="btn btn-info">{% trans "Next month" %}</a>
</div>
{% endif %}
</h1>
<h2>{% blocktrans %}{{ user }} has collected {{ n_fats }} links this month.{% endblocktrans %}</h2>
<table class="table table-responsive">
<tr>
<th class="col-md-2 text-center">{% trans "Ship" %}</th>
<th class="col-md-2 text-center">{% trans "Times used" %}</th>
</tr>
{% for ship, n_fats in shipStats %}
<tr>
<td class="text-center">{{ ship }}</td>
<td class="text-center">{{ n_fats }}</td>
</tr>
{% endfor %}
</table>
{% if created_fats %}
<h2>{% blocktrans %}{{ user }} has created {{ n_created_fats }} links this month.{% endblocktrans %}</h2>
{% if created_fats %}
<table class="table">
<tr>
<th class="text-center">{% trans "Name" %}</th>
<th class="text-center">{% trans "Creator" %}</th>
<th class="text-center">{% trans "Fleet" %}</th>
<th class="text-center">{% trans "Eve Time" %}</th>
<th class="text-center">{% trans "Duration" %}</th>
<th class="text-center">{% trans "Edit" %}</th>
</tr>
{% for link in created_fats %}
<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 %}
{% endif %}
</div>
{% endblock content %}

View File

@@ -0,0 +1,38 @@
{% extends "registered/base.html" %}
{% load bootstrap %}
{% load staticfiles %}
{% load i18n %}
{% block title %}Alliance Auth{% endblock %}
{% block page_title %}{% trans "Personal fatlink statistics" %}{% endblock page_title %}
{% block content %}
<div class="col-lg-12">
<h1 class="page-header text-center">{% blocktrans %}Participation data statistics for {{ year }}{% endblocktrans %}
<div class="text-right">
<a href="{% url 'fatlink:personal_statistics_year' previous_year %}" class="btn btn-info">{% trans "Previous year" %}</a>
{% if next_year %}
<a href="{% url 'fatlink:personal_statistics_year' next_year %}" class="btn btn-info">{% trans "Next year" %}</a>
{% endif %}
</div>
</h1>
<div class="col-lg-2 col-lg-offset-5">
<table class="table table-responsive">
<tr>
<th class="col-md-2 text-center">{% trans "Month" %}</th>
<th class="col-md-2 text-center">{% trans "Fats" %}</th>
</tr>
{% for monthnr, month, n_fats in monthlystats %}
<tr>
<td class="text-center">
<a href="{% url 'fatlink:personal_statistics_month' year monthnr %}">
{{ month }}
</a>
</td>
<td class="text-center">{{ n_fats }}</td>
</tr>
{% endfor %}
</table>
</div>
</div>
{% endblock content %}

View File

@@ -0,0 +1,48 @@
{% extends "registered/base.html" %}
{% load bootstrap %}
{% load staticfiles %}
{% load i18n %}
{% block title %}Alliance Auth{% endblock %}
{% block page_title %}{% trans "Fatlink Corp Statistics" %}{% endblock page_title %}
{% block content %}
<div class="col-lg-12">
<h1 class="page-header text-center">{% blocktrans %}Participation data statistics for {{ month }}, {{ year }}{% endblocktrans %}
<div class="text-right">
<a href="{% url 'fatlink:statistics_corp_month' corpid previous_month|date:"Y" previous_month|date:"m" %}" class="btn btn-info">{% trans "Previous month" %}</a>
{% if next_month %}
<a href="{% url 'fatlink:statistics_corp_month' corpid next_month|date:"Y" next_month|date:"m" %}" class="btn btn-info">{% trans "Next month" %}</a>
{% endif %}
</div>
</h1>
{% if fatStats %}
<table class="table table-responsive">
<tr>
<th class="col-md-1"></th>
<th class="col-md-2 text-center">{% trans "Main Character" %}</th>
<th class="col-md-2 text-center">{% trans "Characters" %}</th>
<th class="col-md-2 text-center">{% trans "Fats" %}</th>
<th class="col-md-2 text-center">{% trans "Average fats" %}
<i class="glyphicon glyphicon-question-sign" rel="tooltip" title="Fats ÷ Characters"></i>
</th>
</tr>
{% for memberStat in fatStats %}
<tr>
<td>
<img src="https://image.eveonline.com/Character/{{ memberStat.mainchid }}_32.jpg" class="ra-avatar img-responsive">
</td>
<td class="text-center">{{ memberStat.mainchar.character_name }}</td>
<td class="text-center">{{ memberStat.n_chars }}</td>
<td class="text-center">{{ memberStat.n_fats }}</td>
<td class="text-center">{{ memberStat.avg_fat }}</td>
</tr>
{% endfor %}
</table>
{% endif %}
</div>
{% endblock content %}
{% block extra_script %}
$(document).ready(function(){
$("[rel=tooltip]").tooltip();
{% endblock extra_script %}

View File

@@ -0,0 +1,50 @@
{% extends "registered/base.html" %}
{% load bootstrap %}
{% load staticfiles %}
{% load i18n %}
{% block title %}Alliance Auth{% endblock %}
{% block page_title %}{% trans "Fatlink statistics" %}{% endblock page_title %}
{% block content %}
<div class="col-lg-12">
<h1 class="page-header text-center">{% blocktrans %}Participation data statistics for {{ month }}, {{ year }}{% endblocktrans %}
<div class="text-right">
<a href="{% url 'fatlink:statistics_month' previous_month|date:"Y" previous_month|date:"m" %}" class="btn btn-info">{% trans "Previous month" %}</a>
{% if next_month %}
<a href="{% url 'fatlink:statistics_month' next_month|date:"Y" next_month|date:"m" %}" class="btn btn-info">{% trans "Next month" %}</a>
{% endif %}
</div>
</h1>
{% if fatStats %}
<table class="table table-responsive">
<tr>
<th class="col-md-1"></th>
<th class="col-md-2 text-center">{% trans "Ticker" %}</th>
<th class="col-md-5 text-center">{% trans "Corp" %}</th>
<th class="col-md-2 text-center">{% trans "Members" %}</th>
<th class="col-md-2 text-center">{% trans "Fats" %}</th>
<th class="col-md-2 text-center">{% trans "Average fats" %}
<i class="glyphicon glyphicon-question-sign" rel="tooltip" title="Fats ÷ Characters"></i>
</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"><a href="{% url 'fatlink:statistics_corp' corpStat.corp.corporation_id %}">[{{ 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>
{% endif %}
</div>
{% endblock content %}
{% block extra_script %}
$(document).ready(function(){
$("[rel=tooltip]").tooltip();
{% endblock extra_script %}

View File

@@ -0,0 +1,102 @@
{% extends "registered/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">{% trans "Participation data" %}</h1>
<table class="table">
<tr>
<th class="col-md-11">
<h4><b>{% trans "Most recent clicked fatlinks" %}</b>
</h4>
</th>
<th class="col-md-1">
<a href="{% url 'fatlink:personal_statistics' %}" class="btn btn-info">
{% trans "Personal statistics" %}
</a>
</th>
</tr>
</table>
{% if fats %}
<table class="table table-responsive">
<tr>
<th class="text-center">{% trans "fatname" %}</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>
</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 != "No Station" %}
<td class="text-center">{% blocktrans %}Docked in {% endblocktrans %}{{ 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>
{% else %}
<div class="alert alert-warning text-center">{% trans "No fleet activity on record." %}</div>
{% endif %}
{% if perms.auth.fleetactivitytracking%}
<table class="table">
<tr>
<th class="col-md-10">
<h4><b>{% trans "Most recent fatlinks" %}</b>
</h4>
</th>
<th class="col-md-1">
<a href="{% url 'fatlink:statistics' %}" class="btn btn-info">
{% trans "View statistics" %}
</a>
</th>
<th class="col-md-1">
<a href="{% url 'fatlink:create' %}" class="btn btn-success">
{% trans "Create fatlink" %}
</a>
</th>
</tr>
</table>
{% if fatlinks %}
<table class="table">
<tr>
<th class="text-center">{% trans "Name" %}</th>
<th class="text-center">{% trans "Creator" %}</th>
<th class="text-center">{% trans "Fleet" %}</th>
<th class="text-center">{% trans "Eve Time" %}</th>
<th class="text-center">{% trans "Duration" %}</th>
<th class="text-center">{% trans "Edit" %}</th>
</tr>
{% for link in fatlinks %}
<tr>
<td class="text-center"><a href="{% url 'fatlink:click_fatlink' %}{{ 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 'fatlink:modify' %}{{ link.hash }}/{{ link.name }}" class="btn btn-info">
<span class="glyphicon glyphicon-edit"></span>
</a>
</td>
</tr>
{% endfor %}
</table>
{% else %}
<div class="alert alert-warning text-center">{% trans "No created fatlinks on record." %}</div>
{% endif %}
{% endif %}
</div>
{% endblock content %}

View File

@@ -0,0 +1,33 @@
from django.conf.urls import url
from . import views
urlpatterns = [
# FleetActivityTracking (FAT)
url(r'^$', views.fatlink_view, name='view'),
url(r'^statistics/$', views.fatlink_statistics_view, name='statistics'),
url(r'^statistics/corp/(\w+)$', views.fatlink_statistics_corp_view,
name='statistics_corp'),
url(r'^statistics/corp/(?P<corpid>\w+)/(?P<year>[0-9]+)/(?P<month>[0-9]+)/',
views.fatlink_statistics_corp_view,
name='statistics_corp_month'),
url(r'^statistics/(?P<year>[0-9]+)/(?P<month>[0-9]+)/$', views.fatlink_statistics_view,
name='statistics_month'),
url(r'^user/statistics/$', views.fatlink_personal_statistics_view,
name='personal_statistics'),
url(r'^user/statistics/(?P<year>[0-9]+)/$', views.fatlink_personal_statistics_view,
name='personal_statistics_year'),
url(r'^user/statistics/(?P<year>[0-9]+)/(?P<month>[0-9]+)/$',
views.fatlink_monthly_personal_statistics_view,
name='personal_statistics_month'),
url(r'^user/(?P<char_id>[0-9]+)/statistics/(?P<year>[0-9]+)/(?P<month>[0-9]+)/$',
views.fatlink_monthly_personal_statistics_view,
name='user_statistics_month'),
url(r'^create/$', views.create_fatlink_view, name='create'),
url(r'^modify/$', views.modify_fatlink_view, name='modify'),
url(r'^modify/(?P<hash>[a-zA-Z0-9_-]+)/([a-z0-9_-]+)$',
views.modify_fatlink_view),
url(r'^link/$', views.fatlink_view, name='click_fatlink'),
url(r'^link/(?P<hash>[a-zA-Z0-9]+)/(?P<fatname>[a-z0-9_-]+)/$',
views.click_fatlink_view),
]

View File

@@ -0,0 +1,366 @@
import datetime
import logging
import os
import random
import string
from allianceauth.authentication.models import CharacterOwnership
from django.conf import settings
from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.contrib.auth.decorators import permission_required
from django.contrib.auth.models import User
from django.core.exceptions import ValidationError, ObjectDoesNotExist
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from django.shortcuts import render, redirect, get_object_or_404
from django.utils import timezone
from django.utils.translation import ugettext_lazy as _
from esi.decorators import token_required
from allianceauth.eveonline.managers import EveManager
from .forms import FatlinkForm
from .models import Fatlink, Fat
from slugify import slugify
from allianceauth.eveonline.models import EveAllianceInfo
from allianceauth.eveonline.models import EveCharacter
from allianceauth.eveonline.models import EveCorporationInfo
SWAGGER_SPEC_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'swagger.json')
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:
fats = p.page(1)
except EmptyPage:
fats = p.page(p.num_pages)
return fats
class CorpStat(object):
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 = 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()
def avg_fat(self):
return "%.2f" % (float(self.n_fats) / float(self.corp.member_count))
class MemberStat(object):
def __init__(self, member, start_of_month, start_of_next_month, mainchid=None):
if mainchid:
self.mainchid = mainchid
else:
self.mainchid = member.profile.main_character.character_id if member.profile.main_character else None
self.mainchar = EveCharacter.objects.get(character_id=self.mainchid)
nchars = 0
for alliance in EveAllianceInfo.objects.all():
nchars += EveCharacter.objects.filter(character_ownership__user=member).filter(alliance_id=alliance.alliance_id).count()
self.n_chars = nchars
self.n_fats = Fat.objects.filter(user_id=member.pk).filter(
fatlink__fatdatetime__gte=start_of_month).filter(fatlink__fatdatetime__lte=start_of_next_month).count()
def avg_fat(self):
return "%.2f" % (float(self.n_fats) / float(self.n_chars))
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 user.has_perm('auth.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(request, 'fleetactivitytracking/fatlinkview.html', context=context)
@login_required
@permission_required('auth.fleetactivitytracking_statistics')
def fatlink_statistics_corp_view(request, corpid, year=None, month=None):
if year is None:
year = datetime.date.today().year
if month is None:
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)
fat_stats = {}
corp_members = CharacterOwnership.objects.filter(character__corporation_id=corpid).values('user_id').distinct()
for member in corp_members:
try:
fat_stats[member['user_id']] = MemberStat(User.objects.get(pk=member['user_id']), start_of_month, start_of_next_month)
except ObjectDoesNotExist:
continue
# collect and sort stats
stat_list = [fat_stats[x] for x in fat_stats]
stat_list.sort(key=lambda stat: stat.mainchar.character_name)
stat_list.sort(key=lambda stat: (stat.n_fats, stat.n_fats / stat.n_chars), reverse=True)
context = {'fatStats': stat_list, 'month': start_of_month.strftime("%B"), 'year': year,
'previous_month': start_of_previous_month, 'corpid': corpid}
if datetime.datetime.now() > start_of_next_month:
context.update({'next_month': start_of_next_month})
return render(request, 'fleetactivitytracking/fatlinkstatisticscorpview.html', context=context)
@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)
fat_stats = {}
for corp in EveCorporationInfo.objects.all():
fat_stats[corp.corporation_id] = CorpStat(corp.corporation_id, start_of_month, start_of_next_month)
# get FAT stats for corps without models
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 fat in fats_in_span.exclude(character__corporation_id__in=fat_stats):
if EveCorporationInfo.objects.filter(corporation_id=fat.character.corporation_id).exists():
fat_stats[fat.character.corporation_id] = CorpStat(fat.character.corporation_id, start_of_month,
start_of_next_month)
# 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)
context = {'fatStats': stat_list, 'month': start_of_month.strftime("%B"), 'year': year,
'previous_month': start_of_previous_month}
if datetime.datetime.now() > start_of_next_month:
context.update({'next_month': start_of_next_month})
return render(request, 'fleetactivitytracking/fatlinkstatisticsview.html', context=context)
@login_required
def fatlink_personal_statistics_view(request, year=datetime.date.today().year):
year = int(year)
logger.debug("Personal statistics view for year %i called by %s" % (year, request.user))
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 = [0 for month in range(1, 13)]
for fat in personal_fats:
fatdate = fat.fatlink.fatdatetime
if fatdate.year == year:
monthlystats[fatdate.month - 1] += 1
monthlystats = [(i + 1, datetime.date(year, i + 1, 1).strftime("%h"), monthlystats[i]) for i in range(12)]
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(request, 'fleetactivitytracking/fatlinkpersonalstatisticsview.html', context=context)
@login_required
def fatlink_monthly_personal_statistics_view(request, year, month, char_id=None):
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)
if request.user.has_perm('auth.fleetactivitytracking_statistics') and char_id:
user = EveCharacter.objects.get(character_id=char_id).user
else:
user = request.user
logger.debug("Personal monthly statistics view for user %s called by %s" % (user, request.user))
personal_fats = Fat.objects.filter(user=user).filter(fatlink__fatdatetime__gte=start_of_month).filter(
fatlink__fatdatetime__lt=start_of_next_month)
ship_statistics = dict()
n_fats = 0
for fat in personal_fats:
ship_statistics[fat.shiptype] = ship_statistics.setdefault(fat.shiptype, 0) + 1
n_fats += 1
context = {'user': user, 'shipStats': sorted(ship_statistics.items()), 'month': start_of_month.strftime("%h"),
'year': year, 'n_fats': n_fats, 'char_id': char_id, 'previous_month': start_of_previous_month,
'next_month': start_of_next_month}
created_fats = Fatlink.objects.filter(creator=user).filter(fatdatetime__gte=start_of_month).filter(
fatdatetime__lt=start_of_next_month)
context["created_fats"] = created_fats
context["n_created_fats"] = len(created_fats)
return render(request, 'fleetactivitytracking/fatlinkpersonalmonthlystatisticsview.html', context=context)
@login_required
@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):
fatlink = get_object_or_404(Fatlink, hash=hash, name=fatname)
if (timezone.now() - fatlink.fatdatetime) < datetime.timedelta(seconds=(fatlink.duration * 60)):
character = EveManager.get_character_by_id(token.character_id)
if character:
# get data
c = token.get_esi_client(spec_file=SWAGGER_SPEC_PATH)
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()[
'name']
if location['station_id']:
location['station_name'] = \
c.Universe.get_universe_stations_station_id(station_id=location['station_id']).result()['name']
elif location['structure_id']:
location['station_name'] = \
c.Universe.get_universe_structures_structure_id(structure_id=location['structure_id']).result()[
'name']
else:
location['station_name'] = "No Station"
ship['ship_type_name'] = EveManager.get_itemtype(ship['ship_type_id']).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 = request.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])
messages.error(request, ' '.join(err_messages))
else:
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.'))
return redirect('fatlink:view')
@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.fatdatetime = timezone.now()
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(request, 'fleetactivitytracking/fatlinkformatter.html', context=context)
else:
form = FatlinkForm()
context = {'form': form, 'badrequest': True}
return render(request, 'fleetactivitytracking/fatlinkformatter.html', context=context)
return redirect('fatlink:view')
else:
form = FatlinkForm()
logger.debug("Returning empty form to user %s" % request.user)
context = {'form': form}
return render(request, 'fleetactivitytracking/fatlinkformatter.html', context=context)
@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 redirect('fatlink:view')
fatlink = Fatlink.objects.filter(hash=hash)[0]
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', None):
logger.debug("Removing fleetactivitytracking %s" % fatlink.name)
fatlink.delete()
return redirect('fatlink:view')
registered_fats = Fat.objects.filter(fatlink=fatlink).order_by('character__character_name')
fat_page = get_page(registered_fats, request.GET.get('page', 1))
context = {'fatlink': fatlink, 'registered_fats': fat_page}
return render(request, 'fleetactivitytracking/fatlinkmodify.html', context=context)