allianceauth/fleetup/managers.py
Basraah 5db340c64a Fleet-up cleanup (#798)
Add caching and better error handling
Move fleetup templates into fleetup app
Move fleetup urls into fleetup app
Fix button overflow and url
Add manager unit tests
Fix python3 compatibility
2017-06-04 18:35:23 -04:00

185 lines
7.3 KiB
Python

from __future__ import unicode_literals
from django.conf import settings
from django.core.cache import cache
from datetime import datetime
import logging
import requests
import hashlib
logger = logging.getLogger(__name__)
class FleetUpManager:
APP_KEY = settings.FLEETUP_APP_KEY
USER_ID = settings.FLEETUP_USER_ID
API_ID = settings.FLEETUP_API_ID
GROUP_ID = settings.FLEETUP_GROUP_ID
BASE_URL = "http://api.fleet-up.com/Api.svc/{}/{}/{}".format(APP_KEY, USER_ID, API_ID)
def __init__(self):
pass
@classmethod
def _request_cache_key(cls, url):
h = hashlib.sha1()
h.update(url.encode('utf-8'))
return 'FLEETUP_ENDPOINT_' + h.hexdigest()
@classmethod
def _cache_until_seconds(cls, cache_until_json):
# Format comes in like "/Date(1493896236163)/"
try:
epoch_ms = int(cache_until_json[6:-2])
cache_delta = datetime.fromtimestamp(epoch_ms/1000) - datetime.now()
cache_delta_seconds = cache_delta.total_seconds()
if cache_delta_seconds < 0:
return 0
elif cache_delta_seconds > 3600:
return 3600
else:
return cache_delta_seconds
except TypeError:
logger.debug("Couldn't convert CachedUntil time, defaulting to 600 seconds")
return 600
@classmethod
def get_endpoint(cls, url):
try:
cache_key = cls._request_cache_key(url)
cached = cache.get(cache_key)
if cached:
return cached
r = requests.get(url)
r.raise_for_status()
json = r.json()
if json['Success']:
cache.set(cache_key, json, cls._cache_until_seconds(json['CachedUntilUTC']))
return json
except requests.exceptions.ConnectionError:
logger.warn("Can't connect to Fleet-Up API, is it offline?!")
except requests.HTTPError:
logger.exception("Error accessing Fleetup API")
return None
@classmethod
def get_fleetup_members(cls):
url = "{}/GroupCharacters/{}".format(cls.BASE_URL, cls.GROUP_ID)
try:
fmembers = cls.get_endpoint(url)
if not fmembers:
return None
return {row["UserId"]: {"user_id": row["UserId"],
"char_name": row["EveCharName"],
"char_id": row["EveCharId"],
"corporation": row["Corporation"]} for row in fmembers["Data"]}
except (ValueError, UnicodeDecodeError, TypeError):
logger.debug("No fleetup members retrieved.")
return {}
@classmethod
def get_fleetup_operations(cls):
url = "{}/Operations/{}".format(cls.BASE_URL, cls.GROUP_ID)
foperations = cls.get_endpoint(url)
if foperations is None:
return None
return {row["StartString"]: {"subject": row["Subject"],
"start": datetime.strptime(row["StartString"], "%Y-%m-%d %H:%M:%S"),
"end": datetime.strptime(row["EndString"], "%Y-%m-%d %H:%M:%S"),
"operation_id": row["OperationId"],
"location": row["Location"],
"location_info": row["LocationInfo"],
"details": row["Details"],
"url": row["Url"],
"doctrine": row["Doctrines"],
"organizer": row["Organizer"]} for row in foperations["Data"]}
@classmethod
def get_fleetup_timers(cls):
url = "{}/Timers/{}".format(cls.BASE_URL, cls.GROUP_ID)
ftimers = cls.get_endpoint(url)
if not ftimers:
return None
return {row["ExpiresString"]: {"solarsystem": row["SolarSystem"],
"planet": row["Planet"],
"moon": row["Moon"],
"owner": row["Owner"],
"type": row["Type"],
"timer_type": row["TimerType"],
"expires": (datetime.strptime(row["ExpiresString"], "%Y-%m-%d %H:%M:%S")),
"notes": row["Notes"]} for row in ftimers["Data"]}
return {}
@classmethod
def get_fleetup_doctrines(cls):
url = "{}/Doctrines/{}".format(cls.BASE_URL, cls.GROUP_ID)
fdoctrines = cls.get_endpoint(url)
if not fdoctrines:
return None
return {"fleetup_doctrines": fdoctrines["Data"]}
@classmethod
def get_fleetup_doctrine(cls, doctrinenumber):
url = "{}/DoctrineFittings/{}".format(cls.BASE_URL, doctrinenumber)
fdoctrine = cls.get_endpoint(url)
if not fdoctrine:
return None
return {"fitting_doctrine": fdoctrine}
@classmethod
def get_fleetup_fittings(cls):
url = "{}/Fittings/{}".format(cls.BASE_URL, cls.GROUP_ID)
ffittings = cls.get_endpoint(url)
if not ffittings:
return None
return {row["FittingId"]: {"fitting_id": row["FittingId"],
"name": row["Name"],
"icon_id": row["EveTypeId"],
"hull": row["HullType"],
"shiptype": row["ShipType"],
"estimated": row["EstPrice"],
"faction": row["Faction"],
"categories": row["Categories"],
"last_update": (
datetime.strptime(row["LastUpdatedString"], "%Y-%m-%d %H:%M:%S"))} for row in
ffittings["Data"]}
@classmethod
def get_fleetup_fitting(cls, fittingnumber):
url = "{}/Fitting/{}".format(cls.BASE_URL, fittingnumber)
try:
ffitting = cls.get_endpoint(url)
if not ffitting:
return None
return {"fitting_data": ffitting["Data"]}
except KeyError:
logger.warn("Failed to retrieve fleetup fitting number %s" % fittingnumber)
return {"fitting_data": {}}
@classmethod
def get_fleetup_doctrineid(cls, fittingnumber):
url = "{}/Fitting/{}".format(cls.BASE_URL, fittingnumber)
try:
fdoctrineid = cls.get_endpoint(url)
if not fdoctrineid:
return None
return fdoctrineid['Data']['Doctrines'][0]['DoctrineId']
except (KeyError, IndexError):
logger.debug("Fleetup fitting number %s not in a doctrine." % fittingnumber)
return {}
@classmethod
def get_fleetup_fitting_eft(cls, fittingnumber):
url = "{}/Fitting/{}/eft".format(cls.BASE_URL, fittingnumber)
try:
ffittingeft = cls.get_endpoint(url)
if not ffittingeft:
return None
return {"fitting_eft": ffittingeft["Data"]["FittingData"]}
except KeyError:
logger.warn("Fleetup fitting eft not found for fitting number %s" % fittingnumber)
return {"fitting_eft": {}}