def post(self, request): try: character = request.user.characters.get( character_id=int(request.POST['character_id'])) except EveUser.DoesNotExist: return HttpResponse(status=403) ESI.request('post_ui_openwindow_contract', client=character.get_client(), contract_id=int(request.POST['contract_id'])) return HttpResponse(status=204)
def generate_route(self, character, route): if settings.GENERATE_ROUTE: for i in range(len(route['esi'])): if i == 0: ESI.request('post_ui_autopilot_waypoint', client=character.get_client(), add_to_beginning=False, clear_other_waypoints=True, destination_id=route['esi'][i]) else: ESI.request('post_ui_autopilot_waypoint', client=character.get_client(), add_to_beginning=False, clear_other_waypoints=False, destination_id=route['esi'][i])
def send_enqueued_mails(): for m in MailSender.objects.all(): client = m.character.get_client() while True: mails = ( Mail.objects .filter(Q(sender__isnull=True) | Q(sender=m)) .order_by('-priority', 'created') ) if not mails.exists(): break mail = mails[0] req = ESI.request( 'post_characters_character_id_mail', client=client, character_id=m.character.character_id, mail={ "approved_cost": 0, "body": mail.body, "recipients": [ r.as_recipient_dict() for r in mail.recipients.all() ], "subject": mail.subject } ) if req.status == 201: mail.delete() else: break
def structure_search(self, character, known_structures): logger.debug(f"Beginning deep search with character {character}.") structure_ids = [] # Search /characters/{character_id}/search/ for the "»" character and some letters # and add everything to a list for item in search_list: structure_ids.extend( ESI.request('get_characters_character_id_search', client=character.get_client(), character_id=character.character_id, categories=['structure'], search=search_string + item).data.structure) # Log the length of the structure list after every iteration logger.debug( f"List complete with {structure_ids} structure IDs. Removing duplicates." ) structure_ids = list(set(structure_ids)) logger.debug(f"Duplicates removed. New total: {structure_ids}") # Remove any structures we've already found structure_list = [ x for x in structure_ids if x not in known_structures ] logger.debug(f"Total structures to index: {structure_list}") # Get information about each structure structure_info = self.structure_parse(character, structure_list) return structure_list, structure_info
def read_assets_for_character(character): valid_module_types = { x for x in ModuleType.objects.values_list('id', flat=True) } try: items = ESI.request('get_characters_character_id_assets', client=character.get_client(), multi_page=True, character_id=character.character_id) except EsiException as e: logger.exception( "Retrieval of assets for character %d failed (status %d)", character.character_id, e.status) return abyssal_modules = [ create_module.call_local(x['type_id'], x['item_id']) for x in items if x['type_id'] in valid_module_types ] with transaction.atomic(): AssetRecord.objects.filter(owner=character).delete() for x in abyssal_modules: AssetRecord(owner=character, module=x).save()
def create_static_types(self): mod_to_source = defaultdict(set) for x in Mutator.objects.all(): for y in x.applicable_modules.all(): mod_to_source[x.result.id].add(y.id) for abyssal_id, sources in tqdm(mod_to_source.items()): for s in sources: data = ESI.request('get_universe_types_type_id', type_id=s).data module, _ = StaticModule.objects.update_or_create( id=s, defaults={ 'source_id': s, 'type_id': abyssal_id }) for attr in data['dogma_attributes']: try: ModuleAttribute.objects.update_or_create( static_module=module, attribute_id=attr['attribute_id'], new_attribute=TypeAttribute.objects.get( type_id=abyssal_id, attribute_id=attr['attribute_id']), defaults={'value': attr['value']}) except TypeAttribute.DoesNotExist: pass
def scan_public_contracts(scan_all=False): if (datetime.time(hour=10, minute=55) <= datetime.datetime.now( datetime.timezone.utc).time() <= datetime.time(hour=11, minute=20)): return all_regions = ESI.request('get_universe_regions').data all_contract_ids = set() for region in all_regions: number_of_page = ESI.head('get_contracts_public_region_id', region_id=region).header['X-Pages'][0] for page in range(1, number_of_page + 1): req = ESI.request('get_contracts_public_region_id', region_id=region, page=page) contracts = list(req.data) for contract_dict in contracts: all_contract_ids.add(contract_dict['contract_id']) if contract_dict['type'] not in ['item_exchange', 'auction']: continue COUNTER_CONTRACTS_FOUND.labels( region=region, type=contract_dict['type']).inc() try: contract = Contract.objects.get( id=contract_dict['contract_id']) if not contract.available: contract.available = True contract.save() if scan_all: scan_contract(dict(contract_dict), region) except Contract.DoesNotExist: scan_contract(dict(contract_dict), region) Contract.objects.filter(Q(available=True) & ~Q(id__in=all_contract_ids)).update( available=False)
def get(self, request): security = ESI.get_security() tokens = security.auth(request.GET['code']) data = security.verify() login(request, authenticate(request, info=data, tokens=tokens)) return redirect('/')
def post(self, request): try: character = request.user.characters.get( character_id=int(request.POST['character_id'])) except EveUser.DoesNotExist: return HttpResponse(status=403) RoutePlannerBackend().check_alliance(character) # Get character's current location from ESI req = ESI.request( 'get_characters_character_id_location', client=character.get_client(), character_id=int( request.POST['character_id'])).data.solar_system_id source_name = SolarSystems.objects.get( solarSystemID=req).solarSystemName # Error checking for characters in wormholes if re.match('J[0-9]{6}', source_name) or source_name == "Thera": return self.render_page(request, True, None, False, False, source_name, "wormhole") # Generate the route try: route = RoutePlannerBackend().generate(req, request.POST['destination']) except NodeNotFound or AttributeError or ObjectDoesNotExist as error: logger.error(error) return self.render_page(request, True, None, False, False, source_name, "route") # Clicking the "Verify" button shows a map and a confirm route button if 'verify' in request.POST: return self.render_page(request, False, route, True, True) # Confirming the route after clicking "Verify" elif 'confirm' in request.POST: RoutePlannerBackend().updateRecents(request.user, request.POST['destination']) self.generate_route(character, route) return self.render_page(request, False, route, True, False) # Basically skipping having to click the "Confirm" button elif 'generate' in request.POST: RoutePlannerBackend().updateRecents(request.user, request.POST['destination']) self.generate_route(character, route) return self.render_page(request, False, route, True, False) # Clicking one of the "Favorites", "Recent", or "Popular" buttons else: RoutePlannerBackend().updateRecents(request.user, request.POST['destination']) self.generate_route(character, route) return self.render_page(request, False, route, True, False)
def create_invtypes(self): existing = set(InvType.objects.values_list('id', flat=True)) available = set() res = ESI.head('get_universe_types') for p in range(1, 1 + res.header['X-Pages'][0]): available |= set(ESI.request('get_universe_types', page=p).data) to_fetch = available - existing for i in to_fetch: data = ESI.request('get_universe_types_type_id', type_id=i).data InvType.objects.update_or_create(id=i, defaults={ 'group_id': data['group_id'], 'name': data['name'], })
def single_search(self, character, query): try: gate_id = ESI.request('get_characters_character_id_search', client=character.get_client(), character_id=character.character_id, categories=['structure'], search=query).data.structure except KeyError: return # Note that searching for 2 systems and the "»" character will return two gates return self.structure_parse(character, gate_id)
def check_alliance(self, character): if timezone.now() - character.esi_updated > timezone.timedelta(days=7): logger.debug( f"Updating {character.name}'s alliance and corporation.") req = ESI.request('get_characters_character_id', character_id=character.character_id).data character.alliance_id = req.alliance_id character.corporation_id = req.corporation_id character.save()
def import_types(self): for i in tqdm(ITEMS): relevant = dict(i['relevant_attributes']) type_obj, _ = ModuleType.objects.update_or_create( id=i['abyssal_id'], defaults={'name': i['name']}) items = ESI.request( 'get_universe_types_type_id', client=self.client, type_id=i['normal_id']).data['dogma_attributes'] for a in items: attr_data = ESI.request('get_dogma_attributes_attribute_id', client=self.client, attribute_id=a['attribute_id']).data if not attr_data.get('published', False): continue attr_obj, _ = ModuleDogmaAttribute.objects.update_or_create( id=attr_data['attribute_id'], defaults={ 'name': attr_data['display_name'], 'short_name': attr_data['name'], 'unit_str': UNIT_STR.get(attr_data.get('unit_id', -1), ''), }) TypeAttribute.objects.update_or_create( type=type_obj, attribute=attr_obj, defaults={ 'high_is_good': relevant.get(attr_data['attribute_id'], attr_data.get('high_is_good', None)), 'display': attr_data['attribute_id'] in relevant })
def post(self, request): scopes = [ 'esi-location.read_location.v1', 'esi-ui.write_waypoint.v1', ] if "approve" in request.POST: scopes.extend([ 'esi-search.search_structures.v1', 'esi-universe.read_structures.v1' ]) return redirect(ESI.get_security().get_auth_uri(state=str(uuid4()), scopes=scopes))
def post(self, request): form = ScopeForm(request.POST) if not form.is_valid(): return redirect('/') scopes = [] if form.cleaned_data['scope_open_window']: scopes.append('esi-ui.open_window.v1') if form.cleaned_data['scope_read_assets']: scopes.append('esi-assets.read_assets.v1') return redirect(ESI.get_security().get_auth_uri(scopes=scopes))
def get_or_create_by_id(self, character_id): try: return self.model.objects.get(id=character_id) except self.model.DoesNotExist: character_data = ESI.request( 'get_characters_character_id', character_id=character_id ).data character, _ = EveCharacter.objects.update_or_create( id=character_id, defaults={ 'name': character_data['name'] } ) return character
def create_module(type_id, item_id, force=False): if not force: try: return Module.objects.get(id=item_id) except Module.DoesNotExist: pass try: module_data = ESI.request('get_dogma_dynamic_items_type_id_item_id', type_id=type_id, item_id=item_id).data except EsiException as e: logger.exception("Retrieval of stats for module %d failed (status %d)", item_id, e.status) return with transaction.atomic(): character = EveCharacter.objects.get_or_create_by_id( module_data['created_by']) res, created = Module.objects.get_or_create( id=item_id, defaults={ 'type_id': type_id, 'mutator_id': module_data['mutator_type_id'], 'source_id': module_data['source_type_id'], 'creator': character }) if created: COUNTER_MODULES_CREATED.labels(type=type_id).inc() for a in module_data['dogma_attributes']: try: ModuleAttribute(module=res, attribute=ModuleDogmaAttribute.objects.get( id=a['attribute_id']), new_attribute=TypeAttribute.objects.get( type_id=type_id, attribute_id=a['attribute_id']), value=a['value']).save() except ModuleDogmaAttribute.DoesNotExist: pass return res
def get_security(self): res = ESI.get_security() res.update_token(self.tokens) if res.is_token_expired(offset=60): try: self.tokens = res.refresh() except APIException as e: if e.status_code == 400: self.scope_open_window = False self.scope_read_assets = False self.save() raise EveUser.KeyDeletedException( "ESI refused to refresh our tokens." ) raise return res
def get_assets(self): results = [] for page in itertools.count(start=1): req = ESI.request( 'get_characters_character_id_assets', client=self.get_client(), character_id=self.character_id, page=page ) date = datetime.datetime.strptime( req.header['Last-Modified'][0], "%a, %d %b %Y %H:%M:%S GMT" ).replace(tzinfo=pytz.UTC) results += req.data if page >= req.header['X-Pages'][0]: break return results, date
def structure_parse(self, character, structure_list): structure_info = [] # Now query /universe/structures/{structure_id}/ to get information about each gate for item in structure_list: req = ESI.request('get_universe_structures_structure_id', client=character.get_client(), structure_id=item).data name = req.name.split(' ') structure = { 'id': item, 'from': name[0], 'to': name[2], 'owner': req.owner_id } structure_info.append(structure.copy()) return structure_info
def update_characters(self): logger.debug("Updating character alliances and corporations.") for character in EveUser.objects.all(): data = ESI.request('get_characters_character_id', character_id=character.character_id).data if "alliance_id" in data: alliance = data.alliance_id else: alliance = 0 corporation = data.corporation_id character.alliance_id = alliance character.corporation_id = corporation character.save() logger.debug("Character information updated!") return len(EveUser.objects.all())
def search_routine(self, alliances): logger.debug("Beginning jump gate search routine.") missing_alliances = [] excluded_gates = [] jump_gates = [] for alliance in alliances: characters = EveUser.objects.filter(alliance_id=alliance, scope_search_structures=True, scope_read_structures=True) # Check if there is a character in the desired alliance. If not, skip this iteration. if not characters: logger.debug(f"No members found in alliance {alliance}.") missing_alliances.append(alliance) continue else: logger.debug( f"Found {len(characters)} character(s) in {alliance}.") # Verify this person is in the correct alliance. exclude_list = [] while True: character = random.choice(characters) logger.debug( f"Checking if character {character.name} is in alliance {alliance}." ) try: alliance_esi = ESI.request( 'get_characters_character_id', character_id=character.character_id).data.alliance_id except KeyError: alliance_esi = 0 if alliance == alliance_esi: logger.debug( f"Character {character.name} is verified as a member of alliance {alliance}." ) break else: logger.debug( f"Character's alliance has changed. Updating to {alliance_esi}." ) character.alliance_id = alliance_esi character.save() # Add the faulty character to the exclude list to avoid getting them again. exclude_list.append(character.id) characters = characters.exclude(id__in=exclude_list) if not characters: break if not characters: logger.debug( f"Character list has been exhausted. Skipping alliance {alliance}." ) continue character = EveUser.objects.get( character_id=character.character_id) new_gate_ids, new_gate_info = self.structure_search( character, excluded_gates) # Add results from the structure search to ignored gates for future searches excluded_gates.extend(new_gate_ids) jump_gates.extend(new_gate_info) # For loop is over - iterate to next alliance after adding the gates to the two lists logger.debug("Removing single sided gates.") final_list = self.check_single_gates(jump_gates) logger.debug(f"{len(jump_gates)-len(final_list)} gates removed.") logger.debug( f"Updating database with {len(final_list)} total jump gates.") # Clear the database and all all the gates to it AnsiblexJumpGates.objects.all().delete() for gate in final_list: fromSolarSystemID = SolarSystems.objects.get( solarSystemName=gate['from']).solarSystemID toSolarSystemID = SolarSystems.objects.get( solarSystemName=gate['to']).solarSystemID AnsiblexJumpGates(structureID=gate['id'], fromSolarSystemID=fromSolarSystemID, toSolarSystemID=toSolarSystemID, ownerID=gate['owner']).save() logger.debug("Completed jump gate update routine.") logger.debug(f"Jump gates found: {len(final_list)}") if missing_alliances: logger.debug( f"Could not find members in the following alliances: {missing_alliances}" ) return len(jump_gates)
def initialize_esi(): logger.info("Initializing ESI application to start Huey consumer") ESI._initialize_app() logger.info("ESI application initialized for consumer!")
def scan_contract(contract_dict, region_id): abyssal_ids = list(ModuleType.objects.values_list('id', flat=True)) COUNTER_CONTRACTS_SCANNED.labels(region=region_id, type=contract_dict['type']).inc() with transaction.atomic(): contract, _ = Contract.objects.get_or_create( id=contract_dict['contract_id'], defaults={ 'issuer_id': contract_dict['issuer_id'], 'price': contract_dict['price'], 'issued_at': contract_dict['date_issued'].v, 'expires_at': contract_dict['date_expired'].v, 'single_item': False, 'location_id': contract_dict['start_location_id'], 'region_id': region_id, 'auction': (contract_dict['type'] == 'auction') }) contract.available = True req = ESI.request('get_contracts_public_items_contract_id', contract_id=contract.id) # This happens if a contract is deleted. if req.status == 404: return # Not totally sure when this happens... if req.status == 403: return # This prevents us from s******g the bed on contracts that are cached but have been accepted since if req.status == 204 and req.data is None: return data = req.data items = 0 contract.single_item = True contract.plex = 0 for item in data: if item['type_id'] in abyssal_ids and item.get( 'is_included', True): items += 1 logger.info("Found abyssal module %d in contract %d.", item['item_id'], contract_dict['contract_id']) module = create_module.call_local(type_id=item['type_id'], item_id=item['item_id']) contract.modules.add(module) elif item['type_id'] == 44992 and not item['is_included']: contract.plex += item['quantity'] else: items += 1 contract.single_item = (items == 1) contract.save()
def get_contracts(self): return ESI.request( 'get_characters_character_id_contracts', client=self.get_client(), character_id=self.character_id ).data
def get_client(self): return ESI.get_client(self.get_security())
def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.client = ESI.get_client()