Files
test-auth/app/eve_api/tasks/character.py

204 lines
9.1 KiB
Python

from datetime import datetime, timedelta
from xml.dom import minidom
import logging
from django.utils.timezone import now, utc
from celery.task import task
from celery.task.sets import subtask
from gargoyle import gargoyle
from eve_proxy.exceptions import *
from eve_proxy.models import CachedDocument
from eve_api.api_exceptions import *
from eve_api.models import EVEPlayerCorporation, EVEPlayerCharacter, EVEPlayerCharacterRole, EVEPlayerCharacterSkill, EVESkill, EVEAccount, EVEPlayerCharacterEmploymentHistory
from eve_api.app_defines import *
from eve_api.utils import basic_xml_parse, basic_xml_parse_doc
@task()
def import_eve_character(character_id, key_id=None, callback=None, **kwargs):
"""
Imports a character from the API, providing a API key will populate
further details. Returns a single EVEPlayerCharacter object
"""
log = import_eve_character.get_logger()
try:
pchar = import_eve_character_func(character_id, key_id, log)
except APIAccessException, exc:
log.error('Error importing character - flagging for retry')
import_eve_character.retry(args=[character_id, key_id, callback], exc=exc, kwargs=kwargs)
if not pchar:
log.error('Error importing character %s' % character_id)
else:
if callback:
subtask(callback).delay(character=pchar.id)
else:
return pchar
@task()
def import_eve_characters(character_list, key_id=None, callback=None, **kwargs):
"""
Imports characters from the API, providing a API key will populate
further details. Returns a list of EVEPlayerCharacter objects
"""
log = import_eve_characters.get_logger()
try:
results = [import_eve_character_func(char, key_id, log) for char in character_list]
except APIAccessException, exc:
log.error('Error importing characters - flagging for retry')
import_eve_characters.retry(args=[character_list, key_id, callback], exc=exc, kwargs=kwargs)
if callback:
subtask(callback).delay(characters=results)
else:
return results
def import_eve_character_func(character_id, key_id=None, logger=logging.getLogger(__name__)):
if int(character_id) >= 3000000 and int(character_id) < 4000000:
# NPC character
return EVEPlayerCharacter.objects.get_or_create(pk=character_id)
try:
char_doc = CachedDocument.objects.api_query('/eve/CharacterInfo.xml.aspx', params={'characterID': character_id}, no_cache=False)
except DocumentRetrievalError, exc:
logger.error('Error retrieving CharacterInfo.xml.aspx for Character ID %s - %s' % (character_id, exc))
raise APIAccessException('Error retrieving CharacterInfo.xml.aspx for Character ID %s - %s' % (character_id, exc))
d = basic_xml_parse_doc(char_doc)['eveapi']
if 'error' in d:
logger.debug('EVE API Error enountered in API document')
return
values = d['result']
pchar, created = EVEPlayerCharacter.objects.get_or_create(id=character_id)
# Set the character's name, avoid oddities in the XML feed
if not values['characterName'] == {}:
pchar.name = values['characterName']
else:
pchar.name = ""
pchar.security_status = values['securityStatus']
# Set corporation and join date
corp, created = EVEPlayerCorporation.objects.get_or_create(pk=values['corporationID'])
from eve_api.tasks.corporation import import_corp_details
if created or not corp.name or corp.api_last_updated < (now() - timedelta(hours=12)):
import_corp_details.delay(values['corporationID'])
pchar.corporation = corp
pchar.corporation_date = datetime.strptime(values['corporationDate'], "%Y-%m-%d %H:%M:%S").replace(tzinfo=utc)
# Derrive Race value from the choices
for v in API_RACES_CHOICES:
val, race = v
if race == values['race']:
pchar.race = val
break
# Import employment history if its made available
if 'employmentHistory' in values:
reclist = pchar.employmenthistory.values_list('pk', flat=True)
for emp in values['employmentHistory']:
if not emp['recordID'] in reclist:
corp, created = EVEPlayerCorporation.objects.get_or_create(pk=emp['corporationID'])
if created:
import_corp_details.delay(emp['corporationID'])
startdate = datetime.strptime(emp['startDate'], "%Y-%m-%d %H:%M:%S").replace(tzinfo=utc)
eobj, created = EVEPlayerCharacterEmploymentHistory.objects.get_or_create(pk=emp['recordID'], corporation=corp, character=pchar, start_date=startdate)
# We've been passed a Key ID, try and work with it
if key_id:
try:
acc = EVEAccount.objects.get(pk=key_id)
except EVEAccount.DoesNotExist:
acc = None
else:
acc = None
# If we have a key, call CharSheet
if acc and acc.has_access(3) and not acc.api_keytype == API_KEYTYPE_CORPORATION:
if gargoyle.is_active('eve-cak') and acc.is_cak:
auth_params = {'keyid': acc.api_user_id, 'vcode': acc.api_key, 'characterid': character_id }
else:
auth_params = {'userID': acc.api_user_id, 'apiKey': acc.api_key, 'characterID': character_id }
try:
char_doc = CachedDocument.objects.api_query('/char/CharacterSheet.xml.aspx', params=auth_params, no_cache=False)
except DocumentRetrievalError, exc:
logger.error('Error retrieving CharacterSheet.xml.aspx for User ID %s, Character ID %s - %s' % (acc.pk, character_id, exc))
raise APIAccessException('Error retrieving CharacterSheet.xml.aspx for User ID %s, Character ID %s - %s' % (acc.pk, character_id, exc.value))
doc = basic_xml_parse_doc(char_doc)['eveapi']
if not 'error' in doc:
values = doc['result']
pchar.name = values['name']
pchar.balance = values['balance']
pchar.attrib_intelligence = values['attributes']['intelligence']
pchar.attrib_charisma = values['attributes']['charisma']
pchar.attrib_perception = values['attributes']['perception']
pchar.attrib_willpower = values['attributes']['willpower']
pchar.attrib_memory = values['attributes']['memory']
# Process the character's skills
pchar.total_sp = 0
for skill in values.get('skills', None):
skillobj, created = EVESkill.objects.get_or_create(pk=skill['typeID'])
charskillobj, created = EVEPlayerCharacterSkill.objects.get_or_create(skill=skillobj, character=pchar)
if created or not charskillobj.level == int(skill['level']) or not charskillobj.skillpoints == int(skill['skillpoints']):
charskillobj.level = int(skill['level'])
charskillobj.skillpoints = int(skill['skillpoints'])
charskillobj.save()
pchar.total_sp = pchar.total_sp + int(skill['skillpoints'])
if acc.has_access(18):
try:
skillqueue = CachedDocument.objects.api_query('/char/SkillInTraining.xml.aspx', params=auth_params, no_cache=False)
except DocumentRetrievalError, exc:
logger.error('Error retrieving SkillInTraining.xml.aspx for User ID %s, Character ID %s - %s' % (key_id, character_id, exc))
else:
queuedoc = basic_xml_parse_doc(skillqueue)
if not 'error' in queuedoc['eveapi'] and 'result' in queuedoc['eveapi']:
queuedoc = queuedoc['eveapi']['result']
EVEPlayerCharacterSkill.objects.filter(character=pchar).update(in_training=0)
if int(queuedoc['skillInTraining']):
skillobj, created = EVESkill.objects.get_or_create(pk=queuedoc['trainingTypeID'])
charskillobj, created = EVEPlayerCharacterSkill.objects.get_or_create(skill=skillobj, character=pchar)
charskillobj.in_training = queuedoc['trainingToLevel']
charskillobj.save()
else:
EVEPlayerCharacterSkill.objects.filter(character=pchar).update(in_training=0)
# Process the character's roles
pchar.roles.clear()
roles = values.get('corporationRoles', None)
if roles and len(roles):
for r in roles:
role, created = EVEPlayerCharacterRole.objects.get_or_create(roleid=r['roleID'], name=r['roleName'])
pchar.roles.add(role)
if values['gender'] == 'Male':
pchar.gender = API_GENDER_MALE
else:
pchar.gender = API_GENDER_FEMALE
pchar.api_last_updated = now()
pchar.save()
if acc:
if not pchar.id in acc.characters.all().values_list('id', flat=True):
acc.characters.add(pchar)
if pchar.director and acc.api_keytype in [API_KEYTYPE_FULL, API_KEYTYPE_CORPORATION]:
from eve_api.tasks.corporation import import_corp_members
import_corp_members.delay(key_id=acc.pk, character_id=pchar.id)
return pchar