diff --git a/eveonline/managers.py b/eveonline/managers.py index 214433e4..e8ee3d4b 100644 --- a/eveonline/managers.py +++ b/eveonline/managers.py @@ -3,17 +3,35 @@ from eveonline.models import EveCharacter from eveonline.models import EveApiKeyPair from eveonline.models import EveAllianceInfo from eveonline.models import EveCorporationInfo - +from eveonline.providers import eve_adapter_factory from services.managers.eve_api_manager import EveApiManager import logging logger = logging.getLogger(__name__) +adapter = eve_adapter_factory() class EveManager: def __init__(self): pass + @staticmethod + def create_character(id, user, api_id): + return EveManager.create_character_obj(adapter.get_character(id), user, api_id) + + @staticmethod + def create_character_obj(character, user, api_id): + EveCharacter.objects.create( + character_id = character.id, + character_name = character.name, + corporation_id = character.corp.id, + corporation_name = character.corp.name, + alliance_id = character.alliance.id, + alliance_name = character.alliance.name, + user = user, + api_id = api_id, + ) + @staticmethod def create_character(character_id, character_name, corporation_id, corporation_name, corporation_ticker, alliance_id, @@ -50,6 +68,20 @@ class EveManager: chars.result[char]['alliance']['name'], user, api_id) + @staticmethod + def update_character(id): + return EveManager.update_character_obj(adapter.get_character(id)) + + @staticmethod + def update_character_obj(char): + model = EveCharacter.objects.get(character_id=char.id) + model.character_name = char.name + model.corporation_id = char.corp.id + model.corporation_name = char.corp.name + model.alliance_id = char.alliance.id + model.alliance_name = char.alliance.name + model.save() + @staticmethod def update_characters_from_list(chars): logger.debug("Updating characters from list: %s" % chars.result) @@ -83,64 +115,74 @@ class EveManager: logger.warn("Attempting to create existing api keypair with id %s" % api_id) @staticmethod - def create_alliance_info(alliance_id, alliance_name, alliance_ticker, alliance_executor_corp_id, - alliance_member_count, is_blue): - logger.debug("Creating alliance info for alliance %s id %s" % (alliance_name, alliance_id)) - if not EveManager.check_if_alliance_exists_by_id(alliance_id): - alliance_info = EveAllianceInfo() - alliance_info.alliance_id = alliance_id - alliance_info.alliance_name = alliance_name - alliance_info.alliance_ticker = alliance_ticker - alliance_info.executor_corp_id = alliance_executor_corp_id - alliance_info.member_count = alliance_member_count - alliance_info.is_blue = is_blue - alliance_info.save() - logger.info("Created alliance model for %s" % alliance_info) - else: - logger.warn("Attempting to create existing alliance model with id %s" % alliance_id) + def create_alliance(id, is_blue=False): + return EveManager.create_alliance_obj(adapter.get_alliance(id), is_blue=is_blue) @staticmethod - def update_alliance_info(alliance_id, alliance_executor_corp_id, alliance_member_count, is_blue): - logger.debug("Updating alliance model with id %s" % alliance_id) - if EveManager.check_if_alliance_exists_by_id(alliance_id): - alliance_info = EveAllianceInfo.objects.get(alliance_id=alliance_id) - alliance_info.executor_corp_id = alliance_executor_corp_id - alliance_info.member_count = alliance_member_count - alliance_info.is_blue = is_blue - alliance_info.save() - logger.debug("Updated alliance model %s" % alliance_info) - else: - logger.warn("Attempting to update non-existing alliance model with id %s" % alliance_id) + def create_alliance_obj(alliance, is_blue=False): + EveAllianceInfo.objects.create( + alliance_id = alliance.id, + alliance_name = alliance.name, + alliance_ticker = alliance.ticker, + executor_corp_id = alliance.executor_corp_id, + is_blue = is_blue, + ) @staticmethod - def create_corporation_info(corp_id, corp_name, corp_ticker, corp_member_count, is_blue, alliance): - logger.debug("Creating corp info for corp %s id %s" % (corp_name, corp_id)) - if not EveManager.check_if_corporation_exists_by_id(corp_id): - corp_info = EveCorporationInfo() - corp_info.corporation_id = corp_id - corp_info.corporation_name = corp_name - corp_info.corporation_ticker = corp_ticker - corp_info.member_count = corp_member_count - corp_info.is_blue = is_blue - if alliance: - corp_info.alliance = alliance - corp_info.save() - logger.info("Created corp model for %s" % corp_info) - else: - logger.warn("Attempting to create existing corp model with id %s" % corp_id) + def update_alliance(id, is_blue=None): + return EveManager.update_alliance_obj(adapter.get_alliance(id), is_blue=is_blue) @staticmethod - def update_corporation_info(corp_id, corp_member_count, alliance, is_blue): - logger.debug("Updating corp model with id %s" % corp_id) - if EveManager.check_if_corporation_exists_by_id(corp_id): - corp_info = EveCorporationInfo.objects.get(corporation_id=corp_id) - corp_info.member_count = corp_member_count - corp_info.alliance = alliance - corp_info.is_blue = is_blue - corp_info.save() - logger.debug("Updated corp model %s" % corp_info) - else: - logger.warn("Attempting to update non-existant corp model with id %s" % corp_id) + def update_alliance_obj(alliance, is_blue=None): + model = EveAllianceInfo.objects.get(alliance_id=alliance.id) + model.executor_corp_id = alliance.executor_corp_id + model.is_blue = model.is_blue if is_blue == None else is_blue + model.save() + + @staticmethod + def populate_alliance(id): + alliance_model = EveAllianceInfo.objects.get(alliance_id=id) + alliance = adapter.get_alliance(id) + for corp_id in alliance.corp_ids: + if not EveCorporationInfo.objects.filter(corporation_id=corp_id).exists(): + EveManager.create_corporation(corp_id, is_blue=alliance_model.is_blue) + EveCorporationInfo.objects.filter(corporation_id__in=alliance.corp_ids).update(alliance=alliance_model) + EveCorporationInfo.objects.filter(alliance=alliance_model).exclude(corporation_id__in=alliance.corp_ids).update(alliance=None) + + + @staticmethod + def create_corporation(id, is_blue=False): + return EveManager.create_corporation_obj(adapter.get_corp(id), is_blue=is_blue) + + @staticmethod + def create_corporation_obj(corp, is_blue=False): + try: + alliance = EveAllianceInfo.objects.get(alliance_id=corp.alliance_id) + except EveAllianceInfo.DoesNotExist: + alliance = None + EveCorporationInfo.objects.create( + corporation_id = corp.id, + corporation_name = corp.name, + corporation_ticker = corp.ticker, + member_count = corp.members, + alliance = alliance, + is_blue = is_blue, + ) + + @staticmethod + def update_corporation(id, is_blue=None): + return EveManager.update_corporation_obj(adapter.get_corp(id), is_blue=is_blue) + + @staticmethod + def update_corporation_obj(corp, is_blue=None): + model = EveCorporationInfo.objects.get(corporation_id=corp.id) + model.member_count = corp.members + try: + model.alliance = EveAllianceInfo.objects.get(alliance_id=corp.alliance_id) + except EveAllianceInfo.DoesNotExist: + model.alliance = None + model.is_blue = model.is_blue if is_blue == None else is_blue + model.save() @staticmethod def get_api_key_pairs(user): diff --git a/eveonline/providers.py b/eveonline/providers.py index c6c2e940..be71244a 100644 --- a/eveonline/providers.py +++ b/eveonline/providers.py @@ -1,8 +1,19 @@ from django.utils.encoding import python_2_unicode_compatible from esi.clients import esi_client_factory from django.conf import settings +from bravado.exception import HTTPNotFound, HTTPUnprocessableEntity import evelink +@python_2_unicode_compatible +class ObjectNotFound(Exception): + def __init__(self, id, type): + self.id = id + self.type = type + + def __str__(self): + return '%s with ID %s not found.' % (self.type, self.id) + + @python_2_unicode_compatible class Entity(object): def __init__(self, id, name): @@ -43,11 +54,12 @@ class Corporation(Entity): class Alliance(Entity): - def __init__(self, provider, id, name, ticker, corp_ids): + def __init__(self, provider, id, name, ticker, corp_ids, executor_corp_id): super(Alliance, self).__init__(id, name) self.provider = provider self.ticker = ticker self.corp_ids = corp_ids + self.executor_corp_id = executor_corp_id def corp(self, id): assert id in self.corp_ids @@ -57,6 +69,10 @@ class Alliance(Entity): def corps(self): return sorted([self.corp(id) for id in self.corp_ids], key=lambda x: x.name) + @property + def executor_corp(self): + return self.provider.get_corp(self.executor_corp_id) + class Character(Entity): def __init__(self, provider, id, name, corp_id, alliance_id): @@ -105,42 +121,52 @@ class EveSwaggerProvider(EveProvider): def __str__(self): return 'esi' - def get_alliance(self, alliance_id): - 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, - alliance_id, - data['alliance_name'], - data['ticker'], - corps, - ) - return model + def get_alliance(self, id): + try: + data = self.client.Alliance.get_alliances_alliance_id(alliance_id=id).result() + corps = self.client.Alliance.get_alliances_alliance_id_corporations(alliance_id=id).result() + model = Alliance( + self.adapter, + id, + data['alliance_name'], + data['ticker'], + corps, + data['executor_corp'], + ) + return model + except HTTPNotFound: + raise ObjectNotFound(id, 'alliance') - def get_corp(self, corp_id): - data = self.client.Corporation.get_corporations_corporation_id(corporation_id=corp_id).result() - model = Corporation( - self.adapter, - corp_id, - data['corporation_name'], - data['ticker'], - data['ceo_id'], - data['member_count'], - data['alliance_id'] if 'alliance_id' in data else None, - ) - return model + def get_corp(self, id): + try: + data = self.client.Corporation.get_corporations_corporation_id(corporation_id=id).result() + model = Corporation( + self.adapter, + id, + data['corporation_name'], + data['ticker'], + data['ceo_id'], + data['member_count'], + data['alliance_id'] if 'alliance_id' in data else None, + ) + return model + except HTTPNotFound: + raise ObjectNotFound(id, 'corporation') - def get_character(self, character_id): - 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, - character_id, - data['name'], - data['corporation_id'], - alliance_id, - ) - return model + def get_character(self, id): + try: + data = self.client.Character.get_characters_character_id(character_id=id).result() + alliance_id = self.adapter.get_corp(data['corporation_id']).alliance_id + model = Character( + self.adapter, + id, + data['name'], + data['corporation_id'], + alliance_id, + ) + return model + except (HTTPNotFound, HTTPUnprocessableEntity): + raise ObjectNotFound(id, 'character') @python_2_unicode_compatible @@ -158,19 +184,28 @@ class EveXmlProvider(EveProvider): def get_alliance(self, id): api = evelink.eve.EVE(api=self.api) alliances = api.alliances().result - results = alliances[int(id)] + try: + results = alliances[int(id)] + except KeyError: + raise ObjectNotFound(id, 'alliance') model = Alliance( self.adapter, id, results['name'], results['ticker'], results['member_corps'], + results['executor_id'], ) return model def get_corp(self, id): api = evelink.corp.Corp(api=self.api) - corpinfo = api.corporation_sheet(corp_id=int(id)).result + try: + corpinfo = api.corporation_sheet(corp_id=int(id)).result + except evelink.api.APIError as e: + if int(e.code) == 523: + raise ObjectNotFound(id, 'corporation') + raise e model = Corporation( self.adapter, id, @@ -184,7 +219,12 @@ class EveXmlProvider(EveProvider): def get_character(self, id): api = evelink.eve.EVE(api=self.api) - charinfo = api.character_info_from_id(id).result + try: + charinfo = api.character_info_from_id(id).result + except evelink.api.APIError as e: + if int(e.code) == 105: + raise ObjectNotFound(id, 'character') + raise e model = Character( self.adapter, id, diff --git a/eveonline/tasks.py b/eveonline/tasks.py index 894e2dfc..8d98bbea 100644 --- a/eveonline/tasks.py +++ b/eveonline/tasks.py @@ -12,6 +12,7 @@ from services.managers.eve_api_manager import EveApiManager from eveonline.models import EveCharacter from eveonline.models import EveCorporationInfo from eveonline.models import EveAllianceInfo +from eveonline.providers import eve_adapter_factory from authentication.tasks import set_state import logging import evelink @@ -105,65 +106,14 @@ def run_api_refresh(): refresh_user_apis.delay(u) -def populate_alliance(id, blue=False): - logger.debug("Populating alliance model with id %s blue %s" % (id, blue)) - alliance_info = EveApiManager.get_alliance_information(id) - - if not alliance_info: - raise ValueError("Supplied alliance id %s is invalid" % id) - - if not EveAllianceInfo.objects.filter(alliance_id=id).exists(): - EveManager.create_alliance_info(alliance_info['id'], alliance_info['name'], alliance_info['ticker'], - alliance_info['executor_id'], alliance_info['member_count'], blue) - alliance = EveAllianceInfo.objects.get(alliance_id=id) - for member_corp in alliance_info['member_corps']: - if EveCorporationInfo.objects.filter(corporation_id=member_corp).exists(): - corp = EveCorporationInfo.objects.get(corporation_id=member_corp) - if corp.alliance != alliance: - corp.alliance = alliance - corp.save() - else: - logger.info("Creating new alliance member corp id %s" % member_corp) - corpinfo = EveApiManager.get_corporation_information(member_corp) - EveManager.create_corporation_info(corpinfo['id'], corpinfo['name'], corpinfo['ticker'], - corpinfo['members']['current'], blue, alliance) - +@task +def update_corp(id): + EveManager.update_corporation(id) @task def update_alliance(id): - alliance = EveAllianceInfo.objects.get(alliance_id=id) - corps = EveCorporationInfo.objects.filter(alliance=alliance) - logger.debug("Updating alliance %s with %s member corps" % (alliance, len(corps))) - allianceinfo = EveApiManager.get_alliance_information(alliance.alliance_id) - if allianceinfo: - EveManager.update_alliance_info(allianceinfo['id'], allianceinfo['executor_id'], - allianceinfo['member_count'], alliance.is_blue) - for corp in corps: - if corp.corporation_id in allianceinfo['member_corps'] is False: - logger.info("Corp %s no longer in alliance %s" % (corp, alliance)) - corp.alliance = None - corp.save() - populate_alliance(alliance.alliance_id, blue=alliance.is_blue) - elif EveApiManager.check_if_alliance_exists(alliance.alliance_id) is False: - logger.info("Alliance %s has closed. Deleting model" % alliance) - alliance.delete() - - -@task -def update_corp(id): - corp = EveCorporationInfo.objects.get(corporation_id=id) - logger.debug("Updating corp %s" % corp) - corpinfo = EveApiManager.get_corporation_information(corp.corporation_id) - if corpinfo: - alliance = None - if EveAllianceInfo.objects.filter(alliance_id=corpinfo['alliance']['id']).exists(): - alliance = EveAllianceInfo.objects.get(alliance_id=corpinfo['alliance']['id']) - EveManager.update_corporation_info(corpinfo['id'], corpinfo['members']['current'], alliance, corp.is_blue) - elif EveApiManager.check_if_corp_exists(corp.corporation_id) is False: - logger.info("Corp %s has closed. Deleting model" % corp) - corp.delete() - - # Run Every 2 hours + EveManager.update_alliance(id) + EveManager.populate_alliance(id) @periodic_task(run_every=crontab(minute=0, hour="*/2")) @@ -172,80 +122,36 @@ def run_corp_update(): logger.warn("Aborted updating corp and alliance models: API server unreachable") return standing_level = 'alliance' + alliance_id = settings.ALLIANCE_ID + + # get corp info for owning corp if required + if settings.IS_CORP: + standing_level = 'corp' + if EveCorporationInfo.objects.filter(corporation_id=settings.CORP_ID).exists(): + update_corp(settings.CORP_ID) + else: + EveManager.create_corporation(settings.CORP_ID) + + alliance_id = eve_adapter_factory().get_corp(settings.CORP_ID).alliance_id + + # get and create alliance info for owning alliance if required + if alliance_id: + if EveAllianceInfo.objects.filter(alliance_id=alliance_id).exists(): + logger.debug("Updating existing owner alliance model with id %s" % alliance_id) + update_alliance(alliance_id) + else: + EveManager.create_alliance(id) + EveManager.populate_alliance(id) + + # update existing corp models + for corp in EveCorporationInfo.objects.all(): + update_corp.delay(corp.corporation_id) + + # update existing alliance models + for alliance in EveAllianceInfo.objects.all(): + update_alliance.delay(alliance.alliance_id) + try: - # get corp info for owning corp if required - ownercorpinfo = {} - if settings.IS_CORP: - standing_level = 'corp' - logger.debug("Getting information for owning corp with id %s" % settings.CORP_ID) - ownercorpinfo = EveApiManager.get_corporation_information(settings.CORP_ID) - if not ownercorpinfo: - logger.error("Failed to retrieve corp info for owning corp id %s - bad corp id?" % settings.CORP_ID) - return - - # check if we need to update an alliance model - alliance_id = '' - if ownercorpinfo and ownercorpinfo['alliance']['id']: - alliance_id = ownercorpinfo['alliance']['id'] - elif settings.IS_CORP is False: - alliance_id = settings.ALLIANCE_ID - - # get and create alliance info for owning alliance if required - alliance = None - if alliance_id: - logger.debug("Getting information for owning alliance with id %s" % alliance_id) - ownerallianceinfo = EveApiManager.get_alliance_information(alliance_id) - if not ownerallianceinfo: - logger.error("Failed to retrieve corp info for owning alliance id %s - bad alliance id?" % alliance_id) - return - if EveAllianceInfo.objects.filter(alliance_id=ownerallianceinfo['id']).exists(): - logger.debug("Updating existing owner alliance model with id %s" % alliance_id) - EveManager.update_alliance_info(ownerallianceinfo['id'], ownerallianceinfo['executor_id'], - ownerallianceinfo['member_count'], False) - else: - populate_alliance(alliance_id) - alliance = EveAllianceInfo.objects.get(alliance_id=alliance_id) - - # create corp info for owning corp if required - if ownercorpinfo: - if EveCorporationInfo.objects.filter(corporation_id=ownercorpinfo['id']).exists(): - logger.debug("Updating existing owner corp model with id %s" % ownercorpinfo['id']) - EveManager.update_corporation_info(ownercorpinfo['id'], ownercorpinfo['members']['current'], alliance, - False) - else: - logger.info("Creating model for owning corp with id %s" % ownercorpinfo['id']) - EveManager.create_corporation_info(ownercorpinfo['id'], ownercorpinfo['name'], ownercorpinfo['ticker'], - ownercorpinfo['members']['current'], False, alliance) - - # validate and create corp models for member corps of owning alliance - if alliance: - current_corps = EveCorporationInfo.objects.filter(alliance=alliance) - for corp in current_corps: - if corp.corporation_id in ownerallianceinfo['member_corps'] is False: - logger.info("Corp %s is no longer in owning alliance %s - updating model." % (corp, alliance)) - corp.alliance = None - corp.save() - for member_corp in ownerallianceinfo['member_corps']: - if EveCorporationInfo.objects.filter(corporation_id=member_corp).exists(): - corp = EveCorporationInfo.objects.get(corporation_id=member_corp) - if corp.alliance == alliance is not True: - logger.info("Associating corp %s with owning alliance %s" % (corp, alliance)) - corp.alliance = alliance - corp.save() - else: - corpinfo = EveApiManager.get_corporation_information(member_corp) - logger.info("Creating model for owning alliance member corp with id %s" % corpinfo['id']) - EveManager.create_corporation_info(corpinfo['id'], corpinfo['name'], corpinfo['ticker'], - corpinfo['members']['current'], False, alliance) - - # update existing corp models - for corp in EveCorporationInfo.objects.all(): - update_corp.delay(corp.corporation_id) - - # update existing alliance models - for alliance in EveAllianceInfo.objects.all(): - update_alliance.delay(alliance.alliance_id) - # create standings standings = EveApiManager.get_corp_standings() if standings: @@ -262,7 +168,7 @@ def run_corp_update(): alliance.is_blue = True alliance.save() else: - populate_alliance(standing, blue=True) + EveManager.create_alliance(standing, blue=True) elif EveApiManager.check_if_id_is_corp(standing): logger.debug("Standing %s is a corp" % standing) if EveCorporationInfo.objects.filter(corporation_id=standing).exists(): @@ -273,13 +179,7 @@ def run_corp_update(): corp.save() else: logger.info("Creating model for blue corp with id %s" % standing) - corpinfo = EveApiManager.get_corporation_information(standing) - corp_alliance = None - if EveAllianceInfo.objects.filter(alliance_id=corpinfo['alliance']['id']).exists(): - logger.debug("New corp model for standing %s has existing alliance model" % standing) - corp_alliance = EveAllianceInfo.objects.get(alliance_id=corpinfo['alliance']['id']) - EveManager.create_corporation_info(corpinfo['id'], corpinfo['name'], corpinfo['ticker'], - corpinfo['members']['current'], True, corp_alliance) + EveManager.create_corporation(standing, blue=True) # update alliance standings for alliance in EveAllianceInfo.objects.filter(is_blue=True): @@ -310,43 +210,43 @@ def run_corp_update(): logger.info("Corp %s is no longer blue" % corp) corp.is_blue = False corp.save() + except evelink.api.APIError as e: + logger.error("Model update failed with error code %s" % e.code) - # delete unnecessary alliance models - for alliance in EveAllianceInfo.objects.filter(is_blue=False): - logger.debug("Checking to delete alliance %s" % alliance) - if not settings.IS_CORP: - if not alliance.alliance_id == settings.ALLIANCE_ID: - logger.info("Deleting unnecessary alliance model %s" % alliance) - alliance.delete() + # delete unnecessary alliance models + for alliance in EveAllianceInfo.objects.filter(is_blue=False): + logger.debug("Checking to delete alliance %s" % alliance) + if not settings.IS_CORP: + if not alliance.alliance_id == settings.ALLIANCE_ID: + logger.info("Deleting unnecessary alliance model %s" % alliance) + alliance.delete() + else: + if not alliance.evecorporationinfo_set.filter(corporation_id=settings.CORP_ID).exists(): + logger.info("Deleting unnecessary alliance model %s" % alliance) + alliance.delete() + + # delete unnecessary corp models + for corp in EveCorporationInfo.objects.filter(is_blue=False): + logger.debug("Checking to delete corp %s" % corp) + if not settings.IS_CORP: + if corp.alliance: + logger.debug("Corp %s has alliance %s" % (corp, corp.alliance)) + if not corp.alliance.alliance_id == settings.ALLIANCE_ID: + logger.info("Deleting unnecessary corp model %s" % corp) + corp.delete() else: - if not alliance.evecorporationinfo_set.filter(corporation_id=settings.CORP_ID).exists(): - logger.info("Deleting unnecessary alliance model %s" % alliance) - alliance.delete() - - # delete unnecessary corp models - for corp in EveCorporationInfo.objects.filter(is_blue=False): - logger.debug("Checking to delete corp %s" % corp) - if not settings.IS_CORP: + logger.info("Deleting unnecessary corp model %s" % corp) + corp.delete() + else: + if corp.corporation_id != settings.CORP_ID: + logger.debug("Corp %s is not owning corp" % corp) if corp.alliance: logger.debug("Corp %s has alliance %s" % (corp, corp.alliance)) - if not corp.alliance.alliance_id == settings.ALLIANCE_ID: + if not corp.alliance.evecorporationinfo_set.filter(corporation_id=settings.CORP_ID).exists(): logger.info("Deleting unnecessary corp model %s" % corp) corp.delete() else: logger.info("Deleting unnecessary corp model %s" % corp) corp.delete() else: - if corp.corporation_id != settings.CORP_ID: - logger.debug("Corp %s is not owning corp" % corp) - if corp.alliance: - logger.debug("Corp %s has alliance %s" % (corp, corp.alliance)) - if not corp.alliance.evecorporationinfo_set.filter(corporation_id=settings.CORP_ID).exists(): - logger.info("Deleting unnecessary corp model %s" % corp) - corp.delete() - else: - logger.info("Deleting unnecessary corp model %s" % corp) - corp.delete() - else: - logger.debug("Corp %s is owning corp" % corp) - except evelink.api.APIError as e: - logger.error("Model update failed with error code %s" % e.code) + logger.debug("Corp %s is owning corp" % corp)