mirror of
https://gitlab.com/allianceauth/allianceauth.git
synced 2026-02-04 14:16:21 +01:00
Compare commits
24 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
026b4c272b | ||
|
|
f5cb6a3fb7 | ||
|
|
0b57e027f7 | ||
|
|
3d50f977d9 | ||
|
|
0abb160886 | ||
|
|
ff3bb9743f | ||
|
|
cf81f59fa6 | ||
|
|
d186088a8f | ||
|
|
2106e492e3 | ||
|
|
badc5a1f7f | ||
|
|
cced434a99 | ||
|
|
6c4e8ec2d1 | ||
|
|
5bbaef4476 | ||
|
|
6208071537 | ||
|
|
df02982983 | ||
|
|
eaa9d1930c | ||
|
|
24bc9d4b7f | ||
|
|
73641a7a1e | ||
|
|
485c0fc373 | ||
|
|
55cbbadc2b | ||
|
|
b1dafeda8d | ||
|
|
380069627a | ||
|
|
c3390b089e | ||
|
|
c9d9b0bf07 |
@@ -1,4 +1,4 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
__version__ = '1.14.1'
|
||||
__version__ = '1.14.2'
|
||||
NAME = 'Alliance Auth v%s' % __version__
|
||||
|
||||
@@ -185,6 +185,16 @@ MESSAGE_TAGS = {
|
||||
messages.ERROR: 'danger'
|
||||
}
|
||||
|
||||
CACHES = {
|
||||
"default": {
|
||||
"BACKEND": "django_redis.cache.RedisCache",
|
||||
"LOCATION": "redis://127.0.0.1:6379/1",
|
||||
"OPTIONS": {
|
||||
"CLIENT_CLASS": "django_redis.client.DefaultClient",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#####################################################
|
||||
##
|
||||
## Auth configuration starts here
|
||||
@@ -259,7 +269,6 @@ BLUE_ALLIANCE_GROUPS = 'True' == os.environ.get('AA_BLUE_ALLIANCE_GROUPS', 'Fals
|
||||
# ENABLE_AUTH_IPS4 - Enable IPS4 support in the auth for auth'd members
|
||||
# ENABLE_AUTH_SMF - Enable SMF forum support in the auth for auth'd members
|
||||
# ENABLE_AUTH_MARKET = Enable Alliance Market support in auth for auth'd members
|
||||
# ENABLE_AUTH_PATHFINDER = Enable Alliance Pathfinder suppor in auth for auth'd members
|
||||
# ENABLE_AUTH_XENFORO = Enable XenForo forums support in the auth for auth'd members
|
||||
#########################
|
||||
ENABLE_AUTH_FORUM = 'True' == os.environ.get('AA_ENABLE_AUTH_FORUM', 'False')
|
||||
@@ -286,7 +295,6 @@ ENABLE_AUTH_XENFORO = 'True' == os.environ.get('AA_ENABLE_AUTH_XENFORO', 'False'
|
||||
# ENABLE_BLUE_IPS4 - Enable IPS4 forum support in the auth for blues
|
||||
# ENABLE_BLUE_SMF - Enable SMF forum support in the auth for blues
|
||||
# ENABLE_BLUE_MARKET - Enable Alliance Market in the auth for blues
|
||||
# ENABLE_BLUE_PATHFINDER = Enable Pathfinder support in the auth for blues
|
||||
# ENABLE_BLUE_XENFORO = Enable XenForo forum support in the auth for blue
|
||||
#####################
|
||||
ENABLE_BLUE_FORUM = 'True' == os.environ.get('AA_ENABLE_BLUE_FORUM', 'False')
|
||||
@@ -351,12 +359,14 @@ API_SSO_VALIDATION = 'True' == os.environ.get('AA_API_SSO_VALIDATION', 'False')
|
||||
# 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
|
||||
# EVEONLINE_ITEMTYPE_PROVIDER - Name of default data source for getting eve item type data
|
||||
#
|
||||
# Available soruces are 'esi' and 'xml'
|
||||
# Available sources are 'esi' and 'xml'. Leaving blank results in the default 'esi' being used.
|
||||
#######################
|
||||
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')
|
||||
EVEONLINE_CHARACTER_PROVIDER = os.environ.get('AA_EVEONLINE_CHARACTER_PROVIDER', '')
|
||||
EVEONLINE_CORP_PROVIDER = os.environ.get('AA_EVEONLINE_CORP_PROVIDER', '')
|
||||
EVEONLINE_ALLIANCE_PROVIDER = os.environ.get('AA_EVEONLINE_ALLIANCE_PROVIDER', '')
|
||||
EVEONLINE_ITEMTYPE_PROVIDER = os.environ.get('AA_EVEONLINE_ITEMTYPE_PROVIDER', '')
|
||||
|
||||
#####################
|
||||
# Alliance Market
|
||||
|
||||
@@ -31,4 +31,4 @@ def post_save_user(sender, instance, created, *args, **kwargs):
|
||||
# ensure all users have a model
|
||||
if created:
|
||||
AuthServicesInfo.objects.get_or_create(user=instance)
|
||||
|
||||
|
||||
|
||||
@@ -110,6 +110,8 @@ def set_state(user):
|
||||
auth.state = state
|
||||
auth.save()
|
||||
notify(user, "Membership State Change", message="You membership state has been changed to %s" % state)
|
||||
assign_corp_group(auth)
|
||||
assign_alliance_group(auth)
|
||||
|
||||
|
||||
def assign_corp_group(auth):
|
||||
|
||||
@@ -67,6 +67,7 @@ def register_user_view(request):
|
||||
|
||||
user.save()
|
||||
logger.info("Created new user %s" % user)
|
||||
login(request, user)
|
||||
messages.warning(request, 'Add an API key to set up your account.')
|
||||
return redirect("auth_dashboard")
|
||||
|
||||
@@ -107,7 +108,8 @@ def sso_login(request, token):
|
||||
else:
|
||||
messages.error(request, 'Your account has been disabled.')
|
||||
else:
|
||||
messages.warning(request, 'Authenticated character has no owning account. Please log in with username and password.')
|
||||
messages.warning(request,
|
||||
'Authenticated character has no owning account. Please log in with username and password.')
|
||||
except EveCharacter.DoesNotExist:
|
||||
messages.error(request, 'No account exists with the authenticated character. Please create an account first.')
|
||||
return redirect(login_user)
|
||||
|
||||
@@ -14,6 +14,7 @@ import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class CorpStats(models.Model):
|
||||
token = models.ForeignKey(Token, on_delete=models.CASCADE)
|
||||
@@ -41,35 +42,42 @@ class CorpStats(models.Model):
|
||||
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()
|
||||
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]
|
||||
|
||||
# requesting too many ids per call results in a HTTP400
|
||||
# the swagger spec doesn't have a maxItems count
|
||||
# manual testing says we can do over 350, but let's not risk it
|
||||
member_id_chunks = [member_ids[i:i+255] for i in range(0, len(member_ids), 255)]
|
||||
member_name_chunks = [c.Character.get_characters_names(character_ids=id_chunk).result() for id_chunk in member_id_chunks]
|
||||
member_id_chunks = [member_ids[i:i + 255] for i in range(0, len(member_ids), 255)]
|
||||
member_name_chunks = [c.Character.get_characters_names(character_ids=id_chunk).result() for id_chunk in
|
||||
member_id_chunks]
|
||||
member_list = {}
|
||||
for name_chunk in member_name_chunks:
|
||||
member_list.update({m['character_id']:m['character_name'] for m in name_chunk})
|
||||
member_list.update({m['character_id']: m['character_name'] for m in name_chunk})
|
||||
|
||||
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")
|
||||
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")
|
||||
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")
|
||||
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
|
||||
@@ -95,7 +103,8 @@ class CorpStats(models.Model):
|
||||
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'):
|
||||
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
|
||||
@@ -109,7 +118,6 @@ class CorpStats(models.Model):
|
||||
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):
|
||||
@@ -144,12 +152,12 @@ class CorpStats(models.Model):
|
||||
|
||||
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'))
|
||||
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):
|
||||
|
||||
15
corputils/tasks.py
Normal file
15
corputils/tasks.py
Normal file
@@ -0,0 +1,15 @@
|
||||
from corputils.models import CorpStats
|
||||
from celery.task import task, periodic_task
|
||||
from celery.task.schedules import crontab
|
||||
|
||||
|
||||
@task
|
||||
def update_corpstats(pk):
|
||||
cs = CorpStats.objects.get(pk=pk)
|
||||
cs.update()
|
||||
|
||||
|
||||
@periodic_task(run_every=crontab(minute=0, hour="*/6"))
|
||||
def update_all_corpstats():
|
||||
for cs in CorpStats.objects.all():
|
||||
update_corpstats.delay(cs.pk)
|
||||
@@ -1,7 +1,7 @@
|
||||
from django.conf.urls import url
|
||||
import corputils.views
|
||||
|
||||
app_name='corputils'
|
||||
app_name = 'corputils'
|
||||
urlpatterns = [
|
||||
url(r'^$', corputils.views.corpstats_view, name='view'),
|
||||
url(r'^add/$', corputils.views.corpstats_add, name='add'),
|
||||
|
||||
@@ -10,9 +10,11 @@ from django.conf import settings
|
||||
from eveonline.models import EveCharacter, EveCorporationInfo
|
||||
from corputils.models import CorpStats
|
||||
from esi.decorators import token_required
|
||||
from bravado.exception import HTTPError
|
||||
|
||||
MEMBERS_PER_PAGE = int(getattr(settings, 'CORPSTATS_MEMBERS_PER_PAGE', 20))
|
||||
|
||||
|
||||
def get_page(model_list, page_num):
|
||||
p = Paginator(model_list, MEMBERS_PER_PAGE)
|
||||
try:
|
||||
@@ -23,8 +25,11 @@ def get_page(model_list, page_num):
|
||||
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')
|
||||
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
|
||||
@user_passes_test(access_corpstats_test)
|
||||
@@ -35,11 +40,13 @@ def corpstats_add(request, token):
|
||||
if EveCharacter.objects.filter(character_id=token.character_id).exists():
|
||||
corp_id = EveCharacter.objects.get(character_id=token.character_id).corporation_id
|
||||
else:
|
||||
corp_id = token.get_esi_client().Character.get_characters_character_id(character_id=token.character_id).result()['corporation_id']
|
||||
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
|
||||
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:
|
||||
@@ -50,11 +57,11 @@ def corpstats_add(request, token):
|
||||
messages.error(request, 'Failed to gather corporation statistics with selected token.')
|
||||
return redirect('corputils:view')
|
||||
|
||||
|
||||
@login_required
|
||||
@user_passes_test(access_corpstats_test)
|
||||
def corpstats_view(request, corp_id=None):
|
||||
corpstats = None
|
||||
show_apis = False
|
||||
|
||||
# get requested model
|
||||
if corp_id:
|
||||
@@ -65,7 +72,7 @@ def corpstats_view(request, corp_id=None):
|
||||
available = CorpStats.objects.visible_to(request.user)
|
||||
|
||||
# ensure we can see the requested model
|
||||
if corpstats and not corpstats in available:
|
||||
if corpstats and corpstats not in available:
|
||||
raise PermissionDenied('You do not have permission to view the selected corporation statistics module.')
|
||||
|
||||
# get default model if none requested
|
||||
@@ -84,22 +91,31 @@ def corpstats_view(request, corp_id=None):
|
||||
|
||||
if corpstats:
|
||||
context.update({
|
||||
'corpstats': corpstats.get_view_model(request.user),
|
||||
'members': members,
|
||||
'corpstats': corpstats.get_view_model(request.user),
|
||||
'members': members,
|
||||
})
|
||||
|
||||
return render(request, 'corputils/corpstats.html', context=context)
|
||||
|
||||
|
||||
@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()
|
||||
try:
|
||||
corpstats.update()
|
||||
except HTTPError as e:
|
||||
messages.error(request, str(e))
|
||||
else:
|
||||
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)
|
||||
raise PermissionDenied(
|
||||
'You do not have permission to update member data for the selected corporation statistics module.')
|
||||
if corpstats.pk:
|
||||
return redirect('corputils:view_corp', corp_id=corp.corporation_id)
|
||||
else:
|
||||
return redirect('corputils:view')
|
||||
|
||||
|
||||
@login_required
|
||||
@user_passes_test(access_corpstats_test)
|
||||
@@ -109,9 +125,11 @@ def corpstats_search(request):
|
||||
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()]
|
||||
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))))
|
||||
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)
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
|
||||
AllianceAuth gets served using a Web Server Gateway Interface (WSGI) script. This script passes web requests to AllianceAuth which generates the content to be displayed and returns it. This means very little has to be configured in Apache to host AllianceAuth.
|
||||
|
||||
In the interest of ~~laziness~~ time-efficiency, scroll down for example configs. Use these, changing the ServerName to your domain name.
|
||||
|
||||
### Required Parameters for AllianceAuth Core
|
||||
|
||||
The AllianceAuth core requires the following parameters to be set:
|
||||
@@ -58,12 +60,14 @@ You can supply your own SSL certificates if you so desire. The alternative is ru
|
||||
- [000-default](http://pastebin.com/HfyKpQNu)
|
||||
- [default-ssl](http://pastebin.com/2WCS5jnb)
|
||||
|
||||
### No SSL or Cloudflare
|
||||
### No SSL Cloudflare, or LetsEncrypt
|
||||
- Apache 2.4 or newer:
|
||||
- [000-default.conf](http://pastebin.com/j1Ps3ZK6)
|
||||
- Apache 2.3 or older:
|
||||
- [000-default](http://pastebin.com/BHQzf2pj)
|
||||
|
||||
To have LetsEncrypt automatically install SSL certs, comment out the three lines starting with `WSGI`, install certificates, then uncomment them in `000-default-ls-ssl.conf`
|
||||
|
||||
## Enabling and Disabling Sites
|
||||
|
||||
To instruct apache to serve traffic from a virtual host, enable it:
|
||||
|
||||
@@ -5,9 +5,10 @@ It's recommended to update all packages before proceeding.
|
||||
`sudo yum upgrade`
|
||||
`sudo reboot`
|
||||
|
||||
Now install all [dependencies](dependencies.md). For this guide you'll need the optional [JDK](dependencies.md) and [Apache](dependencies.md) sections as well.
|
||||
Now install all [dependencies](dependencies.md).
|
||||
|
||||
sudo yum install xxxxxxx
|
||||
|
||||
replacing the x's with the list of packages.
|
||||
|
||||
Make sure redis is running before continuing:
|
||||
@@ -28,9 +29,9 @@ Find the line which says `root ALL=(ALL) ALL` - beneath it add another
|
||||
|
||||
**From this point on you need to be logged in as the allianceserver user**
|
||||
|
||||
start your mariadb server `sudo systemctl start mariadb`
|
||||
Start your mariadb server `sudo systemctl start mariadb`
|
||||
|
||||
secure your MYSQL / Maria-db server by typing `mysql_secure_installation `
|
||||
Secure your MYSQL / Maria-db server by typing `mysql_secure_installation `
|
||||
|
||||
AllianceAuth needs a MySQL user account. Create one as follows, replacing `PASSWORD` with an actual secure password:
|
||||
|
||||
@@ -50,10 +51,14 @@ Ensure you are in the allianceserver home directory by issuing `cd`
|
||||
|
||||
Now we clone the source code:
|
||||
|
||||
git clone https://github.com/R4stl1n/allianceauth.git
|
||||
git clone https://github.com/allianceauth/allianceauth.git
|
||||
|
||||
Enter the folder by issuing `cd allianceauth`
|
||||
|
||||
Ensure you're on the latest version with the following:
|
||||
|
||||
git tag | sort -n | tail -1 | xargs git checkout
|
||||
|
||||
Python package dependencies can be installed from the requirements file:
|
||||
|
||||
sudo pip install -r requirements.txt
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# CloudFlare
|
||||
# Cloudflare
|
||||
|
||||
CloudFlare offers free SSL and DDOS mitigation services. Why not take advantage of it?
|
||||
|
||||
## Setup Protection
|
||||
## Setup
|
||||
|
||||
You’ll need to register an account on [CloudFlare’s site.](https://www.cloudflare.com/)
|
||||
|
||||
@@ -24,18 +24,12 @@ CloudFlare blocks ports outside 80 and 443 on hosts it protects. This means, if
|
||||
|
||||
## Redirect to HTTPS
|
||||
|
||||
Now we need to configure the https redirect to force all traffic to https. Along the top bar of CloudFlare, select `Page Rules`. Add a new rule, Pattern is yourdomain.com, toggle the `Always use https` to ON, and save. It’ll take a few minutes to propagate.
|
||||
Now we need to configure the https redirect to force all traffic to https. Along the top bar of CloudFlare, select `Page Rules`. Add a new rule, Pattern is yourdomain.com, toggle the `Always use https` to ON, and save. It’ll take a few minutes to propagate.
|
||||
|
||||

|
||||
|
||||
## Update Auth URLs
|
||||
|
||||
Edit settings.py and change the following values:
|
||||
- FORUM_URL = `os.environ.get('AA_FORUM_URL', "http://forums.mydomain.com")` if forums are on a subdomain
|
||||
- IPBOARD_ENDPOINT = `os.environ.get('AA_IPBOARD_ENDPOINT', 'http://forums.mydomain.com/ipboard/interface/board/index.php')` if forums are on a subdomain
|
||||
- JABBER_URL = `os.environ.get('AA_JABBER_URL', "jabber.yourdomain.com")`
|
||||
- OPENFIRE_ADDRESS = `os.environ.get('AA_OPENFIRE_ADDRESS', "http://jabber.yourdomain.com:9090")`
|
||||
- MUMBLE_URL = `os.environ.get('AA_MUMBLE_URL', "mumble.yourdomain.com")`
|
||||
- TEAMSPEAK3_PUBLIC_URL = `os.environ.get('AA_TEAMSPEAK3_PUBLIC_URL', 'ts.yourdomain.com')`
|
||||
Edit settings.py and replace everything that has a HTTP with HTTPS (except anything with a port on the end, like `OPENFIRE_ADDRESS`)
|
||||
|
||||
And there we have it. You’re DDOS-protected with free SSL.
|
||||
And there we have it. You’re DDOS-protected with free SSL.
|
||||
@@ -31,6 +31,7 @@ Required for phpBB, smf, evernus alliance market, etc
|
||||
|
||||
### Java
|
||||
Required for hosting jabber server
|
||||
|
||||
oracle-java8-installer
|
||||
|
||||
## CentOS 7
|
||||
@@ -53,7 +54,7 @@ Required for base auth site
|
||||
|
||||
#### Utilities
|
||||
|
||||
screen gcc unzip git redis curl nano
|
||||
screen gcc gcc-c++ unzip git redis curl nano
|
||||
|
||||
### Apache
|
||||
Required for displaying web content
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
centos
|
||||
settings
|
||||
apache
|
||||
cloudflare
|
||||
supervisor
|
||||
quickstart
|
||||
```
|
||||
|
||||
@@ -4,7 +4,7 @@ Once you’ve installed AllianceAuth, perform these steps to get yourself up and
|
||||
|
||||
First you need a superuser account. You can use this as a personal account. From the command line, `python manage.py createsuperuser` and follow the prompts.
|
||||
|
||||
The big goal of AllianceAuth is the automation of group membership, so we’ll need some groups. In the admin interface, select `Groups`, then at the top-right select `Add Group`. Give it a name and select permissions. Special characters (including spaces) are removing before syncing to services, so try not to have group names which will be the same upon cleaning. A description of permissions can be found in the [readme file](https://github.com/R4stl1n/allianceauth/blob/master/README.md). Repeat for all the groups you see fit, whenever you need a new one.
|
||||
The big goal of AllianceAuth is the automation of group membership, so we’ll need some groups. In the admin interface, select `Groups`, then at the top-right select `Add Group`. Give it a name and select permissions. Special characters (including spaces) are removing before syncing to services, so try not to have group names which will be the same upon cleaning. A description of permissions can be found in the [readme file](https://github.com/allianceauth/allianceauth/blob/master/README.md). Repeat for all the groups you see fit, whenever you need a new one.
|
||||
|
||||
### Background Processes
|
||||
|
||||
|
||||
@@ -310,6 +310,8 @@ The default data source to get character information. Default is `esi`
|
||||
The default data source to get corporation information. Default is `esi`
|
||||
### EVEONLINE_ALLIANCE_PROVIDER
|
||||
The default data source to get alliance information. Default is `esi`
|
||||
### EVEONLINE_ITEMTYPE_PROVIDER
|
||||
The default data source to get item type information. Default is `esi`
|
||||
## Alliance Market
|
||||
### MARKET_URL
|
||||
The web address to access the Evernus Alliance Market application.
|
||||
|
||||
@@ -40,13 +40,16 @@ Ensure you are in the allianceserver home directory by issuing `cd`
|
||||
|
||||
Now we clone the source code:
|
||||
|
||||
git clone https://github.com/R4stl1n/allianceauth.git
|
||||
git clone https://github.com/allianceauth/allianceauth.git
|
||||
|
||||
Enter the folder by issuing `cd allianceauth`
|
||||
|
||||
Ensure you're on the latest version with the following:
|
||||
|
||||
git tag | sort -n | tail -1 | xargs git checkout
|
||||
|
||||
Python package dependencies can be installed from the requirements file:
|
||||
|
||||
sudo pip install requests>=2.9.1
|
||||
sudo pip install -r requirements.txt
|
||||
|
||||
The settings file needs configuring. See [this lengthy guide](settings.md) for specifics.
|
||||
|
||||
@@ -13,5 +13,7 @@
|
||||
smf
|
||||
teamspeak3
|
||||
xenforo
|
||||
jacknife
|
||||
pathfinder
|
||||
|
||||
```
|
||||
|
||||
@@ -1,16 +1,12 @@
|
||||
# IPBoard3
|
||||
|
||||
Yes, you read that right. AllianceAuth only supports IPBoard 3, not the new shiny 4. Why? Because InvisionPower removed the API we used to manage it.
|
||||
|
||||
Moving right along.
|
||||
|
||||
You’re on your own for the initial install of IPBoard. It’s pretty much just download, unzip, and move to `/var/www/ipboard/`. Make sure to
|
||||
|
||||
sudo chown -R www-data:www-data /var/www/ipboard
|
||||
|
||||
a few times because it’s pretty finicky.
|
||||
|
||||
You’ll need to add another alias in your [apache config](https://github.com/R4stl1n/allianceauth/wiki/Apache-Setup#additional-parameters-for-full-setup), this one for `/ipboard/` pointing to `/var/www/ipboard` and add another `<directory>` block for `/var/www/ipboard` with `Require all granted` or `Allow from all` depending on your apache version.
|
||||
You’ll need to add another alias in your apache config, this one for `/ipboard` pointing to `/var/www/ipboard` and add another `<directory>` block for `/var/www/ipboard` with `Require all granted` or `Allow from all` depending on your apache version.
|
||||
|
||||
IPBoard needs a database table. Log in to mysql and run:
|
||||
|
||||
@@ -35,10 +31,10 @@ Copy the API key. Now edit your settings.py as follows:
|
||||
- IPBOARD_APIKEY is the key you just copied
|
||||
- IPBOARD_ENDPOINT is `http://yourdomain.com/ipboard/interface/board/index.php`
|
||||
|
||||
Now enable IPBoard for Auth and/or Blue by editing the [booleans](#alliance-service-setup).
|
||||
Now enable IPBoard for Auth and/or Blue by editing the auth settings.
|
||||
|
||||
Save and exit. Restart apache or gunicorn.
|
||||
|
||||
Test it by creating a user through AllianceAuth. Just note right now there’s no real error handling, so if account creation fails it’ll still return a username/password combo.
|
||||
Test it by creating a user through Alliance Auth. Just note right now there’s no real error handling, so if account creation fails it’ll still return a username/password combo.
|
||||
|
||||
Good luck!
|
||||
|
||||
71
docs/installation/services/jacknife.md
Normal file
71
docs/installation/services/jacknife.md
Normal file
@@ -0,0 +1,71 @@
|
||||
# Eve Jacknife
|
||||
|
||||
## Overview
|
||||
Eve Jacknife is used to audit an api so that you might see character skills and what ships they can fly, mails, contracts,assets, and any other given access from a specific api key.
|
||||
|
||||
## Dependencies
|
||||
All php and mysql dependencies should have been taken care of during setup.
|
||||
|
||||
## Installation
|
||||
### Get Code
|
||||
Navigate to your server's web directory: `cd /var/www`
|
||||
|
||||
Download the code: `sudo git clone https://github.com/whinis/eve-jacknife`
|
||||
|
||||
### Create Database
|
||||
|
||||
mysql -u root -p -e "create database jackknife; grant all privileges on jackknife.* to 'allianceserver'@'localhost';"
|
||||
|
||||
### Configure Settings
|
||||
|
||||
Change directory to jacknife: `cd eve-jacknife`
|
||||
|
||||
Now copy the template: `sudo cp base.config.php eve.config.php`
|
||||
|
||||
And now edit: `sudo nano eve.config.php`
|
||||
|
||||
Add the database user information:
|
||||
- `$sql_u = "allianceserver"`
|
||||
- `$sql_p = "MY_SQL_PASSWORD_HERE"`
|
||||
|
||||
## Apache Configuration
|
||||
|
||||
Change ownership of the directory: `sudo chown -R www-data:www-data ../eve-jacknife`
|
||||
|
||||
Eve Jacknife can be served two ways: on its own subdomain (`jacknife.mydomain.com`) or as an alias (`mydomain.com/jacknife`)
|
||||
|
||||
### Subdomain
|
||||
As its own subdomain, create a new apache config: `sudo nano /etc/apache2/sites-available/jacknife.conf` and enter the following:
|
||||
|
||||
<VirtualHost *:80>
|
||||
DocumentRoot "/var/www/eve-jacknife"
|
||||
ServerName jacknife.mydomain.com
|
||||
<Directory "/var/www/eve-jacknife">
|
||||
Require all granted
|
||||
AllowOverride all
|
||||
DirectoryIndex index.php
|
||||
</Directory>
|
||||
</VirtualHost>
|
||||
|
||||
Enable the new site with `sudo a2ensite jacknife.conf` and then reload apache with `sudo service apache2 reload`
|
||||
|
||||
### Alias
|
||||
As an alias, edit your site config (usually 000-default): `sudo nano etc/apache2/sites-available/000-default.conf` and add the following inside the `VirtualHost` block:
|
||||
|
||||
Alias /jacknife "/var/www/eve-jacknife/"
|
||||
<Directory "/var/www/eve-jacknife">
|
||||
Require all granted
|
||||
DirectoryIndex index.php
|
||||
</Directory>
|
||||
|
||||
Reload apache to take effect: `sudo service apache2 reload`
|
||||
|
||||
## Install SQL
|
||||
|
||||
Once apache is configured, Eve Jacknife needs to install some data. Navigate to it in your browser and append `/Installer.php` to the URL.
|
||||
|
||||
Enter your database password and press Check. If all the boxes come back green press Save. On the next screen press Install and wait for it to finish.
|
||||
|
||||
## Update Auth Settings
|
||||
|
||||
Edit your aut settings file (`nano ~/allianceauth/alliance_auth/settings.py`) and replace `JACK_KNIFE_URL` with either `jacknife.mydomain.com/` or `mydomain.com/jacknife/` depending on your apache choice.
|
||||
@@ -21,7 +21,7 @@ REQUIRED: To enable the ICE authenticator, edit the following:
|
||||
|
||||
- `icesecretwrite=MY_CLEVER_PASSWORD`, obviously choosing a secure password
|
||||
|
||||
To customize the database, edit the following:
|
||||
By default mumble operates on sqlite which is fine, but slower than a dedicated MySQL server. To customize the database, edit the following:
|
||||
|
||||
- uncomment the database line, and change it to `database=alliance_mumble`
|
||||
- `dbDriver=QMYSQL`
|
||||
@@ -30,7 +30,7 @@ To customize the database, edit the following:
|
||||
- `dbPort=3306`
|
||||
- `dbPrefix=murmur_`
|
||||
|
||||
To name your root channel, uncomment and edit `registerName=` whatever cool name you want
|
||||
To name your root channel, uncomment and set `registerName=` to whatever cool name you want
|
||||
|
||||
Save and close the file (control + O, control + X).
|
||||
|
||||
@@ -64,7 +64,7 @@ Edit `authenticator.ini` and change these values:
|
||||
|
||||
Test your configuration by starting it: `python authenticator.py`
|
||||
|
||||
#Running the Authenticator
|
||||
## Running the Authenticator
|
||||
|
||||
The authenticator needs to be running 24/7 to validate users on Mumble. The best way is to run it in a screen much like celery:
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ One additional package is required - [openjdk8](http://askubuntu.com/questions/4
|
||||
### Download Installer
|
||||
Openfire is not available through repositories so we need to get a debian from the developer.
|
||||
|
||||
On your PC, naviage to the [Ignite Realtime downloads section](https://www.igniterealtime.org/downloads/index.jsp), and under Openfire select Linux, click on the debian file (2nd in list, ends with .deb).
|
||||
On your PC, naviage to the [Ignite Realtime downloads section](https://www.igniterealtime.org/downloads/index.jsp), and under Openfire select Linux, click on the debian file (2nd from bottom of list, ends with .deb).
|
||||
|
||||
Retrieve the file location by copying the url from the “click here” link.
|
||||
|
||||
@@ -22,11 +22,11 @@ In the console, ensure you’re in your user’s home directory: `cd ~`
|
||||
|
||||
Now download the package. Replace the link below with the link you got earlier.
|
||||
|
||||
wget https://www.igniterealtime.org/downloadServlet?filename=openfire/openfire_3.10.2_all.deb
|
||||
wget https://www.igniterealtime.org/downloadServlet?filename=openfire/openfire_4.1.1_all.deb
|
||||
|
||||
Now install from the debian. Replace the filename with your file name (the last part of the download url is the file name)
|
||||
|
||||
sudo dpkg -i openfire_3.10.2_all.deb
|
||||
sudo dpkg -i openfire_4.1.1_all.deb
|
||||
|
||||
### Web Configuration
|
||||
The remainder of the setup occurs through Openfire’s web interface. Navigate to http://yourdomain.com:9090, or if you’re behind CloudFlare, go straight to your server’s IP:9090.
|
||||
@@ -58,7 +58,7 @@ Once loaded, press the green plus on the right for `REST API`.
|
||||
|
||||
Navigate the `Server` tab, `Sever Settings` subtab. At the bottom of the left navigation bar select `REST API`.
|
||||
|
||||
Select `Enabled`, and `Secret Key Auth`. Enter the secret key from OPENFIRE_SECRET_KEY here.
|
||||
Select `Enabled`, and `Secret Key Auth`. Update Alliance Auth settings with this secret key as `OPENFIRE_SECRET_KEY`.
|
||||
|
||||
### Broadcast Plugin Setup
|
||||
|
||||
|
||||
77
docs/installation/services/pathfinder.md
Normal file
77
docs/installation/services/pathfinder.md
Normal file
@@ -0,0 +1,77 @@
|
||||
# Pathfinder
|
||||
Pathfinder is a wormhole mapping tool.
|
||||
|
||||
While auth doesn't integrate with pathfinder anymore, from personal experience I've found it much easier to use the following install process than to try and follow the pathfinder-supplied docs.
|
||||
|
||||
|
||||
## Installation
|
||||
### Get the code
|
||||
|
||||
Navigate to the install location: `cd /var/www/` and git clone the repo:
|
||||
|
||||
sudo git clone https://github.com/exodus4d/pathfinder.git
|
||||
|
||||
### Create logs and caches
|
||||
|
||||
Change directory to pathfinder: `cd pathfinder`
|
||||
|
||||
The logging and caching folders need to be created and have permission set. If upon installation you get Server Error 500, try resetting these permissions.
|
||||
|
||||
sudo mkdir logs
|
||||
sudo mkdir tmp/cache
|
||||
sudo chmod -R 766 logs
|
||||
sudo chmod -R 766 tmp/cache
|
||||
|
||||
## .htaccess Configuration
|
||||
|
||||
In your `pathfinder` directory there are two `.htaccess` files. The default installation instructions want you to choose one for rewriting purposes, and these force you to www.pathfinder.mydomain.com. Personally I don't like that.
|
||||
|
||||
So we'll frankenstein our own. We'll use the HTTP one as a base:
|
||||
|
||||
sudo mv .htaccess .htaccess_HTTPS
|
||||
sudo mv .htaccess_HTTPS .htaccess
|
||||
sudo nano .htaccess
|
||||
|
||||
Find the www rewriting section (labelled `Rewrite NONE www. to force www.`). Change it so that all lines start with a `#`:
|
||||
|
||||
#RewriteCond %{HTTP_HOST} !^www\.
|
||||
# skip "localhost" (dev environment)...
|
||||
#RewriteCond %{HTTP_HOST} !=localhost
|
||||
# skip IP calls (dev environment) e.g. 127.0.0.1
|
||||
#RewriteCond %{HTTP_HOST} !^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$
|
||||
# rewrite everything else to "http://" and "www."
|
||||
#RewriteRule .* http://www.%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
|
||||
|
||||
This allows us to choose SSL and www forwarding with our apache conf instead of this htaccess file.
|
||||
|
||||
## Apache Configuration
|
||||
The best way to have this is to setup a subdomain on your server.
|
||||
|
||||
Create a config file `sudo nano /etc/apache2/sites-available/pathfinder.conf` and enter [this configuration](http://pastebin.com/wmXyf6pN), being sure to edit the `ServerName`
|
||||
|
||||
Enable it with:
|
||||
|
||||
sudo a2ensite pathfinder.conf
|
||||
sudo service apache2 reload
|
||||
|
||||
## Configuration Files
|
||||
|
||||
The default configuration should be fine in most cases. Edit all values with caution!
|
||||
|
||||
environment.ini
|
||||
- `SERVER` Should be changed to `PRODUCTION`
|
||||
- `BASE` is the full filesystem path to the application root on your server. In our case, `/var/www/pathfinder/`
|
||||
- `URL` Is the URL to your app (without a trailing slash). In our case, `http://pathfinder.mydomain.com`
|
||||
- `DEBUG` sets the level of debugging (1,2 or 3) (check /logs for a more detail backtrace information)
|
||||
- `DB_*` sets your DB connection information
|
||||
- `SMTP_*` are used to send out emails, you will need an SMTP server login to make this work. (not required)
|
||||
- `SSO_CCP_*` follow the [official docs](https://github.com/exodus4d/pathfinder/wiki/CREST)
|
||||
|
||||
## Database Setup
|
||||
This is done through the browser. Go to `pathfinder.yourdomain.com/setup` and see the [official docs](https://github.com/exodus4d/pathfinder/wiki/Database) for instructions.
|
||||
|
||||
## Cron Jobs
|
||||
Again the [official docs](https://github.com/exodus4d/pathfinder/wiki/Cronjob) do a good job here.
|
||||
|
||||
## Finish Setup
|
||||
Once you've compelted the above steps, we need to disable the setup page. Edit the routes with `nano app/routes.ini` and put a `;` in front of the line starting with `GET @setup`
|
||||
@@ -14,11 +14,11 @@ In the console, navigate to your user’s home directory: `cd ~`
|
||||
|
||||
Now download using wget, replacing the url with the url for the package you just retrieved
|
||||
|
||||
wget https://www.phpbb.com/files/release/phpBB-3.1.6.zip
|
||||
wget https://www.phpbb.com/files/release/phpBB-3.2.0.zip
|
||||
|
||||
This needs to be unpackaged. Unzip it, replacing the file name with that of the file you just downloaded
|
||||
|
||||
unzip phpBB-3.1.6.zip
|
||||
unzip phpBB-3.2.0.zip
|
||||
|
||||
Now we need to move this to our web directory. Usually `/var/www/forums`.
|
||||
|
||||
@@ -47,7 +47,7 @@ You should see `Succesful Connection` and proceed.
|
||||
|
||||
Enter administrator credentials on the next page.
|
||||
|
||||
Everything from hereon out should be intuitive.
|
||||
Everything from here should be intuitive.
|
||||
|
||||
phpBB will then write its own config file.
|
||||
|
||||
@@ -59,11 +59,11 @@ Before users can see the forums, we need to remove the install directory
|
||||
### Enabling Avatars
|
||||
AllianceAuth sets user avatars to their character portrait when the account is created or password reset. We need to allow external URLs for avatars for them to behave properly. Navigate to the admin control panel for phpbb3, and under the `General` tab, along the left navigation bar beneath `Board Configuration`, select `Avatar Settings`. Set `Enable Remote Avatars` to `Yes` and then `Submit`.
|
||||
|
||||
[Screenshot of this page](http://imgur.com/UOgaq6J)
|
||||

|
||||
|
||||
You can allow members to overwrite the portrait with a custom image if desired. Navigate to `Users and Groups`, `Group Permissions`, select the appropriate group (usually `Member` if you want everyone to have this ability), expand `Advanced Permissions`, under the `Profile` tab, set `Can Change Avatars` to `Yes`, and press `Apply Permissions`.
|
||||
|
||||
[Screenshot of this page](http://i.imgur.com/VGHwdxM.png)
|
||||

|
||||
|
||||
## Setup Complete
|
||||
You’ve finished the steps required to make AllianceAuth work with phpBB. Play around with it and make it your own.
|
||||
|
||||
@@ -14,11 +14,11 @@ In the console, navigate to your user’s home directory: `cd ~`
|
||||
|
||||
Now download using wget, replacing the url with the url for the package you just retrieved
|
||||
|
||||
wget http://download.simplemachines.org/index.php?thanks;filename=smf_2-0-11_install.zip
|
||||
wget http://download.simplemachines.org/index.php?thanks;filename=smf_2-0-13_install.zip
|
||||
|
||||
This needs to be unpackaged. Unzip it, replacing the file name with that of the file you just downloaded
|
||||
|
||||
unzip smf_2-0-11_install.zip
|
||||
unzip smf_2-0-13_install.zip
|
||||
|
||||
Now we need to move this to our web directory. Usually `/var/www/forums`.
|
||||
|
||||
|
||||
@@ -3,10 +3,14 @@
|
||||
## Overview
|
||||
Teamspeak3 is the most popular VOIP program for gamers.
|
||||
|
||||
But have you considered using Mumble? Not only is it free, but it has features and performance far superior to Teamspeak3.
|
||||
|
||||
## Dependencies
|
||||
All dependencies should have been taken care of during the AllianceAuth install.
|
||||
|
||||
## Setup
|
||||
Sticking with it? Alright, I tried.
|
||||
|
||||
### Download Installer
|
||||
To install we need a copy of the server. You can find the latest version from [this dl server](http://dl.4players.de/ts/releases/) (I’d recommed getting the latest stable version – find this version number from the [TeamSpeak site](https://www.teamspeak.com/downloads#)). Be sure to get a link to the linux version.
|
||||
|
||||
@@ -14,11 +18,11 @@ From the console, ensure you’re in the user’s home directory: `cd ~`
|
||||
|
||||
And now download the server, replacing the link with the link you got earlier.
|
||||
|
||||
wget http://dl.4players.de/ts/releases/3.0.11.4/teamspeak3-server_linux-amd64-3.0.11.4.tar.gz
|
||||
http://dl.4players.de/ts/releases/3.0.13.6/teamspeak3-server_linux_amd64-3.0.13.6.tar.bz2
|
||||
|
||||
Now we need to extract the file.
|
||||
|
||||
tar -xvf teamspeak3-server_linux-amd64-3.0.11.4.tar.gz
|
||||
tar -xf teamspeak3-server_linux_amd64-3.0.13.6.tar.bz2
|
||||
|
||||
### Create User
|
||||
Teamspeak needs its own user.
|
||||
@@ -28,15 +32,13 @@ Teamspeak needs its own user.
|
||||
### Install Binary
|
||||
Now we move the server binary somewhere more accessible and change its ownership to the new user.
|
||||
|
||||
sudo mv teamspeak3-server_linux-amd64 /usr/local/teamspeak
|
||||
|
||||
sudo mv teamspeak3-server_linux_amd64 /usr/local/teamspeak
|
||||
sudo chown -R teamspeak:teamspeak /usr/local/teamspeak
|
||||
|
||||
### Startup
|
||||
Now we generate a startup script so teamspeak comes up with the server.
|
||||
|
||||
sudo ln -s /usr/local/teamspeak/ts3server_startscript.sh /etc/init.d/teamspeak
|
||||
|
||||
sudo update-rc.d teamspeak defaults
|
||||
|
||||
Finally we start the server.
|
||||
@@ -46,14 +48,16 @@ Finally we start the server.
|
||||
### Update Settings
|
||||
The console will spit out a block of text. **SAVE THIS**.
|
||||
|
||||
Update the AllianceAuth settings file with the following:
|
||||
- TEAMSPEAK3_SERVERQUERY_USER is `loginname`
|
||||
- TEAMSPEAK3_SERVERQUERY_PASSWORD is `password`
|
||||
Update the AllianceAuth settings file with the following from that block of text:
|
||||
- `TEAMSPEAK3_SERVERQUERY_USER` is `loginname` (usually `serveradmin`)
|
||||
- `TEAMSPEAK3_SERVERQUERY_PASSWORD` is `password`
|
||||
|
||||
Save and reload apache.
|
||||
Save and reload apache. Restart celery workers as well.
|
||||
|
||||
sudo service apache2 reload
|
||||
|
||||
If you plan on claiming the ServerAdmin token, do so with a different TeamSpeak client profile than the one used for your auth account, or you will lose your admin status.
|
||||
|
||||
### Generate User Account
|
||||
And now we can generate ourselves a user account. Navigate to the services in AllianceAuth for your user account and press the checkmark for TeamSpeak 3.
|
||||
|
||||
@@ -65,6 +69,47 @@ Now we need to make groups. AllianceAuth handles groups in teamspeak differently
|
||||
|
||||
Navigate back to the AllianceAuth admin interface (yourdomain.com/admin) and under `Services`, select `Auth / TS Groups`. In the top-right corner click `Add`.
|
||||
|
||||
The dropdown box provides all auth groups. Select one and assign TeamSpeak groups from the panels below. If these panels are empty, wait a minute for the database update to run.
|
||||
The dropdown box provides all auth groups. Select one and assign TeamSpeak groups from the panels below. If these panels are empty, wait a minute for the database update to run, or see the [troubleshooting section](#ts-group-models-not-populating-on-admin-site) below.
|
||||
|
||||
## Setup Complete
|
||||
## Troubleshooting
|
||||
|
||||
### `Insufficient client permissions (failed on Invalid permission: 0x26)`
|
||||
|
||||
Using the advanced permissions editor, ensure the `Guest` group has the permission `Use Privilege Keys to gain permissions` (under `Virtual Server` expand the `Administration` section)
|
||||
|
||||
To enable advanced permissions, on your client go to the `Tools` menu, `Application`, and under the `Misc` section, tick `Advanced permission system`
|
||||
|
||||
### TS group models not populating on admin site
|
||||
The method which populates these runs every 30 minutes. To populate manually, start a celery shell:
|
||||
|
||||
python manage.py celery shell
|
||||
|
||||
And execute the update:
|
||||
|
||||
run_ts3_group_update()
|
||||
|
||||
Ensure that command does not return an error.
|
||||
|
||||
### `2564 access to default group is forbidden`
|
||||
|
||||
This usually occurs because auth is trying to remove a user from the `Guest` group (group ID 8). The guest group is only assigned to a user when they have no other groups, unless you have changed the default teamspeak server config.
|
||||
|
||||
Teamspeak servers v3.0.13 and up are especially susceptible to this. Ensure the Channel Admin Group is not set to `Guest (8)`. Check by right clicking on the server name, `Edit virtual server`, and in the middle of the panel select the `Misc` tab.
|
||||
|
||||
### `TypeError: string indices must be integers, not str`
|
||||
|
||||
This error generally means teamspeak returned an error message that went unhandled. The full traceback is required for proper debugging, which the logs do not record. Please check the superuser notifications for this record and get in touch with a developer.
|
||||
|
||||
### `3331 flood ban`
|
||||
|
||||
This most commonly happens when your teamspeak server is externally hosted. You need to add the auth server IP to the teamspeak serverquery whitelist. This varies by provider.
|
||||
|
||||
If you have SSH access to the server hosting it, you need to locate the teamspeak server folder and add the auth server IP on a new line in `server_query_whitelist.txt`
|
||||
|
||||
### `520 invalid loginname or password`
|
||||
|
||||
The serverquery account login specified in settings.py is incorrect. Please verify `TEAMSPEAK3_SERVERQUERY_USER` and `TEAMSPEAK3_SERVERQUERY_PASSWORD`. The [installation section](#update-settings) describes where to get them.
|
||||
|
||||
### `2568 insufficient client permissions`
|
||||
|
||||
This usually occurs if you've created a separate serverquery user to use with auth. It has not been assigned sufficient permissions to complete all the tasks required of it. The full list of required permissions is not known, so assign liberally.
|
||||
@@ -1,12 +1,12 @@
|
||||
# Changelog
|
||||
|
||||
## From now on all changelogs will be included as release notes.
|
||||
https://github.com/R4stl1n/allianceauth/releases
|
||||
https://github.com/allianceauth/allianceauth/releases
|
||||
|
||||
### 547
|
||||
Oct 16
|
||||
|
||||
Golly this is a big one. Upgrading takes a bit of work. [For full instructions click here.](https://github.com/R4stl1n/allianceauth/pull/547#issue-183247630)
|
||||
Golly this is a big one. Upgrading takes a bit of work. [For full instructions click here.](https://github.com/allianceauth/allianceauth/pull/547#issue-183247630)
|
||||
|
||||
- Update django version to 1.10
|
||||
- Remove member/blue permissions
|
||||
@@ -100,7 +100,7 @@ Mar 23 2016
|
||||
### 314
|
||||
Mar 22 2016
|
||||
- Revamp of the Human Resources Application and Management System
|
||||
- see the [wiki page](https://github.com/R4stl1n/allianceauth/wiki/HRApplications) for how to use the new system
|
||||
- see the [docs](../features/hrapplications.md) for how to use the new system
|
||||
- a completely untested conversion script exists. If you want to view your old models, contact Adarnof to try it out
|
||||
- Moved Error Handling for the API Keys to the API Calls to better handle API server outages
|
||||
- Removed the infamous database update task
|
||||
|
||||
@@ -6,6 +6,5 @@
|
||||
|
||||
changelog
|
||||
troubleshooting
|
||||
cloudflare
|
||||
|
||||
```
|
||||
|
||||
@@ -3,12 +3,11 @@
|
||||
## Something broken? Stuck on an issue? Can't get it set up?
|
||||
|
||||
Start here:
|
||||
- read the [documentation](https://github.com/R4stl1n/allianceauth/wiki)
|
||||
- check the [issues](https://github.com/R4stl1n/allianceauth/issues?utf8=%E2%9C%93&q=is%3Aissue) - especially closed ones
|
||||
- check the [issues](https://github.com/allianceauth/allianceauth/issues?utf8=%E2%9C%93&q=is%3Aissue) - especially closed ones
|
||||
- check the [forums](https://forums.eveonline.com/default.aspx?g=posts&t=383030)
|
||||
|
||||
No answer?
|
||||
- open an [issue](https://github.com/R4stl1n/allianceauth/issues)
|
||||
- open an [issue](https://github.com/allianceauth/allianceauth/issues)
|
||||
- harass us on [gitter](https://gitter.im/R4stl1n/allianceauth)
|
||||
- post to the [forums](https://forums.eveonline.com/default.aspx?g=posts&t=383030)
|
||||
|
||||
@@ -16,9 +15,7 @@ No answer?
|
||||
|
||||
### `pip install -r requirements.txt` is failing
|
||||
|
||||
Most commonly, your repositories did not include the `requests` package. Install it and try again: `sudo pip install requests`
|
||||
|
||||
Otherwise it's usually a missing dependency. Check [the list](../installation/auth/dependencies.md), reinstall, and try again.
|
||||
Either you need to `sudo` that command, or it's a missing dependency. Check [the list](../installation/auth/dependencies.md), reinstall, and try again.
|
||||
|
||||
### I'm getting an error 500 trying to connect to the website on a new install
|
||||
|
||||
@@ -26,7 +23,11 @@ Read the apache error log: `sudo nano /var/log/apache2/error.log`
|
||||
|
||||
If it talks about failing to import something, google its name and install it.
|
||||
|
||||
If it whines about being unable to configure logger, make sure the log directory is write-able: `chmod -R 777 /home/allianceserver/allianceauth/log`, then reload apache.
|
||||
If it whines about being unable to configure logger, see below.
|
||||
|
||||
### Failed to configure log handler
|
||||
|
||||
Make sure the log directory is write-able: `chmod -R 777 /home/allianceserver/allianceauth/log`, then reload apache/celery/supervisor/etc.
|
||||
|
||||
### Groups aren't syncing to services
|
||||
|
||||
@@ -34,9 +35,7 @@ Make sure the background processes are running: `ps aux | grep celery` should re
|
||||
|
||||
If that doesn't do it, try clearing the worker queue. First kill all celery processes as described above, then do the following:
|
||||
|
||||
sudo rabbitmqctl stop_app
|
||||
sudo rabbitmqctl reset
|
||||
sudo rabbitmqctl start_app
|
||||
redis-cli FLUSHALL
|
||||
python manage.py celeryd --purge
|
||||
|
||||
Press control+C once.
|
||||
|
||||
@@ -13,7 +13,17 @@ admin.site.register(EveCorporationInfo)
|
||||
|
||||
class EveApiKeyPairAdmin(admin.ModelAdmin):
|
||||
search_fields = ['api_id', 'user__username']
|
||||
list_display = ['api_id', 'user']
|
||||
list_display = ['api_id', 'user', 'characters']
|
||||
|
||||
@staticmethod
|
||||
def characters(obj):
|
||||
return ', '.join(sorted([c.character_name for c in EveCharacter.objects.filter(api_id=obj.api_id)]))
|
||||
|
||||
def get_search_results(self, request, queryset, search_term):
|
||||
queryset, use_distinct = super(EveApiKeyPairAdmin, self).get_search_results(request, queryset, search_term)
|
||||
chars = EveCharacter.objects.filter(character_name__icontains=search_term)
|
||||
queryset |= EveApiKeyPair.objects.filter(api_id__in=[char.api_id for char in chars if bool(char.api_id)])
|
||||
return queryset, use_distinct
|
||||
|
||||
|
||||
class EveCharacterAdmin(admin.ModelAdmin):
|
||||
|
||||
@@ -28,7 +28,10 @@ class UpdateKeyForm(forms.Form):
|
||||
raise forms.ValidationError("API ID must be a number")
|
||||
|
||||
def clean(self):
|
||||
super(UpdateKeyForm, self).clean()
|
||||
if 'api_id' not in self.cleaned_data or 'api_key' not in self.cleaned_data:
|
||||
# need to check if api_id and vcode in cleaned_data because
|
||||
# if they fail, they get removed from the dict but this method still happens
|
||||
return self.cleaned_data
|
||||
|
||||
if EveManager.check_if_api_key_pair_exist(self.cleaned_data['api_id']):
|
||||
logger.debug("UpdateKeyForm failed cleaning as API id %s already exists." % self.cleaned_data['api_id'])
|
||||
|
||||
@@ -9,15 +9,23 @@ import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
adapter = eve_adapter_factory()
|
||||
|
||||
class EveManager:
|
||||
def __init__(self):
|
||||
pass
|
||||
class EveManager(object):
|
||||
adapter = None
|
||||
|
||||
@classmethod
|
||||
def get_adapter(cls):
|
||||
if not cls.adapter:
|
||||
cls.adapter = eve_adapter_factory()
|
||||
return cls.adapter
|
||||
|
||||
@classmethod
|
||||
def get_character(cls, character_id):
|
||||
return cls.get_adapter().get_character(character_id)
|
||||
|
||||
@staticmethod
|
||||
def create_character(id, user, api_id):
|
||||
return EveManager.create_character_obj(adapter.get_character(id), user, api_id)
|
||||
return EveManager.create_character_obj(EveManager.get_character(id), user, api_id)
|
||||
|
||||
@staticmethod
|
||||
def create_character_obj(character, user, api_id):
|
||||
@@ -35,7 +43,7 @@ class EveManager:
|
||||
|
||||
@staticmethod
|
||||
def update_character(id):
|
||||
return EveManager.update_character_obj(adapter.get_character(id))
|
||||
return EveManager.update_character_obj(EveManager.get_character(id))
|
||||
|
||||
@staticmethod
|
||||
def update_character_obj(char):
|
||||
@@ -61,9 +69,13 @@ class EveManager:
|
||||
else:
|
||||
logger.warn("Attempting to create existing api keypair with id %s" % api_id)
|
||||
|
||||
@classmethod
|
||||
def get_alliance(cls, alliance_id):
|
||||
return cls.get_adapter().get_alliance(alliance_id)
|
||||
|
||||
@staticmethod
|
||||
def create_alliance(id, is_blue=False):
|
||||
return EveManager.create_alliance_obj(adapter.get_alliance(id), is_blue=is_blue)
|
||||
return EveManager.create_alliance_obj(EveManager.get_alliance(id), is_blue=is_blue)
|
||||
|
||||
@staticmethod
|
||||
def create_alliance_obj(alliance, is_blue=False):
|
||||
@@ -77,7 +89,7 @@ class EveManager:
|
||||
|
||||
@staticmethod
|
||||
def update_alliance(id, is_blue=None):
|
||||
return EveManager.update_alliance_obj(adapter.get_alliance(id), is_blue=is_blue)
|
||||
return EveManager.update_alliance_obj(EveManager.get_alliance(id), is_blue=is_blue)
|
||||
|
||||
@staticmethod
|
||||
def update_alliance_obj(alliance, is_blue=None):
|
||||
@@ -89,17 +101,20 @@ class EveManager:
|
||||
@staticmethod
|
||||
def populate_alliance(id):
|
||||
alliance_model = EveAllianceInfo.objects.get(alliance_id=id)
|
||||
alliance = adapter.get_alliance(id)
|
||||
alliance = EveManager.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)
|
||||
|
||||
|
||||
@classmethod
|
||||
def get_corporation(cls, corp_id):
|
||||
return cls.get_adapter().get_corp(corp_id)
|
||||
|
||||
@staticmethod
|
||||
def create_corporation(id, is_blue=False):
|
||||
return EveManager.create_corporation_obj(adapter.get_corp(id), is_blue=is_blue)
|
||||
return EveManager.create_corporation_obj(EveManager.get_corporation(id), is_blue=is_blue)
|
||||
|
||||
@staticmethod
|
||||
def create_corporation_obj(corp, is_blue=False):
|
||||
@@ -118,7 +133,7 @@ class EveManager:
|
||||
|
||||
@staticmethod
|
||||
def update_corporation(id, is_blue=None):
|
||||
return EveManager.update_corporation_obj(adapter.get_corp(id), is_blue=is_blue)
|
||||
return EveManager.update_corporation_obj(EveManager.get_corporation(id), is_blue=is_blue)
|
||||
|
||||
@staticmethod
|
||||
def update_corporation_obj(corp, is_blue=None):
|
||||
@@ -131,10 +146,14 @@ class EveManager:
|
||||
model.is_blue = model.is_blue if is_blue == None else is_blue
|
||||
model.save()
|
||||
|
||||
@classmethod
|
||||
def get_itemtype(cls, type_id):
|
||||
return cls.get_adapter().get_itemtype(type_id)
|
||||
|
||||
@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)
|
||||
provider = EveXmlProvider(adapter=EveManager.get_adapter())
|
||||
return [provider._build_character(result) for id, result in char_result.items()]
|
||||
|
||||
@staticmethod
|
||||
|
||||
122
eveonline/migrations/0007_unique_id_name.py
Normal file
122
eveonline/migrations/0007_unique_id_name.py
Normal file
@@ -0,0 +1,122 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.10.5 on 2017-01-18 13:20
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
def get_duplicates(items):
|
||||
return set([item for item in items if items.count(item) > 1])
|
||||
|
||||
|
||||
def enforce_unique_characters(apps, schema_editor):
|
||||
EveCharacter = apps.get_model('eveonline', 'EveCharacter')
|
||||
|
||||
ids = [c.character_id for c in EveCharacter.objects.all()]
|
||||
duplicates = get_duplicates(ids)
|
||||
for c_id in duplicates:
|
||||
dupes = EveCharacter.objects.filter(character_id=c_id)
|
||||
dupes.exclude(pk=dupes[0].pk).delete()
|
||||
|
||||
names = [c.character_name for c in EveCharacter.objects.all()]
|
||||
duplicates = get_duplicates(names)
|
||||
for name in duplicates:
|
||||
dupes = EveCharacter.objects.filter(character_name=name)
|
||||
dupes.exclude(pk=dupes[0].pk).delete()
|
||||
|
||||
|
||||
def enforce_unique_corporations(apps, schema_editor):
|
||||
EveCorporationInfo = apps.get_model('eveonline', 'EveCorporationInfo')
|
||||
|
||||
ids = [c.corporation_id for c in EveCorporationInfo.objects.all()]
|
||||
duplicates = get_duplicates(ids)
|
||||
for c_id in duplicates:
|
||||
dupes = EveCorporationInfo.objects.filter(corporation_id=c_id)
|
||||
dupes.exclude(pk=dupes[0].pk).delete()
|
||||
|
||||
names = [c.corporation_name for c in EveCorporationInfo.objects.all()]
|
||||
duplicates = get_duplicates(names)
|
||||
for name in duplicates:
|
||||
dupes = EveCorporationInfo.objects.filter(character_name=name)
|
||||
dupes.exclude(pk=dupes[0].pk).delete()
|
||||
|
||||
|
||||
def enforce_unique_alliances(apps, schema_editor):
|
||||
EveAllianceInfo = apps.get_model('eveonline', 'EveAllianceInfo')
|
||||
EveCorporationInfo = apps.get_model('eveonline', 'EveCorporationInfo')
|
||||
|
||||
ids = [a.alliance_id for a in EveAllianceInfo.objects.all()]
|
||||
duplicates = get_duplicates(ids)
|
||||
for a_id in duplicates:
|
||||
dupes = EveAllianceInfo.objects.filter(alliance_id=a_id)
|
||||
to_be_kept = dupes[0]
|
||||
EveCorporationInfo.objects.filter(alliance__pk__in=[a.pk for a in dupes.exclude(pk=to_be_kept.pk)]).update(
|
||||
alliance=to_be_kept.pk)
|
||||
dupes.exclude(pk=to_be_kept.pk).delete()
|
||||
|
||||
names = [a.alliance_name for a in EveAllianceInfo.objects.all()]
|
||||
duplicates = get_duplicates(names)
|
||||
for name in duplicates:
|
||||
dupes = EveAllianceInfo.objects.filter(alliance_name=name)
|
||||
to_be_kept = dupes[0]
|
||||
EveCorporationInfo.objects.filter(alliance__in=[a.pk for a in dupes.exclude(pk=to_be_kept.pk)]).update(
|
||||
alliance=to_be_kept.pk)
|
||||
dupes.exclude(pk=to_be_kept.pk).delete()
|
||||
|
||||
|
||||
def enforce_unique_apis(apps, schema_editor):
|
||||
EveApiKeyPair = apps.get_model('eveonline', 'EveApiKeyPair')
|
||||
|
||||
ids = [api.api_id for api in EveApiKeyPair.objects.all()]
|
||||
duplicates = get_duplicates(ids)
|
||||
for api_id in duplicates:
|
||||
dupes = EveApiKeyPair.objects.filter(api_id=api_id)
|
||||
dupes.exclude(pk=dupes[0].pk).delete()
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
('eveonline', '0006_allow_null_evecharacter_alliance'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RunPython(enforce_unique_characters, migrations.RunPython.noop),
|
||||
migrations.RunPython(enforce_unique_corporations, migrations.RunPython.noop),
|
||||
migrations.RunPython(enforce_unique_alliances, migrations.RunPython.noop),
|
||||
migrations.RunPython(enforce_unique_apis, migrations.RunPython.noop),
|
||||
migrations.AlterField(
|
||||
model_name='evecharacter',
|
||||
name='character_id',
|
||||
field=models.CharField(max_length=254, unique=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='evecharacter',
|
||||
name='character_name',
|
||||
field=models.CharField(max_length=254, unique=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='evecorporationinfo',
|
||||
name='corporation_id',
|
||||
field=models.CharField(max_length=254, unique=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='evecorporationinfo',
|
||||
name='corporation_name',
|
||||
field=models.CharField(max_length=254, unique=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='eveallianceinfo',
|
||||
name='alliance_id',
|
||||
field=models.CharField(max_length=254, unique=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='eveallianceinfo',
|
||||
name='alliance_name',
|
||||
field=models.CharField(max_length=254, unique=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='eveapikeypair',
|
||||
name='api_id',
|
||||
field=models.CharField(max_length=254, unique=True),
|
||||
),
|
||||
]
|
||||
@@ -6,8 +6,8 @@ from django.contrib.auth.models import User
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class EveCharacter(models.Model):
|
||||
character_id = models.CharField(max_length=254)
|
||||
character_name = models.CharField(max_length=254)
|
||||
character_id = models.CharField(max_length=254, unique=True)
|
||||
character_name = models.CharField(max_length=254, unique=True)
|
||||
corporation_id = models.CharField(max_length=254)
|
||||
corporation_name = models.CharField(max_length=254)
|
||||
corporation_ticker = models.CharField(max_length=254)
|
||||
@@ -22,7 +22,7 @@ class EveCharacter(models.Model):
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class EveApiKeyPair(models.Model):
|
||||
api_id = models.CharField(max_length=254)
|
||||
api_id = models.CharField(max_length=254, unique=True)
|
||||
api_key = models.CharField(max_length=254)
|
||||
user = models.ForeignKey(User, blank=True, null=True)
|
||||
sso_verified = models.BooleanField(default=False)
|
||||
@@ -33,8 +33,8 @@ class EveApiKeyPair(models.Model):
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class EveAllianceInfo(models.Model):
|
||||
alliance_id = models.CharField(max_length=254)
|
||||
alliance_name = models.CharField(max_length=254)
|
||||
alliance_id = models.CharField(max_length=254, unique=True)
|
||||
alliance_name = models.CharField(max_length=254, unique=True)
|
||||
alliance_ticker = models.CharField(max_length=254)
|
||||
executor_corp_id = models.CharField(max_length=254)
|
||||
is_blue = models.BooleanField(default=False)
|
||||
@@ -45,8 +45,8 @@ class EveAllianceInfo(models.Model):
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class EveCorporationInfo(models.Model):
|
||||
corporation_id = models.CharField(max_length=254)
|
||||
corporation_name = models.CharField(max_length=254)
|
||||
corporation_id = models.CharField(max_length=254, unique=True)
|
||||
corporation_name = models.CharField(max_length=254, unique=True)
|
||||
corporation_ticker = models.CharField(max_length=254)
|
||||
member_count = models.IntegerField()
|
||||
is_blue = models.BooleanField(default=False)
|
||||
|
||||
@@ -1,14 +1,23 @@
|
||||
from django.utils.encoding import python_2_unicode_compatible
|
||||
from esi.clients import esi_client_factory
|
||||
from django.conf import settings
|
||||
from django.core.cache import cache
|
||||
import json
|
||||
from bravado.exception import HTTPNotFound, HTTPUnprocessableEntity
|
||||
import evelink
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# optional setting to control cached object lifespan
|
||||
OBJ_CACHE_DURATION = int(getattr(settings, 'EVEONLINE_OBJ_CACHE_DURATION', 300))
|
||||
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class ObjectNotFound(Exception):
|
||||
def __init__(self, id, type):
|
||||
self.id = id
|
||||
self.type = type
|
||||
def __init__(self, obj_id, type_name):
|
||||
self.id = obj_id
|
||||
self.type = type_name
|
||||
|
||||
def __str__(self):
|
||||
return '%s with ID %s not found.' % (self.type, self.id)
|
||||
@@ -32,6 +41,16 @@ class Entity(object):
|
||||
def __eq__(self, other):
|
||||
return self.id == other.id
|
||||
|
||||
def serialize(self):
|
||||
return {
|
||||
'id': self.id,
|
||||
'name': self.name,
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, data_dict):
|
||||
return cls(data_dict['id'], data_dict['name'])
|
||||
|
||||
|
||||
class Corporation(Entity):
|
||||
def __init__(self, provider, id, name, ticker, ceo_id, members, alliance_id):
|
||||
@@ -58,6 +77,28 @@ class Corporation(Entity):
|
||||
self._ceo = self.provider.get_character(self.ceo_id)
|
||||
return self._ceo
|
||||
|
||||
def serialize(self):
|
||||
return {
|
||||
'id': self.id,
|
||||
'name': self.name,
|
||||
'ticker': self.ticker,
|
||||
'ceo_id': self.ceo_id,
|
||||
'members': self.members,
|
||||
'alliance_id': self.alliance_id
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, dict):
|
||||
return cls(
|
||||
None,
|
||||
dict['id'],
|
||||
dict['name'],
|
||||
dict['ticker'],
|
||||
dict['ceo_id'],
|
||||
dict['members'],
|
||||
dict['alliance_id'],
|
||||
)
|
||||
|
||||
|
||||
class Alliance(Entity):
|
||||
def __init__(self, provider, id, name, ticker, corp_ids, executor_corp_id):
|
||||
@@ -70,7 +111,7 @@ class Alliance(Entity):
|
||||
|
||||
def corp(self, id):
|
||||
assert id in self.corp_ids
|
||||
if not id in self._corps:
|
||||
if id not in self._corps:
|
||||
self._corps[id] = self.provider.get_corp(id)
|
||||
self._corps[id]._alliance = self
|
||||
return self._corps[id]
|
||||
@@ -83,6 +124,26 @@ class Alliance(Entity):
|
||||
def executor_corp(self):
|
||||
return self.corp(self.executor_corp_id)
|
||||
|
||||
def serialize(self):
|
||||
return {
|
||||
'id': self.id,
|
||||
'name': self.name,
|
||||
'ticker': self.ticker,
|
||||
'corp_ids': self.corp_ids,
|
||||
'executor_corp_id': self.executor_corp_id,
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, dict):
|
||||
return cls(
|
||||
None,
|
||||
dict['id'],
|
||||
dict['name'],
|
||||
dict['ticker'],
|
||||
dict['corp_ids'],
|
||||
dict['executor_corp_id'],
|
||||
)
|
||||
|
||||
|
||||
class Character(Entity):
|
||||
def __init__(self, provider, id, name, corp_id, alliance_id):
|
||||
@@ -96,7 +157,7 @@ class Character(Entity):
|
||||
@property
|
||||
def corp(self):
|
||||
if not self._corp:
|
||||
self._corp = self.provider.get_corp(self.corp_id)
|
||||
self._corp = self.provider.get_corp(self.corp_id)
|
||||
return self._corp
|
||||
|
||||
@property
|
||||
@@ -105,8 +166,40 @@ class Character(Entity):
|
||||
return self.corp.alliance
|
||||
return Entity(None, None)
|
||||
|
||||
def serialize(self):
|
||||
return {
|
||||
'id': self.id,
|
||||
'name': self.name,
|
||||
'corp_id': self.corp_id,
|
||||
'alliance_id': self.alliance_id,
|
||||
}
|
||||
|
||||
class EveProvider:
|
||||
@classmethod
|
||||
def from_dict(cls, dict):
|
||||
return cls(
|
||||
None,
|
||||
dict['id'],
|
||||
dict['name'],
|
||||
dict['corp_id'],
|
||||
dict['alliance_id'],
|
||||
)
|
||||
|
||||
|
||||
class ItemType(Entity):
|
||||
def __init__(self, provider, type_id, name):
|
||||
super(ItemType, self).__init__(type_id, name)
|
||||
self.provider = provider
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, data_dict):
|
||||
return cls(
|
||||
None,
|
||||
data_dict['id'],
|
||||
data_dict['name'],
|
||||
)
|
||||
|
||||
|
||||
class EveProvider(object):
|
||||
def get_alliance(self, alliance_id):
|
||||
"""
|
||||
:return: an Alliance object for the given ID
|
||||
@@ -119,12 +212,18 @@ class EveProvider:
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
|
||||
def get_character(self, corp_id):
|
||||
def get_character(self, character_id):
|
||||
"""
|
||||
:return: a Character object for the given ID
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
|
||||
def get_itemtype(self, type_id):
|
||||
"""
|
||||
:return: an ItemType object for the given ID
|
||||
"""
|
||||
raise NotImplemented()
|
||||
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class EveSwaggerProvider(EveProvider):
|
||||
@@ -135,13 +234,13 @@ class EveSwaggerProvider(EveProvider):
|
||||
def __str__(self):
|
||||
return 'esi'
|
||||
|
||||
def get_alliance(self, id):
|
||||
def get_alliance(self, alliance_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()
|
||||
data = self.client.Alliance.get_alliances_alliance_id(alliance_id=alliance_id).result()
|
||||
corps = self.client.Alliance.get_alliances_alliance_id_corporations(alliance_id=alliance_id).result()
|
||||
model = Alliance(
|
||||
self.adapter,
|
||||
id,
|
||||
alliance_id,
|
||||
data['alliance_name'],
|
||||
data['ticker'],
|
||||
corps,
|
||||
@@ -149,14 +248,14 @@ class EveSwaggerProvider(EveProvider):
|
||||
)
|
||||
return model
|
||||
except HTTPNotFound:
|
||||
raise ObjectNotFound(id, 'alliance')
|
||||
raise ObjectNotFound(alliance_id, 'alliance')
|
||||
|
||||
def get_corp(self, id):
|
||||
def get_corp(self, corp_id):
|
||||
try:
|
||||
data = self.client.Corporation.get_corporations_corporation_id(corporation_id=id).result()
|
||||
data = self.client.Corporation.get_corporations_corporation_id(corporation_id=corp_id).result()
|
||||
model = Corporation(
|
||||
self.adapter,
|
||||
id,
|
||||
corp_id,
|
||||
data['corporation_name'],
|
||||
data['ticker'],
|
||||
data['ceo_id'],
|
||||
@@ -167,20 +266,27 @@ class EveSwaggerProvider(EveProvider):
|
||||
except HTTPNotFound:
|
||||
raise ObjectNotFound(id, 'corporation')
|
||||
|
||||
def get_character(self, id):
|
||||
def get_character(self, character_id):
|
||||
try:
|
||||
data = self.client.Character.get_characters_character_id(character_id=id).result()
|
||||
data = self.client.Character.get_characters_character_id(character_id=character_id).result()
|
||||
alliance_id = self.adapter.get_corp(data['corporation_id']).alliance_id
|
||||
model = Character(
|
||||
self.adapter,
|
||||
id,
|
||||
character_id,
|
||||
data['name'],
|
||||
data['corporation_id'],
|
||||
alliance_id,
|
||||
)
|
||||
return model
|
||||
except (HTTPNotFound, HTTPUnprocessableEntity):
|
||||
raise ObjectNotFound(id, 'character')
|
||||
raise ObjectNotFound(character_id, 'character')
|
||||
|
||||
def get_itemtype(self, type_id):
|
||||
try:
|
||||
data = self.client.Universe.get_universe_types_type_id(type_id=type_id).result()
|
||||
return ItemType(self.adapter, type_id, data['name'])
|
||||
except (HTTPNotFound, HTTPUnprocessableEntity):
|
||||
raise ObjectNotFound(type_id, 'type')
|
||||
|
||||
|
||||
@python_2_unicode_compatible
|
||||
@@ -250,34 +356,112 @@ class EveXmlProvider(EveProvider):
|
||||
raise e
|
||||
return self._build_character(charinfo)
|
||||
|
||||
def get_itemtype(self, type_id):
|
||||
api = evelink.eve.EVE(api=self.api)
|
||||
try:
|
||||
type_name = api.type_name_from_id(type_id).result
|
||||
assert type_name != 'Unknown Type'
|
||||
return ItemType(self.adapter, type_id, type_name)
|
||||
except AssertionError:
|
||||
raise ObjectNotFound(type_id, 'itemtype')
|
||||
|
||||
|
||||
class EveAdapter(EveProvider):
|
||||
"""
|
||||
Redirects queries to appropriate data source.
|
||||
"""
|
||||
def __init__(self, char_provider, corp_provider, alliance_provider):
|
||||
|
||||
def __init__(self, char_provider, corp_provider, alliance_provider, itemtype_provider):
|
||||
self.char_provider = char_provider
|
||||
self.corp_provider = corp_provider
|
||||
self.alliance_provider = alliance_provider
|
||||
self.itemtype_provider = itemtype_provider
|
||||
self.char_provider.adapter = self
|
||||
self.corp_provider.adapter = self
|
||||
self.alliance_provider.adapter = self
|
||||
self.itemtype_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))
|
||||
return "<{} (character:{} corp:{} alliance:{} itemtype:{})>".format(self.__class__.__name__,
|
||||
str(self.char_provider),
|
||||
str(self.corp_provider),
|
||||
str(self.alliance_provider),
|
||||
str(self.itemtype_provider))
|
||||
|
||||
@staticmethod
|
||||
def _get_from_cache(obj_class, id):
|
||||
data = cache.get('%s__%s' % (obj_class.__name__.lower(), id))
|
||||
if data:
|
||||
obj = obj_class.from_dict(json.loads(data))
|
||||
logger.debug('Got from cache: %s' % obj.__repr__())
|
||||
return obj
|
||||
else:
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def _cache(obj):
|
||||
logger.debug('Caching: %s ' % obj.__repr__())
|
||||
cache.set('%s__%s' % (obj.__class__.__name__.lower(), obj.id), json.dumps(obj.serialize()),
|
||||
int(OBJ_CACHE_DURATION))
|
||||
|
||||
def get_character(self, id):
|
||||
return self.char_provider.get_character(id)
|
||||
obj = self._get_from_cache(Character, id)
|
||||
if obj:
|
||||
obj.provider = self
|
||||
else:
|
||||
obj = self._get_character(id)
|
||||
self._cache(obj)
|
||||
return obj
|
||||
|
||||
def get_corp(self, id):
|
||||
return self.corp_provider.get_corp(id)
|
||||
obj = self._get_from_cache(Corporation, id)
|
||||
if obj:
|
||||
obj.provider = self
|
||||
else:
|
||||
obj = self._get_corp(id)
|
||||
self._cache(obj)
|
||||
return obj
|
||||
|
||||
def get_alliance(self, id):
|
||||
obj = self._get_from_cache(Alliance, id)
|
||||
if obj:
|
||||
obj.provider = self
|
||||
else:
|
||||
obj = self._get_alliance(id)
|
||||
self._cache(obj)
|
||||
return obj
|
||||
|
||||
def get_itemtype(self, type_id):
|
||||
obj = self._get_from_cache(ItemType, type_id)
|
||||
if obj:
|
||||
obj.provider = self
|
||||
else:
|
||||
obj = self._get_itemtype(type_id)
|
||||
self._cache(obj)
|
||||
return obj
|
||||
|
||||
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 _get_itemtype(self, type_id):
|
||||
return self.itemtype_provider.get_itemtype(type_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]
|
||||
|
||||
CHARACTER_PROVIDER = getattr(settings, 'EVEONLINE_CHARACTER_PROVIDER', '') or 'esi'
|
||||
CORP_PROVIDER = getattr(settings, 'EVEONLINE_CORP_PROVIDER', '') or 'esi'
|
||||
ALLIANCE_PROVIDER = getattr(settings, 'EVEONLINE_ALLIANCE_PROVIDER', '') or 'esi'
|
||||
ITEMTYPE_PROVIDER = getattr(settings, 'EVEONLINE_ITEMTYPE_PROVIDER', '') or 'esi'
|
||||
|
||||
|
||||
def eve_adapter_factory(character_source=CHARACTER_PROVIDER, corp_source=CORP_PROVIDER,
|
||||
alliance_source=ALLIANCE_PROVIDER, itemtype_source=ITEMTYPE_PROVIDER, api_key=None, token=None):
|
||||
sources = [character_source, corp_source, alliance_source, itemtype_source]
|
||||
providers = []
|
||||
|
||||
if 'xml' in sources:
|
||||
@@ -292,4 +476,4 @@ def eve_adapter_factory(character_source=settings.EVEONLINE_CHARACTER_PROVIDER,
|
||||
providers.append(esi)
|
||||
else:
|
||||
raise ValueError('Unrecognized data source "%s"' % source)
|
||||
return EveAdapter(providers[0], providers[1], providers[2])
|
||||
return EveAdapter(providers[0], providers[1], providers[2], providers[3])
|
||||
|
||||
@@ -12,7 +12,6 @@ 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
|
||||
|
||||
@@ -2,7 +2,6 @@ from __future__ import unicode_literals
|
||||
from django.shortcuts import render, redirect, get_object_or_404
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.contrib import messages
|
||||
|
||||
from eveonline.forms import UpdateKeyForm
|
||||
from eveonline.managers import EveManager
|
||||
from authentication.managers import AuthServicesInfoManager
|
||||
@@ -11,7 +10,6 @@ from eveonline.models import EveApiKeyPair, EveCharacter
|
||||
from authentication.models import AuthServicesInfo
|
||||
from authentication.tasks import set_state
|
||||
from eveonline.tasks import refresh_api
|
||||
|
||||
from esi.decorators import token_required
|
||||
from django.conf import settings
|
||||
import logging
|
||||
@@ -30,7 +28,7 @@ def add_api_key(request):
|
||||
api_key=form.cleaned_data['api_key']).exists():
|
||||
# allow orphaned keys to proceed to SSO validation upon re-entry
|
||||
api_key = EveApiKeyPair.objects.get(api_id=form.cleaned_data['api_id'],
|
||||
api_key=form.cleaned_data['api_key'])
|
||||
api_key=form.cleaned_data['api_key'])
|
||||
elif EveApiKeyPair.objects.filter(api_id=form.cleaned_data['api_id']).exists():
|
||||
logger.warn('API %s re-added with different vcode.' % form.cleaned_data['api_id'])
|
||||
EveApiKeyPair.objects.filter(api_id=form.cleaned_data['api_id']).delete()
|
||||
@@ -47,7 +45,8 @@ def add_api_key(request):
|
||||
owner = request.user
|
||||
# Grab characters associated with the key pair
|
||||
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()]
|
||||
[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'])
|
||||
@@ -57,7 +56,7 @@ def add_api_key(request):
|
||||
return redirect("auth_dashboard")
|
||||
else:
|
||||
logger.debug('Requesting SSO validation of API %s by user %s' % (api_key.api_id, request.user))
|
||||
return render(request, 'registered/apisso.html', context={'api':api_key})
|
||||
return render(request, 'registered/apisso.html', context={'api': api_key})
|
||||
else:
|
||||
logger.debug("Form invalid: returning to form.")
|
||||
else:
|
||||
@@ -93,8 +92,9 @@ def api_sso_validate(request, token, api_id):
|
||||
return redirect('auth_characters')
|
||||
return redirect('auth_dashboard')
|
||||
else:
|
||||
messages.warning(request, '%s not found on API %s. Please SSO as a character on the API.' % (token.character_name, api.api_id))
|
||||
return render(request, 'registered/apisso.html', context={'api':api})
|
||||
messages.warning(request, '%s not found on API %s. Please SSO as a character on the API.' % (
|
||||
token.character_name, api.api_id))
|
||||
return render(request, 'registered/apisso.html', context={'api': api})
|
||||
|
||||
|
||||
@login_required
|
||||
@@ -110,7 +110,7 @@ def dashboard_view(request):
|
||||
api_chars.append({
|
||||
'id': api.api_id,
|
||||
'sso_verified': api.sso_verified if sso_validation else True,
|
||||
'characters': EveManager.get_characters_by_api_id(api.api_id),
|
||||
'characters': EveCharacter.objects.filter(api_id=api.api_id),
|
||||
})
|
||||
|
||||
context = {
|
||||
@@ -139,7 +139,7 @@ def api_key_removal(request, api_id):
|
||||
@login_required
|
||||
def characters_view(request):
|
||||
logger.debug("characters_view called by user %s" % request.user)
|
||||
render_items = {'characters': EveManager.get_characters_by_owner_id(request.user.id),
|
||||
render_items = {'characters': EveCharacter.objects.filter(user=request.user),
|
||||
'authinfo': AuthServicesInfo.objects.get(user=request.user)}
|
||||
return render(request, 'registered/characters.html', context=render_items)
|
||||
|
||||
@@ -147,7 +147,8 @@ def characters_view(request):
|
||||
@login_required
|
||||
def main_character_change(request, char_id):
|
||||
logger.debug("main_character_change called by user %s for character id %s" % (request.user, char_id))
|
||||
if EveManager.check_if_character_owned_by_user(char_id, request.user):
|
||||
if EveCharacter.objects.filter(character_id=char_id).exists() and EveCharacter.objects.get(
|
||||
character_id=char_id).user == request.user:
|
||||
AuthServicesInfoManager.update_main_char_id(char_id, request.user)
|
||||
messages.success(request, 'Changed main character ID to %s' % char_id)
|
||||
set_state(request.user)
|
||||
|
||||
@@ -28,14 +28,15 @@ 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)
|
||||
fats = p.page(1)
|
||||
except EmptyPage:
|
||||
fatss = p.page(p.num_pages)
|
||||
fats = p.page(p.num_pages)
|
||||
return fats
|
||||
|
||||
|
||||
@@ -45,7 +46,8 @@ class CorpStat(object):
|
||||
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()
|
||||
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):
|
||||
@@ -95,7 +97,6 @@ def fatlink_statistics_view(request, year=datetime.date.today().year, month=date
|
||||
start_of_previous_month = first_day_of_previous_month(year, month)
|
||||
|
||||
fat_stats = {}
|
||||
|
||||
|
||||
# get FAT stats for member corps
|
||||
for corp_id in settings.STR_CORP_IDS:
|
||||
@@ -110,8 +111,9 @@ def fatlink_statistics_view(request, year=datetime.date.today().year, month=date
|
||||
fatlink__fatdatetime__lt=start_of_next_month).exclude(character__corporation_id__in=fat_stats)
|
||||
|
||||
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)
|
||||
if fat.character.corporation_id not in fat_stats:
|
||||
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]
|
||||
@@ -129,7 +131,7 @@ def fatlink_statistics_view(request, year=datetime.date.today().year, month=date
|
||||
|
||||
|
||||
@login_required
|
||||
def fatlink_personal_statistics_view(request, year=datetime.date.today().year, main_name=None):
|
||||
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))
|
||||
|
||||
@@ -191,7 +193,8 @@ def fatlink_monthly_personal_statistics_view(request, year, month, char_id=None)
|
||||
|
||||
|
||||
@login_required
|
||||
@token_required(scopes=['esi-location.read_location.v1', 'esi-location.read_ship_type.v1', 'esi-universe.read_structures.v1'])
|
||||
@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]
|
||||
@@ -205,14 +208,20 @@ def click_fatlink_view(request, token, hash, fatname):
|
||||
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']
|
||||
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']
|
||||
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']
|
||||
location['station_name'] = \
|
||||
c.Universe.get_universe_stations_station_id(station_id=location['station_id']).result()[
|
||||
'station_name']
|
||||
else:
|
||||
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']
|
||||
ship['ship_type_name'] = EveManager.get_itemtype(ship['ship_type_id']).name
|
||||
|
||||
fat = Fat()
|
||||
fat.system = location['solar_system_name']
|
||||
|
||||
@@ -16,12 +16,15 @@ django>=1.10,<2.0
|
||||
django-bootstrap-form
|
||||
django-navhelper
|
||||
django-bootstrap-pagination
|
||||
django-redis>=4.4
|
||||
|
||||
# awating release for fix to celery/django-celery#447
|
||||
# django-celery
|
||||
git+https://github.com/celery/django-celery
|
||||
|
||||
git+git://github.com/nikdoof/python-ts3.git
|
||||
git+https://github.com/pyghassen/openfire-restapi
|
||||
|
||||
# awating pyghassen/openfire-restapi #1 to fix installation issues
|
||||
git+https://github.com/adarnof/openfire-restapi
|
||||
|
||||
git+https://github.com/adarnof/adarnauth-esi
|
||||
|
||||
20
srp/migrations/0002_srpuserrequest_srp_status_choices.py
Normal file
20
srp/migrations/0002_srpuserrequest_srp_status_choices.py
Normal file
@@ -0,0 +1,20 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.10.5 on 2017-01-18 20:21
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('srp', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='srpuserrequest',
|
||||
name='srp_status',
|
||||
field=models.CharField(choices=[('Pending', 'Pending'), ('Approved', 'Approved'), ('Rejected', 'Rejected')], default='Pending', max_length=8),
|
||||
),
|
||||
]
|
||||
@@ -16,15 +16,29 @@ class SrpFleetMain(models.Model):
|
||||
fleet_srp_aar_link = models.CharField(max_length=254, default="")
|
||||
|
||||
def __str__(self):
|
||||
return self.fleet_name + " - SrpFleetMain"
|
||||
return self.fleet_name
|
||||
|
||||
@property
|
||||
def total_cost(self):
|
||||
return sum([int(r.srp_total_amount) for r in self.srpuserrequest_set.all()])
|
||||
|
||||
@property
|
||||
def pending_requests(self):
|
||||
return self.srpuserrequest_set.filter(srp_status='Pending').count()
|
||||
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class SrpUserRequest(models.Model):
|
||||
SRP_STATUS_CHOICES = (
|
||||
('Pending', 'Pending'),
|
||||
('Approved', 'Approved'),
|
||||
('Rejected', 'Rejected'),
|
||||
)
|
||||
|
||||
killboard_link = models.CharField(max_length=254, default="")
|
||||
after_action_report_link = models.CharField(max_length=254, default="")
|
||||
additional_info = models.CharField(max_length=254, default="")
|
||||
srp_status = models.CharField(max_length=254, default="")
|
||||
srp_status = models.CharField(max_length=8, default="Pending", choices=SRP_STATUS_CHOICES)
|
||||
srp_total_amount = models.BigIntegerField(default=0)
|
||||
character = models.ForeignKey(EveCharacter)
|
||||
srp_fleet_main = models.ForeignKey(SrpFleetMain)
|
||||
@@ -33,4 +47,4 @@ class SrpUserRequest(models.Model):
|
||||
post_time = models.DateTimeField(default=timezone.now)
|
||||
|
||||
def __str__(self):
|
||||
return self.character.character_name + " - SrpUserRequest"
|
||||
return self.character.character_name + ' SRP request for ' + self.srp_ship_name
|
||||
|
||||
50
srp/views.py
50
srp/views.py
@@ -15,7 +15,6 @@ from services.managers.srp_manager import srpManager
|
||||
from notifications import notify
|
||||
from django.utils import timezone
|
||||
from authentication.decorators import members_and_blues
|
||||
from esi.clients import esi_client_factory
|
||||
import uuid
|
||||
|
||||
import logging
|
||||
@@ -35,20 +34,9 @@ def random_string(string_length=10):
|
||||
@members_and_blues()
|
||||
def srp_management(request):
|
||||
logger.debug("srp_management called by user %s" % request.user)
|
||||
totalcost = 0
|
||||
runningcost = 0
|
||||
price_pair = {}
|
||||
for fleet_main in SrpFleetMain.objects.filter(fleet_srp_status="").iterator():
|
||||
for fleet_data in SrpUserRequest.objects.filter(srp_fleet_main=fleet_main).iterator():
|
||||
totalcost = totalcost + fleet_data.srp_total_amount
|
||||
runningcost = runningcost + fleet_data.srp_total_amount
|
||||
price_pair[fleet_main.id] = runningcost
|
||||
logger.debug("Determined SRP fleet %s costs %s" % (fleet_main.id, runningcost))
|
||||
runningcost = 0
|
||||
logger.debug("Determined total outstanding SRP cost %s" % totalcost)
|
||||
|
||||
context = {"srpfleets": SrpFleetMain.objects.filter(fleet_srp_status=""), "totalcost": totalcost,
|
||||
"price_pair": price_pair}
|
||||
fleets = SrpFleetMain.objects.filter(fleet_srp_status="")
|
||||
totalcost = sum([int(fleet.total_cost) for fleet in fleets])
|
||||
context = {"srpfleets": fleets, "totalcost": totalcost}
|
||||
return render(request, 'registered/srpmanagement.html', context=context)
|
||||
|
||||
|
||||
@@ -56,19 +44,9 @@ def srp_management(request):
|
||||
@members_and_blues()
|
||||
def srp_management_all(request):
|
||||
logger.debug("srp_management_all called by user %s" % request.user)
|
||||
totalcost = 0
|
||||
runningcost = 0
|
||||
price_pair = {}
|
||||
for fleet_main in SrpFleetMain.objects.all().iterator():
|
||||
for fleet_data in SrpUserRequest.objects.filter(srp_fleet_main=fleet_main).iterator():
|
||||
totalcost = totalcost + fleet_data.srp_total_amount
|
||||
runningcost = runningcost + fleet_data.srp_total_amount
|
||||
price_pair[fleet_main.id] = runningcost
|
||||
logger.debug("Determined SRP fleet %s costs %s" % (fleet_main.id, runningcost))
|
||||
runningcost = 0
|
||||
logger.debug("Determined all-time total SRP cost %s" % totalcost)
|
||||
|
||||
context = {"srpfleets": SrpFleetMain.objects.all(), "totalcost": totalcost, "price_pair": price_pair}
|
||||
fleets = SrpFleetMain.objects.all()
|
||||
totalcost = sum([int(fleet.total_cost) for fleet in fleets])
|
||||
context = {"srpfleets": SrpFleetMain.objects.all(), "totalcost": totalcost}
|
||||
return render(request, 'registered/srpmanagement.html', context=context)
|
||||
|
||||
|
||||
@@ -78,14 +56,9 @@ def srp_fleet_view(request, fleet_id):
|
||||
logger.debug("srp_fleet_view called by user %s for fleet id %s" % (request.user, fleet_id))
|
||||
if SrpFleetMain.objects.filter(id=fleet_id).exists():
|
||||
fleet_main = SrpFleetMain.objects.get(id=fleet_id)
|
||||
totalcost = 0
|
||||
for fleet_data in SrpUserRequest.objects.filter(srp_fleet_main=fleet_main).filter(srp_status="Approved"):
|
||||
totalcost = totalcost + fleet_data.srp_total_amount
|
||||
logger.debug("Determiend fleet id %s total cost %s" % (fleet_id, totalcost))
|
||||
|
||||
context = {"fleet_id": fleet_id, "fleet_status": fleet_main.fleet_srp_status,
|
||||
"srpfleetrequests": SrpUserRequest.objects.filter(srp_fleet_main=fleet_main),
|
||||
"totalcost": totalcost}
|
||||
"srpfleetrequests": fleet_main.srpuserrequest_set.all(),
|
||||
"totalcost": fleet_main.total_cost}
|
||||
|
||||
return render(request, 'registered/srpfleetdata.html', context=context)
|
||||
else:
|
||||
@@ -236,18 +209,16 @@ def srp_request_view(request, fleet_srp):
|
||||
character = EveManager.get_character_by_id(authinfo.main_char_id)
|
||||
srp_fleet_main = SrpFleetMain.objects.get(fleet_srp_code=fleet_srp)
|
||||
post_time = timezone.now()
|
||||
srp_status = "Pending"
|
||||
|
||||
srp_request = SrpUserRequest()
|
||||
srp_request.killboard_link = form.cleaned_data['killboard_link']
|
||||
srp_request.additional_info = form.cleaned_data['additional_info']
|
||||
srp_request.character = character
|
||||
srp_request.srp_fleet_main = srp_fleet_main
|
||||
srp_request.srp_status = srp_status
|
||||
|
||||
try:
|
||||
srp_kill_link = srpManager.get_kill_id(srp_request.killboard_link)
|
||||
(srp_kill_data, ship_value) = srpManager.get_kill_data(srp_kill_link)
|
||||
(ship_type_id, ship_value) = srpManager.get_kill_data(srp_kill_link)
|
||||
except ValueError:
|
||||
logger.debug("User %s Submitted Invalid Killmail Link %s or server could not be reached" % (
|
||||
request.user, srp_request.killboard_link))
|
||||
@@ -255,8 +226,7 @@ def srp_request_view(request, fleet_srp):
|
||||
messages.error(request,
|
||||
"Your SRP request Killmail link is invalid. Please make sure you are using zKillboard.")
|
||||
return redirect("auth_srp_management_view")
|
||||
c = esi_client_factory()
|
||||
srp_ship_name = c.Universe.get_universe_types_type_id(type_id=srp_kill_data).result()['type_name']
|
||||
srp_ship_name = EveManager.get_itemtype(ship_type_id).name
|
||||
srp_request.srp_ship_name = srp_ship_name
|
||||
kb_total_loss = ship_value
|
||||
srp_request.kb_total_loss = kb_total_loss
|
||||
|
||||
@@ -32,13 +32,7 @@
|
||||
<html>
|
||||
<head lang="en">
|
||||
<meta charset="UTF-8">
|
||||
<title>
|
||||
{% if IS_CORP %}
|
||||
{{ CORP_NAME }}
|
||||
{% else %}
|
||||
{{ ALLIANCE_NAME }}
|
||||
{% endif %}
|
||||
</title>
|
||||
<title>{{ SITE_NAME }}</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="logo">
|
||||
|
||||
@@ -11,12 +11,8 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="description" content="">
|
||||
<meta name="author" content="">
|
||||
{% if IS_CORP %}
|
||||
<title>{{ CORP_NAME }} - Login</title>
|
||||
{% else %}
|
||||
<title>{{ ALLIANCE_NAME }} - Login</title>
|
||||
{% endif %}
|
||||
|
||||
<title>{{ SITE_NAME }} - Login</title>
|
||||
|
||||
<!-- Bootstrap Core CSS -->
|
||||
<link href="{% static 'css/bootstrap.min.css' %}" rel="stylesheet">
|
||||
<!-- Custom Fonts -->
|
||||
|
||||
@@ -10,12 +10,7 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="description" content="">
|
||||
<meta name="author" content="">
|
||||
|
||||
{% if IS_CORP %}
|
||||
<title>{{ CORP_NAME }} - Login</title>
|
||||
{% else %}
|
||||
<title>{{ ALLIANCE_NAME }} - Login</title>
|
||||
{% endif %}
|
||||
<title>{{ SITE_NAME }} - Login</title>
|
||||
|
||||
<!-- Bootstrap Core CSS -->
|
||||
<link href="{% static 'css/bootstrap.min.css' %}" rel="stylesheet">
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
</div>
|
||||
<div class="col-lg-4 col-sm-2">
|
||||
<table class="table">
|
||||
<tr><td class="text-center"><img class="ra-avatar" src="http://image.eveonline.com/Corporation/{{ main.corporation_id }}_128.png"></td></tr>
|
||||
<tr><td class="text-center"><img class="ra-avatar" src="https://image.eveonline.com/Corporation/{{ main.corporation_id }}_128.png"></td></tr>
|
||||
<tr><td class="text-center">{{ main.corporation_name }}</td></tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
@@ -51,11 +51,7 @@
|
||||
<div class="alert alert-warning text-center">No groups available.</div>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
{% if IS_CORP %}
|
||||
<div class="alert alert-danger" role="alert">{% trans "You are not in the corporation." %}</div>
|
||||
{% else %}
|
||||
<div class="alert alert-danger" role="alert">{% trans "You are not in the alliance." %}</div>
|
||||
{% endif %}
|
||||
<div class="alert alert-danger" role="alert">{% trans "You are not a member." %}</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
|
||||
@@ -51,14 +51,10 @@
|
||||
</tr>
|
||||
{% for srpfleetrequest in srpfleetrequests %}
|
||||
<tr>
|
||||
<td class="text-center">
|
||||
<div class="label label-info">
|
||||
{{ srpfleetrequest.character.character_name }}
|
||||
</div>
|
||||
</td>
|
||||
<td class="text-center">{{ srpfleetrequest.character.character_name }}</td>
|
||||
<td class="text-center">
|
||||
<a href="{{ srpfleetrequest.killboard_link }}"
|
||||
target="_blank">{{ srpfleetrequest.killboard_link }}</a>
|
||||
target="_blank" class="label label-warning">Link</a>
|
||||
</td>
|
||||
<td class="text-center">{{ srpfleetrequest.additional_info }}</td>
|
||||
<td class="text-center">{{ srpfleetrequest.srp_ship_name }}</td>
|
||||
@@ -83,36 +79,28 @@
|
||||
{% if perms.auth.srp_management %}
|
||||
|
||||
<td class="text-center">
|
||||
<a href="{% url 'auth_srp_request_update_amount_view' srpfleetrequest.id %}" class="btn btn-info">
|
||||
<span class="glyphicon glyphicon-pencil"></span>
|
||||
<a href="{% url 'auth_srp_request_update_amount_view' srpfleetrequest.id %}" class="btn btn-info" title="Update Value">
|
||||
<span class="glyphicon glyphicon-usd"></span>
|
||||
</a>
|
||||
{% if srpfleetrequest.srp_status == "Rejected" %}
|
||||
<a href="{% url 'auth_srp_request_approve' srpfleetrequest.id %}" class="btn btn-success">
|
||||
<span class="glyphicon glyphicon-ok"></span>
|
||||
</a>
|
||||
{% elif srpfleetrequest.srp_status == "Pending" %}
|
||||
<a href="{% url 'auth_srp_request_approve' srpfleetrequest.id %}" class="btn btn-success">
|
||||
{% if srpfleetrequest.srp_status in "RejectedPending" %}
|
||||
<a href="{% url 'auth_srp_request_approve' srpfleetrequest.id %}" class="btn btn-success" title="Approve">
|
||||
<span class="glyphicon glyphicon-ok"></span>
|
||||
</a>
|
||||
{% elif srpfleetrequest.srp_status == "" %}
|
||||
<a href="{% url 'auth_srp_request_approve' srpfleetrequest.id %}" class="btn btn-success">
|
||||
<a href="{% url 'auth_srp_request_approve' srpfleetrequest.id %}" class="btn btn-success" title="Approve">
|
||||
<span class="glyphicon glyphicon-ok"></span>
|
||||
</a>
|
||||
{% endif %}
|
||||
{% if srpfleetrequest.srp_status == "Approved" %}
|
||||
<a href="{% url 'auth_srp_request_reject' srpfleetrequest.id %}" class="btn btn-warning">
|
||||
<span class="glyphicon glyphicon-remove"></span>
|
||||
</a>
|
||||
{% elif srpfleetrequest.srp_status == "Pending" %}
|
||||
<a href="{% url 'auth_srp_request_reject' srpfleetrequest.id %}" class="btn btn-warning">
|
||||
{% if srpfleetrequest.srp_status in "ApprovedPending" %}
|
||||
<a href="{% url 'auth_srp_request_reject' srpfleetrequest.id %}" class="btn btn-warning" title="Reject">
|
||||
<span class="glyphicon glyphicon-remove"></span>
|
||||
</a>
|
||||
{% elif srpfleetrequest.srp_status == "" %}
|
||||
<a href="{% url 'auth_srp_request_reject' srpfleetrequest.id %}" class="btn btn-warning">
|
||||
<a href="{% url 'auth_srp_request_reject' srpfleetrequest.id %}" class="btn btn-warning" title="Reject">
|
||||
<span class="glyphicon glyphicon-remove"></span>
|
||||
</a>
|
||||
{% endif %}
|
||||
<a href="{% url 'auth_srp_request_remove' srpfleetrequest.id %}" class="btn btn-danger">
|
||||
<a href="{% url 'auth_srp_request_remove' srpfleetrequest.id %}" class="btn btn-danger" title="Remove">
|
||||
<span class="glyphicon glyphicon-trash"></span>
|
||||
</a>
|
||||
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
<th class="text-center">{% trans "Fleet SRP Code" %}</th>
|
||||
<th class="text-center">{% trans "Fleet ISK Cost" %}</th>
|
||||
<th class="text-center">{% trans "SRP Status" %}</th>
|
||||
<th class="text-center">{% trans "Pending Requests" %}</th>
|
||||
<th class="text-center">{% trans "Actions" %}</th>
|
||||
</tr>
|
||||
{% for srpfleet in srpfleets %}
|
||||
@@ -56,27 +57,21 @@
|
||||
{{ srpfleet.fleet_commander.character_name }}
|
||||
</div>
|
||||
</td>
|
||||
<th class="text-center"><a href="{{ srpfleet.fleet_srp_aar_link }}"
|
||||
target="_blank">{{ srpfleet.fleet_srp_aar_link }}</a></th>
|
||||
<th class="text-center">
|
||||
<td class="text-center">
|
||||
{% if srpfleet.fleet_srp_aar_link %}
|
||||
<a href="{{ srpfleet.fleet_srp_aar_link }}" target="_blank" class="label label-primary">{% trans 'Link' %}</a>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="text-center">
|
||||
{% if srpfleet.fleet_srp_code %}
|
||||
<div class="label label-warning">
|
||||
<a href="{% url 'auth_srp_request_view' srpfleet.fleet_srp_code %}"
|
||||
>{{ srpfleet.fleet_srp_code }}</a>
|
||||
</div>
|
||||
<a class="label label-warning" href="{% url 'auth_srp_request_view' srpfleet.fleet_srp_code %}">{{ srpfleet.fleet_srp_code }}</a>
|
||||
{% else %}
|
||||
<div class="label label-danger">
|
||||
{% trans "Disabled" %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</th>
|
||||
<td class="text-center">
|
||||
{% for key,value in price_pair.items %}
|
||||
{% if key == srpfleet.id %}
|
||||
ISK: {{ value | intcomma }}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</td>
|
||||
<td class="text-center">ISK: {{ srpfleet.total_cost | intcomma }}</td>
|
||||
|
||||
<td class="text-center">
|
||||
{% if srpfleet.fleet_srp_status == "" %}
|
||||
@@ -89,26 +84,29 @@
|
||||
</div>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="text-center">
|
||||
<div class="label label-warning">{{ srpfleet.pending_requests }}</div>
|
||||
</td>
|
||||
<td class="text-center">
|
||||
|
||||
<a href="{% url 'auth_srp_fleet_view' srpfleet.id %}" class="btn btn-primary">
|
||||
<a href="{% url 'auth_srp_fleet_view' srpfleet.id %}" class="btn btn-primary" title="View">
|
||||
<span class="glyphicon glyphicon-eye-open"></span>
|
||||
</a>
|
||||
|
||||
{% if perms.auth.srp_management %}
|
||||
<a href="{% url 'auth_srp_fleet_edit_view' srpfleet.id %}" class="btn btn-info">
|
||||
<a href="{% url 'auth_srp_fleet_edit_view' srpfleet.id %}" class="btn btn-info" title="Edit">
|
||||
<span class="glyphicon glyphicon-pencil"></span>
|
||||
</a>
|
||||
|
||||
<a href="{% url 'auth_srp_fleet_remove' srpfleet.id %}" class="btn btn-danger">
|
||||
<a href="{% url 'auth_srp_fleet_remove' srpfleet.id %}" class="btn btn-danger" title="Remove">
|
||||
<span class="glyphicon glyphicon-trash"></span>
|
||||
</a>
|
||||
{% if srpfleet.fleet_srp_code %}
|
||||
<a href="{% url 'auth_srp_fleet_disable' srpfleet.id %}" class="btn btn-warning">
|
||||
<a href="{% url 'auth_srp_fleet_disable' srpfleet.id %}" class="btn btn-warning" title="Disable">
|
||||
<span class="glyphicon glyphicon-remove-sign"></span>
|
||||
</a>
|
||||
{% else %}
|
||||
<a href="{% url 'auth_srp_fleet_enable' srpfleet.id %}" class="btn btn-success">
|
||||
<a href="{% url 'auth_srp_fleet_enable' srpfleet.id %}" class="btn btn-success" title="Enable">
|
||||
<span class="glyphicon glyphicon-ok-sign"></span>
|
||||
</a>
|
||||
{% endif %}
|
||||
|
||||
@@ -12,11 +12,7 @@
|
||||
<meta name="description" content="">
|
||||
<meta name="author" content="">
|
||||
|
||||
{% if IS_CORP %}
|
||||
<title>{{ CORP_NAME }} - Login</title>
|
||||
{% else %}
|
||||
<title>{{ ALLIANCE_NAME }} - Login</title>
|
||||
{% endif %}
|
||||
<title>{{ SITE_NAME }} - Login</title>
|
||||
|
||||
<!-- Bootstrap Core CSS -->
|
||||
<link href="{% static 'css/bootstrap.min.css' %}" rel="stylesheet">
|
||||
|
||||
@@ -12,11 +12,7 @@
|
||||
<meta name="description" content="">
|
||||
<meta name="author" content="">
|
||||
|
||||
{% if IS_CORP %}
|
||||
<title>{{ CORP_NAME }} - Login</title>
|
||||
{% else %}
|
||||
<title>{{ ALLIANCE_NAME }} - Login</title>
|
||||
{% endif %}
|
||||
<title>{{ SITE_NAME }} - Login</title>
|
||||
<!-- Bootstrap Core CSS -->
|
||||
<link href="{% static 'css/bootstrap.min.css' %}" rel="stylesheet">
|
||||
<!-- Custom Fonts -->
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
<meta name="description" content="">
|
||||
<meta name="author" content="">
|
||||
|
||||
<title>{{ CORP_NAME }} - Login</title>
|
||||
<title>{{ SITE_NAME }} - Login</title>
|
||||
|
||||
<!-- Bootstrap Core CSS -->
|
||||
<link href="{% static 'css/bootstrap.min.css' %}" rel="stylesheet">
|
||||
|
||||
@@ -11,12 +11,7 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="description" content="">
|
||||
<meta name="author" content="">
|
||||
|
||||
{% if IS_CORP %}
|
||||
<title>{{ CORP_NAME }} - Login</title>
|
||||
{% else %}
|
||||
<title>{{ ALLIANCE_NAME }} - Login</title>
|
||||
{% endif %}
|
||||
<title>{{ SITE_NAME }} - Login</title>
|
||||
|
||||
<!-- Bootstrap Core CSS -->
|
||||
<link href="{% static 'css/bootstrap.min.css' %}" rel="stylesheet">
|
||||
|
||||
Reference in New Issue
Block a user