Exemplo n.º 1
0
    def test_client_raw_body_only(self):
        client = EsiClient(raw_body_only=True)
        self.assertEqual(client.raw_body_only, True)

        with httmock.HTTMock(public_incursion):
            incursions = client.request(self.app.op['get_incursions']())
            self.assertIsNone(incursions.data)
            self.assertTrue(len(incursions.raw) > 0)

            incursions = client.request(self.app.op['get_incursions'](),
                                        raw_body_only=False)
            self.assertIsNotNone(incursions.data)
def characterid_from_name(char_name: str) -> Tuple[Optional[int], Optional[str]]:
    """
    @return: charid, name
    """

    api = get_api()
    security = Security(
        api,
    )

    client = EsiClient(security, timeout=10)

    search_answer = client.request(api.op['get_search'](search=char_name, categories=['character'], strict=True))
    # this character name doesn't exist
    if not ('character' in search_answer.data):
        return None, None
    char_id: int = int(search_answer.data['character'][0])
    
    char_answer = client.request(api.op['get_characters_character_id'](character_id=char_id))
    char_name: str = char_answer.data['name']
    
    return char_id, char_name
Exemplo n.º 3
0
def add_system_info(system_id: int, esi_client: EsiClient) -> Optional[Tuple[int, EsiClient]]:
    try:
        api: App = get_api()
        system_request = api.op['get_universe_systems_system_id'](system_id=system_id)
        system_resp = esi_client.request(system_request)
        if system_resp.status != 200:
            logger.error(f'Could not get systen info for id={system_id} status={system_resp.status}')
            return
        system = SolarSystem()
        system.solarSystemID = system_resp.data['system_id']
        system.solarSystemName = system_resp.data['name']
        db.session.merge(system)
        db.session.commit()
        return None
    except Exception as e:
        return system_id, esi_client
Exemplo n.º 4
0
def add_constellation_info(const_id: int, esi_client: EsiClient) -> Optional[Tuple[int, EsiClient]]:
    try:
        api: App = get_api()
        const_request = api.op['get_universe_constellations_constellation_id'](constellation_id=const_id)

        const_resp = esi_client.request(const_request)
        if const_resp.status != 200:
            logger.error(f'Could not get constellation info for id={const_id} status={const_resp.status}')
            return
        const = Constellation()
        const.constellationID = const_resp.data['constellation_id']
        const.constellationName = const_resp.data['name']
        db.session.merge(const)
        db.session.commit()
        return None
    except Exception as e:
        return const_id, esi_client
Exemplo n.º 5
0
class Market(Cog):
    """
    Market related commands.
    """
    def __init__(self, bot):
        self.bot = bot

        self.esi = EsiClient(
            retry_requests=True,
            headers={
                'User-Agent':
                f'application: MercuryBot contact: {self.bot.config["bot"]["user_agent"]}'
            })

    def type_from_name(self, name: str) -> Optional[dict]:
        """
        Returns a type ID from ESI for a given name.
            Return value of None indicates an invalid type name.
        :param name:
        :return:
        """
        post_op = self.bot.esi_app.op['post_universe_ids'](names=[name])
        response = self.esi.request(post_op)
        if 'inventory_types' not in response.data:
            return None
        return response.data['inventory_types'][0]

    @commands.command(aliases=['pc'])
    async def price_check(self, ctx, item_name):
        """
        Check the price of a given item.
            Returns Jita price data.
        """
        type_data = self.type_from_name(item_name)
        market_data = await get_market_data(type_data['id'])

        return await ctx.send(
            embed=await build_embed(type_data, market_data['resp']))
Exemplo n.º 6
0
class TestEsiPy(unittest.TestCase):
    CALLBACK_URI = "https://foo.bar/baz/callback"
    LOGIN_EVE = "https://login.eveonline.com"
    OAUTH_VERIFY = "%s/oauth/verify" % LOGIN_EVE
    OAUTH_TOKEN = "%s/oauth/token" % LOGIN_EVE
    CLIENT_ID = 'foo'
    SECRET_KEY = 'bar'
    BASIC_TOKEN = six.u('Zm9vOmJhcg==')
    SECURITY_NAME = 'evesso'

    RSC_SSO_ENDPOINTS = "test/resources/oauth-authorization-server.json"
    RSC_JWKS = "test/resources/jwks.json"

    @mock.patch('six.moves.urllib.request.urlopen')
    def setUp(self, urlopen_mock):
        # I hate those mock... thx urlopen instead of requests...
        urlopen_mock.return_value = open('test/resources/swagger.json')
        warnings.simplefilter('ignore')

        self.app = App.create('https://esi.evetech.net/latest/swagger.json')

        with open(TestEsiPy.RSC_SSO_ENDPOINTS, 'r') as sso_endpoints:
            with open(TestEsiPy.RSC_JWKS, "r") as jwks:
                self.security = EsiSecurity(
                    app=self.app,
                    redirect_uri=TestEsiPy.CALLBACK_URI,
                    client_id=TestEsiPy.CLIENT_ID,
                    secret_key=TestEsiPy.SECRET_KEY,
                    sso_endpoints=json.load(sso_endpoints),
                    jwks_key=json.load(jwks))

        self.cache = DictCache()
        self.client = EsiClient(self.security, cache=self.cache)
        self.client_no_auth = EsiClient(cache=self.cache, retry_requests=True)

    def tearDown(self):
        """ clear the cache so we don't have residual data """
        self.cache._dict = {}

    def test_esipy_client_no_args(self):
        client_no_args = EsiClient()
        self.assertIsNone(client_no_args.security)
        self.assertTrue(isinstance(client_no_args.cache, DictCache))
        self.assertEqual(client_no_args._session.headers['User-Agent'],
                         'EsiPy/Client - https://github.com/Kyria/EsiPy')
        self.assertEqual(client_no_args.raw_body_only, False)

    def test_esipy_client_with_headers(self):
        client_with_headers = EsiClient(headers={'User-Agent': 'foobar'})
        self.assertEqual(client_with_headers._session.headers['User-Agent'],
                         'foobar')

    def test_esipy_client_with_adapter(self):
        transport_adapter = HTTPAdapter()
        client_with_adapters = EsiClient(transport_adapter=transport_adapter)
        self.assertEqual(client_with_adapters._session.get_adapter('http://'),
                         transport_adapter)
        self.assertEqual(client_with_adapters._session.get_adapter('https://'),
                         transport_adapter)

    def test_esipy_client_without_cache(self):
        client_without_cache = EsiClient(cache=None)
        self.assertTrue(isinstance(client_without_cache.cache, DummyCache))

    def test_esipy_client_with_cache(self):
        cache = DictCache()
        client_with_cache = EsiClient(cache=cache)
        self.assertTrue(isinstance(client_with_cache.cache, BaseCache))
        self.assertEqual(client_with_cache.cache, cache)

    def test_esipy_client_wrong_cache(self):
        with self.assertRaises(ValueError):
            EsiClient(cache=DictCache)

    def test_esipy_request_public(self):
        with httmock.HTTMock(public_incursion):
            incursions = self.client_no_auth.request(
                self.app.op['get_incursions']())
            self.assertEqual(incursions.data[0].type, 'Incursion')
            self.assertEqual(incursions.data[0].faction_id, 500019)

    def test_esipy_request_authed(self):
        with httmock.HTTMock(*_all_auth_mock_):
            self.security.auth('let it bee')
            char_location = self.client.request(
                self.app.op['get_characters_character_id_location'](
                    character_id=123456789))
            self.assertEqual(char_location.data.station_id, 60004756)

            # force expire
            self.security.token_expiry = 0
            char_location_with_refresh = self.client.request(
                self.app.op['get_characters_character_id_location'](
                    character_id=123456789))
            self.assertEqual(char_location_with_refresh.data.station_id,
                             60004756)

    def test_client_cache_request(self):
        @httmock.all_requests
        def fail_if_request(url, request):
            self.fail('Cached data is not supposed to do requests')

        incursion_operation = self.app.op['get_incursions']

        with httmock.HTTMock(public_incursion_no_expires):
            incursions = self.client_no_auth.request(incursion_operation())
            self.assertEqual(incursions.data[0].state, 'mobilizing')

        with httmock.HTTMock(public_incursion_no_expires_second):
            incursions = self.client_no_auth.request(incursion_operation())
            self.assertEqual(incursions.data[0].state, 'established')

        with httmock.HTTMock(public_incursion):
            incursions = self.client_no_auth.request(incursion_operation())
            self.assertEqual(incursions.data[0].state, 'mobilizing')

        with httmock.HTTMock(fail_if_request):
            incursions = self.client_no_auth.request(incursion_operation())
            self.assertEqual(incursions.data[0].state, 'mobilizing')

    def test_client_warning_header(self):
        # deprecated warning
        warnings.simplefilter('error')
        with httmock.HTTMock(public_incursion_warning):
            incursion_operation = self.app.op['get_incursions']

            with self.assertRaises(UserWarning):
                self.client_no_auth.request(incursion_operation())

            with self.assertRaises(UserWarning):
                self.client_no_auth.head(incursion_operation())

    def test_client_raw_body_only(self):
        client = EsiClient(raw_body_only=True)
        self.assertEqual(client.raw_body_only, True)

        with httmock.HTTMock(public_incursion):
            incursions = client.request(self.app.op['get_incursions']())
            self.assertIsNone(incursions.data)
            self.assertTrue(len(incursions.raw) > 0)

            incursions = client.request(self.app.op['get_incursions'](),
                                        raw_body_only=False)
            self.assertIsNotNone(incursions.data)

    def test_esipy_reuse_operation(self):
        operation = self.app.op['get_incursions']()
        with httmock.HTTMock(public_incursion):
            incursions = self.client_no_auth.request(operation)
            self.assertEqual(incursions.data[0].faction_id, 500019)

            # this shouldn't create any errors
            incursions = self.client_no_auth.request(operation)
            self.assertEqual(incursions.data[0].faction_id, 500019)

    def test_esipy_multi_request(self):
        operation = self.app.op['get_incursions']()

        with httmock.HTTMock(public_incursion):
            count = 0
            for req, incursions in self.client_no_auth.multi_request(
                [operation, operation, operation], threads=2):
                self.assertEqual(incursions.data[0].faction_id, 500019)
                count += 1

            # Check we made 3 requests
            self.assertEqual(count, 3)

    def test_esipy_backoff(self):
        operation = self.app.op['get_incursions']()

        start_calls = time.time()

        with httmock.HTTMock(public_incursion_server_error):
            incursions = self.client_no_auth.request(operation)
            self.assertEqual(incursions.data.error, 'broke')

        end_calls = time.time()

        # Check we retried 5 times
        self.assertEqual(incursions.data.count, 5)

        # Check that backoff slept for a sum > 2 seconds
        self.assertTrue(end_calls - start_calls > 2)

    def test_esipy_timeout(self):
        def send_function(*args, **kwargs):
            """ manually create a ConnectionError to test the retry and be sure
            no exception is thrown """
            send_function.count += 1
            raise ConnectionError

        send_function.count = 0

        self.client_no_auth._session.send = mock.MagicMock(
            side_effect=send_function)

        operation = self.app.op['get_incursions']()
        with httmock.HTTMock(public_incursion):
            incursions = self.client_no_auth.request(operation)
            # there shouldn't be any exceptions

        self.assertEqual(incursions.status, 500)
        self.assertEqual(send_function.count, 5)

    def test_esipy_raise_on_error(self):
        operation = self.app.op['get_incursions']()

        with httmock.HTTMock(public_incursion_server_error):
            # try with retries
            with self.assertRaises(APIException):
                self.client_no_auth.request(operation, raise_on_error=True)

            # try without retries
            with self.assertRaises(APIException):
                self.client.request(operation, raise_on_error=True)

            # try with head
            with self.assertRaises(APIException):
                self.client_no_auth.head(operation, raise_on_error=True)

    def test_esipy_expired_response(self):
        operation = self.app.op['get_incursions']

        with httmock.HTTMock(public_incursion_expired):
            warnings.filterwarnings('error', '.*returned expired result')

            with self.assertRaises(UserWarning):
                self.client_no_auth.request(operation())

            warnings.resetwarnings()
            warnings.simplefilter('ignore')
            incursions = self.client_no_auth.request(operation())
            self.assertEquals(incursions.status, 200)

    def test_esipy_uncached_method(self):
        operation = self.app.op['post_universe_ids'](names=['Foo'])

        self.assertEqual(self.cache._dict, {})
        with httmock.HTTMock(post_universe_id):
            res = self.client.request(operation)
            self.assertEqual(res.data.characters[0].id, 123456789)

        self.assertEqual(self.cache._dict, {})

    def test_esipy_head_request(self):
        operation = self.app.op['get_incursions']()

        with httmock.HTTMock(public_incursion):
            res = self.client.head(operation)
            self.assertIsNone(res.data)
            self.assertIn('Expires', res.header)

    def test_esipy_expired_header_etag(self):
        @httmock.all_requests
        def check_etag(url, request):
            self.assertEqual(request.headers.get('If-None-Match'),
                             '"esipy_test_etag_status"')
            return httmock.response(headers={
                'Etag': '"esipy_test_etag_status"',
                'expires': make_expire_time_str(),
                'date': make_expire_time_str()
            },
                                    status_code=304)

        operation = self.app.op['get_status']()

        with httmock.HTTMock(eve_status):
            self.assertEqual(self.cache._dict, {})
            res = self.client.request(operation)
            self.assertNotEqual(self.cache._dict, {})
            self.assertEqual(res.data.server_version, "1313143")

        time.sleep(2)

        with httmock.HTTMock(check_etag):
            res = self.client.request(operation)
            self.assertEqual(res.data.server_version, "1313143")

    def test_esipy_expired_header_noetag(self):
        def check_etag(url, request):
            self.assertNotIn('If-None-Match', request.headers)
            return httmock.response(status_code=200,
                                    content={
                                        "players": 29597,
                                        "server_version": "1313143",
                                        "start_time": "2018-05-20T11:04:30Z"
                                    })

        operation = self.app.op['get_status']()

        with httmock.HTTMock(eve_status_noetag):
            res = self.client.request(operation)
            self.assertEqual(res.data.server_version, "1313143")

        time.sleep(2)

        with httmock.HTTMock(check_etag):
            res = self.client.request(operation)
            self.assertEqual(res.data.server_version, "1313143")

    def test_esipy_non_json_response(self):
        operation = self.app.op['get_status']()
        with httmock.HTTMock(non_json_error):
            try:
                self.client.request(operation)
            except APIException as exc:
                self.assertEqual(exc.status_code, 502)
                self.assertEqual(
                    exc.response,
                    six.b('<html><body>Some HTML Errors</body></html>'))

            try:
                self.client_no_auth.request(operation)
            except APIException as exc:
                self.assertEqual(exc.status_code, 502)
                self.assertEqual(
                    exc.response,
                    six.b('<html><body>Some HTML Errors</body></html>'))
Exemplo n.º 7
0
class ZkillCommands(Cog):
    def __init__(self, bot):
        self.bot = bot

        self.esi = EsiClient(
            retry_requests=True,
            headers={
                'User-Agent':
                f'applucation: MercuryBot contact: {self.bot.config["bot"]["user_agent"]}'
            })

    async def _get_character_id_from_esi(self, name: str) -> int:
        """
        Returns the character ID from ESI.
            Returns -1 when no ID is returned for a name.
        :param name:
        :return:
        """

        id_op = self.bot.esi_app.op["get_search"](categories="character",
                                                  search=name,
                                                  strict=True)

        id_response = self.esi.request(id_op)

        if "character" not in id_response.data:
            return -1

        return int(id_response.data['character'][0])

    async def _get_character_name_from_id(self,
                                          character_id: int) -> Optional[str]:
        """
        Returns the name of a character for a given character_id.
            Returns None if the ID is not valid.
        :param character_id:
        :return:
        """
        name_op = self.bot.esi_app.op["get_characters_character_id"](
            character_id=character_id)

        try:
            name_response = self.esi.request(name_op)
        except APIException:
            logger.error(
                f'Error getting name for character with ID {character_id} from ESI.'
            )
            logger.error(traceback.print_exc())
            return None

        return name_response.data['name']

    @commands.command(aliases=['t'])
    async def threat(self, ctx, *, name: str):
        """
        Returns info on a character from the zKill stats API.
        """
        # Get the character_id from ESI
        char_id = await self._get_character_id_from_esi(name)
        if char_id == -1:
            return await ctx.send(
                f"Character `{name}` not found. Please check the spelling and try again."
            )

        # Get the real name from ESI (ensure it is spelled correctly... i.e. dont trust user input)
        char_name = await self._get_character_name_from_id(char_id)
        if char_name is None:
            return await ctx.send(
                "Something went wrong, please try again later.")

        # Get Zkill Stats
        stats = await get_char_stats_from_zkill(char_id)
        if stats is None:
            return await ctx.send(
                "The provided character has no killboard stats.")

        embed = await build_embed(stats, name, char_id)

        return await ctx.send(embed=embed)
Exemplo n.º 8
0
from esipy import App

app = App.create(
    url="https://esi.tech.ccp.is/latest/swagger.json?datasource=tranquility")

from esipy import EsiClient

client = EsiClient(
    retry_requests=True,  # set to retry on http 5xx error (default False)
    headers={'User-Agent': 'Gc4be9375d12d45288bced3dd57e9aae1'},
    raw_body_only=
    True,  # default False, set to True to never parse response and only return raw JSON string content.
)

route_find = app.op['get_route_origin_destination'](origin=30002187,
                                                    destination=30000142,
                                                    flag='shortest')

response = client.request(route_find)

print(response.header)
Exemplo n.º 9
0
class NewsWatch(Cog, command_attrs=dict(hidden=True)):
    def __init__(self, bot):
        self.bot = bot

        self.esi = EsiClient(
            retry_requests=True,
            headers={
                'User-Agent':
                f'application: MercuryBot contact: {self.bot.config["bot"]["user_agent"]}'
            },
            raw_body_only=False,
        )

        self.channels = None
        self.news_task.start()

    def cog_unload(self):
        self.news_task.cancel()

    async def load_channels(self):
        """
        Loads self.channels
        :return:
        """
        news = await NewsChannel.filter(news=True)
        devblogs = await NewsChannel.filter(devblogs=True)
        patchnotes = await NewsChannel.filter(patchnotes=True)
        self.channels = {
            'news': news,
            'devblogs': devblogs,
            'patchnotes': patchnotes
        }

    async def _get_character_id_from_name(self, character_name: str) -> int:
        """
        Returns the character_id for a given character name
        :param character_name:
        :return:
        """

        id_op = self.bot.esi_app.op["get_search"](categories=['character'],
                                                  search=character_name,
                                                  strict=True)

        id_resp = self.esi.request(id_op)

        if 'character' not in id_resp.data:
            return -1

        return id_resp.data['character'][0]

    @commands.command(
        aliases=['nc', 'newschan', 'nchan', 'news_chan', 'n_chan'])
    @checks.is_admin()
    async def news_channel(self, ctx, action):
        """
        Sets or unsets the server's news feed channel.

        Valid Actions:
         - set (aliases: add)
         - unset (aliases: delete, remove)
         - edit

         The set and edit actions must be run from the intended channel, however,
         the unset action can be run from any channel.
        """
        action = action.lower()
        if action in ('set', 'add'):
            # Check if the news channel is already set for this guild.
            if await NewsChannel.filter(pk=ctx.guild.id).exists():
                return await ctx.send(
                    f"The news channel for this server is already set! To change it"
                    f"please run the `edit` action from the intended channel. To unset the news "
                    f"channel run the `unset` action from any channel.")

            # Set the channel
            channel = await NewsChannel(guild_id=ctx.guild.id,
                                        channel_id=ctx.channel.id)
            await channel.save()

            return await ctx.send(
                f"{ctx.channel.mention} has been set as the news channel for `{ctx.guild.name}`"
            )

        elif action in ('unset', 'delete', 'remove'):
            # Make sure the channel exists
            if not await NewsChannel.filter(pk=ctx.guild.id).exists():
                return await ctx.send(
                    f"The news channel for this server is not yet set! To set it,"
                    f"run the `set` action from the intended channel.")

            # Unset the channel
            channel = await NewsChannel.filter(pk=ctx.guild.id).first()
            await channel.delete()

            return await ctx.send(
                f"The news channel for `{ctx.guild.id}` has been unset.")

        elif action == 'edit':
            # Make sure the channel exists
            if not await NewsChannel.filter(pk=ctx.guild.id).exists():
                return await ctx.send(
                    f"The news channel for this server is not yet set! To set it,"
                    f"run the `set` action from the intended channel.")

            # Get the current channel.
            channel = await NewsChannel.filter(pk=ctx.guild.id).first()
            channel.channel_id = ctx.channel.id
            await channel.save()

            return await ctx.send(
                f"The news channel for this server has been updated. "
                f"New channel is {ctx.channel.mention}")
        else:
            return await ctx.send(
                f"{action} is not a valid action for this command. To see valid actions run"
                f"the help command. (`/help news_channel`)")

    @commands.command(
        aliases=['news_track', 'nt', 'track_news', 'track_type', 'tt'])
    @checks.is_admin()
    async def news_type(self, ctx, action, *, news_type: str):
        """
        Sets the news channel for the current guild to track the specified type.

            Valid Actions:
            add, remove (aliases: delete)

            Valid Types are:
            news, devblogs (including plural variations), patchnotes (including plural variations), all
        """
        action = action.lower()

        # Check that the channel is set
        if not await NewsChannel.filter(pk=ctx.guild.id).exists():
            return await ctx.send(
                f"The news channel for this server is not yet set. To set it please run the "
                f"`news_channel` command from the intended channel.")

        channel = await NewsChannel.filter(pk=ctx.guild.id).first()
        bad_type = False

        if action == 'add':
            if news_type == 'news':
                channel.news = True
            elif news_type in ("patchnotes", "patch notes", "patch_notes",
                               "patch-notes"):
                channel.patchnotes = True
            elif news_type in ('devblogs', 'dev blogs', 'dev-blogs',
                               'dev_blogs'):
                channel.devblogs = True
            elif news_type == 'all':
                channel.news = True
                channel.patchnotes = True
                channel.devblogs = True
            else:
                bad_type = True

            if not bad_type:
                await channel.save()
        elif action in ('remove', 'delete'):
            if news_type == 'news':
                channel.news = False
            elif news_type in ("patchnotes", "patch notes", "patch_notes",
                               "patch-notes"):
                channel.patchnotes = False
            elif news_type in ('devblogs', 'dev blogs', 'dev-blogs',
                               'dev_blogs'):
                channel.devblogs = False
            elif news_type == 'all':
                channel.news = False
                channel.patchnotes = False
                channel.devblogs = False
            else:
                bad_type = True

            if not bad_type:
                await channel.save()
        else:
            return await ctx.send(
                f"{action} is not a valid action for this command. To see valid actions run "
                f"the help command. (`/help news_type`)")

        if bad_type:
            return await ctx.send(
                f"{news_type} is not a valid news type. To see valid news types run "
                f"the help command. (`/help news_type`)")

        await self.load_channels()
        return await ctx.send(
            f'The news channel for `{ctx.guild.name}` is now tracking `{news_type}` news articles.'
        )

    @tasks.loop(seconds=300.0)
    async def news_task(self):
        dev_blog_url = "https://www.eveonline.com/rss/json/dev-blogs"
        news_url = "https://www.eveonline.com/rss/json/news"
        patch_url = "https://www.eveonline.com/rss/json/patch-notes"

        articles_to_save = []

        try:
            async with aiohttp.ClientSession() as session:
                devs = await get_json(session, dev_blog_url)
                news = await get_json(session, news_url)
                patches = await get_json(session, patch_url)

            resps = (devs['resp'], news['resp'], patches['resp'])

            # Get list of posted articles
            article_ids = await PostedArticles.all().values_list('article_id',
                                                                 flat=True)
            for resp in resps:
                for article in resp:
                    if article['id'] not in article_ids:
                        articles_to_save.append(
                            await PostedArticles(article_id=article['id']))

                        await self.post(article,
                                        article['category'].replace('-', ''))
                    else:
                        continue

        except Exception as e:
            logger.error(f"Error occurred in the news task! Error: {e}")
            logger.error(traceback.print_exc())
        finally:
            await PostedArticles.bulk_create(articles_to_save)

    @news_task.before_loop
    async def before_news_task(self):
        # Wait for the bot to be ready
        await self.bot.wait_until_ready()
        # Load channels and articles
        await self.load_channels()

    @news_task.after_loop
    async def on_news_task_cancel(self):
        pass

    async def post(self, article, category):
        """
        Processes and posts the article to the channels defined in self.channels.
        :param article:
        :param category:
        :return:
        """
        title = article["title"].replace('"', '""')
        image = og(article['link'], ['og:image']).image
        author_id = await self._get_character_id_from_name(article['author'])
        if author_id == -1:
            author_id = 3019582
        author_img = f'https://imageserver.eveonline.com/Character/{author_id}_128.jpg'

        desc = article['description']
        if len(desc) > 1000:
            desc = article['description'][:1000].replace('__*', '***').replace('*__', '***')\
                                    .replace('__', '**').replace('###', '').replace('##', '')+'...'
        time = datetime.strptime(article['publishingDate'].strip('Z'),
                                 '%Y-%m-%dT%H:%M:%S')

        embed = discord.Embed(title=title, timestamp=time, description=desc)
        embed.set_author(name=f'EVE Online {article["category"].title()}',
                         icon_url='https://www.ccpgames.com/img/ccp_logo.png')

        embed.add_field(name="Link", value=f'{article["link"]}')
        embed.set_image(url=image)
        embed.set_footer(text=f'{article["author"]}', icon_url=author_img)

        for channel in self.channels[category]:
            channel = self.bot.get_channel(channel.channel_id)
            await channel.send(embed=embed)
Exemplo n.º 10
0
class myApp:
    pp = pprint.PrettyPrinter(indent=2)
    app = None
    client = None

    def main(self):
        print "setting up the app..."
        self.app = App.create(
            url=
            "https://esi.tech.ccp.is/latest/swagger.json?datasource=tranquility"
        )
        print "done. \n Setting up the client."

        self.client = EsiClient(
            retry_requests=
            True,  # set to retry on http 5xx error (default False)
            header={'User-Agent': 'Jimmy - api test app:  [email protected]'},
            raw_body_only=
            True,  # default False, set to True to never parse response and only return raw JSON string content.
        )
        print "done, after this it's all me and my calls."
        chars = ["alderith", "gruxella", "lord grapefruit", "druzidelcastro"]

        try:
            # self.get_id_for_users(chars)
            # self.get_group_item_ids()
            self.get_orders_for_region(10000002)
        except Exception as err:
            self.pp.pprint(err)
#        self.get_user_info()

# try:
#     self.original_example()
# except Exception as err:
#     print "Error:: "
#     print err
#     e = sys.exc_info()[0]
#     self.pp.pprint(e)

# self.original_example()
# print "hello world"

    def get_orders_for_region(self, reg_id):
        count = 0
        query = self.app.op['get_markets_region_id_orders'](
            order_type="all",
            region_id=reg_id,
        )
        response = self.client.request(query)
        #        self.pp.pprint(response.raw)

        print "Attempting to parse json"
        data = json.loads(response.raw)
        print "done parsing json"
        print len(data)
        #       self.pp.pprint(data)
        #       return

        queries = []
        print "this dataset expires:"
        print response.header['Expires']
        print "we need this many pages:"
        size = response.header['X-Pages'][0]
        print size
        if (size > 1):
            for page in range(1, size + 1):
                #           for page in range(1,3):
                queries.append(self.app.op['get_markets_region_id_orders'](
                    order_type="all",
                    region_id=reg_id,
                    page=page,
                ))
        print "doing long request to CCP..."
        #        results = self.client.multi_request(queries,None,None,size)
        results = self.client.multi_request(queries)
        print "done with long request"

        for result in results:
            # self.pp.pprint(result[1].header)
            # self.pp.pprint(result[1].data)
            data = json.loads(result[1].raw)
            count += len(data)
            print "Running count = %d" % (count)
            print "is buy order? %r" % (data[0]['is_buy_order'])
            print "remaining volume: %d" % (data[0]['volume_remain'])


#       self.pp.pprint(results)
        print "Total orders = %d" % (count)
        return results

    def get_market_groups(self):
        query = self.app.op['get_markets_groups']()
        response = self.client.request(query)
        # self.pp.pprint(response.data)
        self.pp.pprint(response.header)
        print len(response.data)
        return response

    def get_group_item_ids(self):
        marketgroup_response = self.get_market_groups()
        groups = []
        count = 0
        for group in marketgroup_response.data:
            count += 1
            print group
            query = self.app.op['get_markets_groups_market_group_id'](
                market_group_id=group)
            response = self.client.request(query)
            groups.append(response.data)
            if count == 25:
                break
            # self.pp.pprint(response.data)
        self.pp.pprint(groups)

    def get_id_for_users(self, *user_array):
        users = []
        query = self.app.op['post_universe_ids'](names=user_array[0])
        response = self.client.request(query)
        for char in response.data['characters']:
            print "%s id = %d" % (char['name'], char['id'])

    def get_user_info(self):
        query = self.app.op['post_universe_ids'](
            names=["Gruxella", "Alderith"])

        # query = self.app.op['get_characters_character_id'](
        #     character_id=712133937
        # )

        # query = self.app.op['get_characters_names'](
        #     character_ids=[712133937]
        # )
        response = self.client.request(query)
        print response.data

    def original_example(self):

        market_order_operation = self.app.op['get_markets_region_id_orders'](
            region_id=10000002,
            type_id=34,
            order_type='all',
        )

        # do the request
        print "did I get here? 2"
        response = self.client.request(market_order_operation)

        # use it: response.data contains the parsed result of the request.
        print response.data[0].price

        # to get the headers objects, you can get the header attribute
        print response.header
Exemplo n.º 11
0
class TheraWatch(Cog, command_attrs=dict(hidden=True)):
    """
    Watch the EVE-Scout API for new Thera wormhole connections.
    """
    def __init__(self, bot):
        self.bot = bot

        self.TYPE_MODELS = {
            'region': TheraEveRegion,
            'system': TheraEveSystem,
            'constellation': TheraEveConstellation
        }

        self.last_thera = None
        self.channels = None

        self.esi = EsiClient(
            retry_requests=True,
            headers={
                'User-Agent':
                f'application: MercuryBot contact: {self.bot.config["bot"]["user_agent"]}'
            },
            raw_body_only=False)

        self.thera.start()

    def cog_unload(self):
        self.thera.cancel()

    async def load_channels(self):
        """
        Updates self.channels.
        :return:
        """
        systems = await TheraEveSystem.all()
        constellations = await TheraEveConstellation.all()
        regions = await TheraEveRegion.all()
        self.channels = {
            'systems': {x.system_id: await x.channels.all()
                        for x in systems},
            'constellations': {
                x.constellation_id: await x.channels.all()
                for x in constellations
            },
            'regions': {x.region_id: await x.channels.all()
                        for x in regions}
        }

    async def update_channels(self, location_type: str, location):
        """
        Updates self.channels
        :param location: A location object
        :param location_type: string
        :return:
        """
        plural = f'{location_type}s'
        self.channels[plural][location.pk] = await location.channels.all()

    async def location_from_id(self, location_type: str, location_id: int):
        """
        Checks if the ID provided is valid for the type provided.
        :param location_type: string
        :param location_id: integer
        :return: Thera location model.
        """
        RANGES = {
            'region': [10000000, 13000000],
            'constellation': [20000000, 23000000],
            'system': [30000000, 33000000]
        }
        if not RANGES[location_type][0] <= location_id <= RANGES[
                location_type][1] and location_id is not 0:
            return -1

        if await self.TYPE_MODELS[location_type].filter(pk=location_id
                                                        ).exists():
            return await self.TYPE_MODELS[location_type].filter(pk=location_id
                                                                ).first()

        if location_id is not 0:
            post_op = self.bot.esi_app.op['post_universe_names'](
                ids=[location_id])
            response = self.esi.request(post_op)
            if location_type not in response.data[0]['category']:
                logger.debug(response.data)
                return -1
            model_kwargs = {
                f'{location_type}_id': response.data[0]['id'],
                'name': response.data[0]['name']
            }
            location = self.TYPE_MODELS[location_type](**model_kwargs)
            await location.save()
        else:
            # If we want to add all regions take care of this special case.
            location = self.TYPE_MODELS[location_type](name="All Regions",
                                                       region_id=0)
            await location.save()

        return location

    async def location_from_name(self, location_type: str, location_name: str):
        """
        Returns the location object for a location using its name.
        :param location_type: string
        :param location_name: string
        :return: Thera location model.
        """
        plural = f'{location_type}s'

        # Check the DB for the item
        if await self.TYPE_MODELS[location_type].filter(name=location_name
                                                        ).exists():
            return await self.TYPE_MODELS[location_type].filter(
                name=location_name).first()

        if location_name.lower() != "all regions":
            # Get the system ID from ESI.
            post_op = self.bot.esi_app.op['post_universe_ids'](
                names=[location_name])
            response = self.esi.request(post_op)
            if plural not in response.data:
                return -1
            model_kwargs = {
                f'{location_type}_id': response.data[plural][0]['id'],
                'name': response.data[plural][0]['name']
            }
            location = self.TYPE_MODELS[location_type](**model_kwargs)
            await location.save()
        else:
            # If we want to add all regions take care of this special case.
            location = self.TYPE_MODELS[location_type](name="All Regions",
                                                       region_id=0)
            await location.save()

        return location

    async def load_last(self):
        """
        Loads the last thera id seen.
        """
        last_thera = await LastThera.first()
        if last_thera is not None:
            self.last_thera = last_thera.last_thera

    @commands.command(aliases=['set_tc', 'tc'])
    @checks.is_admin()
    async def set_thera_channel(self, ctx):
        """
        Set the channel to post new thera connections into.
        """
        channels = await TheraChannel.filter(pk=ctx.guild.id)
        if len(channels) is not 0:
            return await ctx.send(
                f'Thera channel already set for `{ctx.guild.name}`. '
                f'To change it, please first unset the thera channel using '
                f'the `unset_thera_channel` command.')

        # Set the Thera Channel
        guild_id = ctx.guild.id
        channel_id = ctx.channel.id
        channel = TheraChannel(guild_id=guild_id, channel_id=channel_id)
        await channel.save()

        return await ctx.send(
            f'{ctx.channel.mention} has been set as the '
            f'Thera notifications channel for `{ctx.guild.name}`')

    @commands.command(aliases=['utc', 'delete_tc'])
    @checks.is_admin()
    async def unset_thera_channel(self, ctx):
        """
        This command unsets the channel used for thera connection posts.
            Note: This command can be run from any channel.
        """
        channels = await TheraChannel.filter(pk=ctx.guild.id)
        if len(channels) is 0:
            return await ctx.send(
                f'Thera channel not set for `{ctx.guild.name}`. '
                f'Use the `set_thera_channel` command from '
                f'the target channel to set it.')

        await channels[0].delete()
        # Update self.channels
        await self.load_channels()  # Reloading channels is easier on delete.

        return await ctx.send(f'Unset thera channel for `{ctx.guild.name}`')

    @commands.command(aliases=['ts', 'tsys'])
    @checks.is_admin()
    async def thera_system(self, ctx, action, *, system):
        """
        Add or remove watchlisted system.
            Both names and IDs are accepted.

            Valid Actions: add, remove
        """
        # Get the TheraChannel
        channel = await TheraChannel.filter(pk=ctx.guild.id).first()
        if channel is None:
            return await ctx.send(
                f'A thera notifications channel must be set up before you can manage watchlisted '
                f'locations. To set a thera notifications channel run the '
                f'`set_thera_channel` from the target channel.')

        # First check if we have a name or id
        name = not system.isnumeric()

        # Get / Validate the system ID
        system_obj = None
        if name:
            # Get the system ID from ESI.
            system_obj = await self.location_from_name('system', system)
            if system_obj == -1:
                return await ctx.send(
                    f'The system name provided does not appear to be valid. Please '
                    f'check the spelling and try again or try adding the system by ID.'
                )
        else:
            system = int(system)
            system_obj = await self.location_from_id('system', system)
            if system_obj == -1:
                return await ctx.send(
                    f'The system ID provided is not valid. Please check the ID and try again '
                    f'or try adding the system by name.')

        if action.lower() == 'add':
            # Make sure we dont have the same system on the list twice.
            if system_obj in await channel.systems.all():
                return await ctx.send(
                    f'System `{system}` already on watchlist.')

            # Add the system to the list and save the model.
            await channel.systems.add(system_obj)
        elif action.lower() == 'remove':
            # Make sure the system is on the list.
            if system_obj not in await channel.systems.all():
                return await ctx.send(
                    f'System `{system}` is not on the watchlist.')

            await channel.systems.remove(system_obj)
        else:
            return await ctx.send(
                f'`{action}` is an invalid action. Valid actions are `add` or `remove`.'
            )

        actioned = f'{action}ed'
        await self.update_channels('system', system_obj)

        return await ctx.send(f'Watchlist System `{system}` {actioned}.')

    @commands.command(aliases=['tcon'])
    @checks.is_admin()
    async def thera_constellation(self, ctx, action, *, constellation):
        """
        Add or remove a watchlisted constellation.
            Both names and IDs accepted.

            Valid Actions: add, remove
        """
        # Get the TheraChannel
        channel = await TheraChannel.filter(pk=ctx.guild.id).first()
        if channel is None:
            return await ctx.send(
                f'A thera notifications channel must be set up before you can manage watchlisted '
                f'locations. To set a thera notifications channel run the '
                f'`set_thera_channel` from the target channel.')

        name = not constellation.isnumeric()

        constellation_obj = None
        # Get / Validate constellation id
        if name:
            # Get the constellation ID from ESI
            constellation_obj = await self.location_from_name(
                'constellation', constellation)
            if constellation_obj == -1:
                return await ctx.send(
                    f'The constellation name provided does not appear to be valid. '
                    f'Please check the spelling and try again or try adding using its ID.'
                )
        else:
            constellation = int(constellation)
            constellation_obj = await self.location_from_id(
                'constellation', constellation)
            if constellation_obj == -1:
                return await ctx.send(
                    f'The constellation ID provided is not valid. Please check the ID and '
                    f'try again or try adding using its name.')

        if action.lower() == 'add':
            if constellation_obj in await channel.constellations.all():
                return await ctx.send(
                    f'Constellation `{constellation}` is already on watchlist.'
                )
            await channel.constellations.add(constellation_obj)
        elif action.lower() == 'remove':
            if constellation_obj not in await channel.constellations.all():
                return await ctx.send(
                    f'Constellation `{constellation}` is not on the watchlist.'
                )
            await channel.constellations.remove(constellation_obj)
        else:
            return await ctx.send(
                f'`{action}` is an invalid action. Valid actions are `add` and `remove`'
            )

        await self.update_channels('constellation', constellation_obj)

        return await ctx.send(
            f'Watchlist Constellation `{constellation}` {action}ed')

    @commands.command(aliases=['tr', 'treg'])
    @checks.is_admin()
    async def thera_region(self, ctx, action, *, region):
        """
        Add or remove a watchlisted region.
            Both names and IDs accepted.

            Valid Actions: add, remove
        """
        # Get the TheraChannel
        channel = await TheraChannel.filter(pk=ctx.guild.id).first()
        if channel is None:
            return await ctx.send(
                f'A thera notifications channel must be set up before you can manage watchlisted '
                f'locations. To set a thera notifications channel run the '
                f'`set_thera_channel` from the target channel.')

        name = not region.isnumeric()

        region_obj = None
        # Get / Validate region id
        if name:
            # Get the region ID from ESI
            region_obj = await self.location_from_name('region', region)
            if region_obj == -1:
                return await ctx.send(
                    f'The region name provided does not appear to be valid. Please check '
                    f'the spelling and try again or try adding it by ID.')
        else:
            region = int(region)
            region_obj = await self.location_from_id('region', region)
            if region_obj == -1:
                return await ctx.send(
                    f'The region ID provided is not valid. Please check the ID and try again '
                    f'or try adding it by name.')

        if action.lower() == 'add':
            if region_obj in await channel.regions.all():
                return await ctx.send(f'`{region}` already on the watchlist.')
            await channel.regions.add(region_obj)
        elif action.lower() == 'remove':
            if region_obj not in await channel.regions.all():
                return await ctx.send(f'`{region}` is not on the watchlist.')
            await channel.regions.remove(region_obj)
        else:
            return await ctx.send(
                f'`{action}` is an invalid action. Valid actions are `add` and `remove`.'
            )

        await self.update_channels('region', region_obj)

        return await ctx.send(f'Watchlist Region `{region}` {action}ed.')

    @tasks.loop(seconds=60.0)
    async def thera(self):
        url = 'https://www.eve-scout.com/api/wormholes'
        try:
            async with aiohttp.ClientSession() as session:
                resp = await get(session, url)
            hole = list(resp['resp'])[0]
            hole_id = hole['id']
            source = hole['sourceSolarSystem']
            if self.last_thera <= hole_id:
                pass  # Do nothing
            elif source['name'] == "Thera":
                self.last_thera = hole_id  # Ensure we keep track of the last thera id
                destination = hole['destinationSolarSystem']
                if destination['id'] in self.channels['systems']:
                    await self.process_hole(hole)
                elif destination['constellationID'] in self.channels[
                        'constellations']:
                    await self.process_hole(hole)
                elif destination['regionId'] in self.channels[
                        'regions'] or 0 in self.channels['regions']:
                    await self.process_hole(hole)

        except Exception as e:
            logger.warning("Exception occurred in thera loop.")
            logger.warning(traceback.format_exc())

    @thera.before_loop
    async def before_thera(self):
        # Wait until the bot is ready
        await self.bot.wait_until_ready()
        # Load channels and the last thera id.
        await self.load_channels()
        await self.load_last()

    @thera.after_loop
    async def on_thera_cancel(self):
        if self.thera.is_being_cancelled():
            if self.last_thera is not None:
                # Save last_thera.
                last_thera_obj = await LastThera.first()
                if last_thera_obj is None:
                    new_obj = LastThera(last_thera=self.last_thera)
                    await new_obj.save()
                else:
                    last_thera_obj.last_thera = self.last_thera
                    await last_thera_obj.save()

    async def process_hole(self, hole):
        """
        Build the embed for a given hole, and build a dict of which channels to send it to.
        :param hole:
        :return:
        """
        # Pull info from hole dict
        d_system = hole['destinationSolarSystem']
        hole_type = hole['destinationWormholeType']['name']
        if hole_type == 'K162':
            hole_type = hole['sourceWormholeType']['name']
        system = d_system['name']
        region = d_system['region']['name']
        c_id = d_system['constellationID']
        try:
            c_name = self.esi.request(
                self.bot.esi_app.
                op['get_universe_constellations_constellation_id'](
                    constellation_id=c_id)).data['name']
        except:
            print("oops")
        in_sig = hole['wormholeDestinationSignatureId']
        out_sig = hole['signatureId']

        # Build Discord Embed
        embed = discord.Embed(title="Thera Alert",
                              color=discord.Color.blurple())
        embed.set_author(
            name='EVE-Scout',
            icon_url=
            'http://games.chruker.dk/eve_online/graphics/ids/128/20956.jpg')
        embed.set_thumbnail(
            url='https://www.eve-scout.com/images/eve-scout-logo.png')
        embed.set_footer(text=f"ID: {hole['id']}")

        embed.add_field(name='Region', value=region, inline=True)
        embed.add_field(name='\u200B', value='\u200B',
                        inline=True)  # Empty Field
        embed.add_field(name='System (Constellation)',
                        value=f'{system} ({c_name})',
                        inline=True)

        embed.add_field(name='Signature (In - Out)',
                        value=f'`{in_sig}` - `{out_sig}`',
                        inline=True)
        embed.add_field(name='\u200B', value='\u200B',
                        inline=True)  # Empty Field
        embed.add_field(name='Type', value=hole_type, inline=True)

        # Build channels for this hole
        send_channels = {
            'system': list(),
            'constellation': list(),
            'region': list()
        }

        if d_system['id'] in self.channels['systems']:
            send_channels['system'] += self.channels['systems'][d_system['id']]
        elif d_system['constellationID'] in self.channels['constellations']:
            send_channels['constellation'] += self.channels['constellation'][
                d_system['constellationId']]
        elif d_system['regionId'] in self.channels[
                'regions'] or 0 in self.channels['regions']:
            if 0 in self.channels[
                    'regions']:  # Send to anyone that specified all regions
                send_channels['region'] += self.channels['regions'][0]
            if d_system['regionId'] in self.channels[
                    'regions']:  # Send to anyone that specified *this* region.
                send_channels['region'] += self.channels['regions'][
                    d_system['regionId']]

        return await self.send_thera(embed, send_channels)

    async def send_thera(self, embed: discord.Embed, channels: dict):
        mentions = {
            'system': "@everyone",
            'constellation': "@here",
            'region': ""
        }

        for k, v in channels.items():
            for c in v:
                # Get channel
                channel = self.bot.get_channel(c.channel_id)
                await channel.send(content=mentions[k], embed=embed)
Exemplo n.º 12
0
class TestEsiPy(unittest.TestCase):
    CALLBACK_URI = "https://foo.bar/baz/callback"
    LOGIN_EVE = "https://login.eveonline.com"
    OAUTH_VERIFY = "%s/oauth/verify" % LOGIN_EVE
    OAUTH_TOKEN = "%s/oauth/token" % LOGIN_EVE
    CLIENT_ID = 'foo'
    SECRET_KEY = 'bar'
    BASIC_TOKEN = six.u('Zm9vOmJhcg==')
    SECURITY_NAME = 'evesso'

    @mock.patch('six.moves.urllib.request.urlopen')
    def setUp(self, urlopen_mock):
        # I hate those mock... thx urlopen instead of requests...
        urlopen_mock.return_value = open('test/resources/swagger.json')

        self.app = App.create('https://esi.tech.ccp.is/latest/swagger.json')

        self.security = EsiSecurity(
            app=self.app,
            redirect_uri=TestEsiPy.CALLBACK_URI,
            client_id=TestEsiPy.CLIENT_ID,
            secret_key=TestEsiPy.SECRET_KEY,
        )

        self.cache = DictCache()
        self.client = EsiClient(self.security, cache=self.cache)
        self.client_no_auth = EsiClient(cache=self.cache, retry_requests=True)

    def tearDown(self):
        """ clear the cache so we don't have residual data """
        self.cache._dict = {}

    def test_esipy_client_no_args(self):
        client_no_args = EsiClient()
        self.assertIsNone(client_no_args.security)
        self.assertTrue(isinstance(client_no_args.cache, DictCache))
        self.assertEqual(client_no_args._session.headers['User-Agent'],
                         'EsiPy/Client - https://github.com/Kyria/EsiPy')
        self.assertEqual(client_no_args.raw_body_only, False)

    def test_esipy_client_with_headers(self):
        client_with_headers = EsiClient(headers={'User-Agent': 'foobar'})
        self.assertEqual(client_with_headers._session.headers['User-Agent'],
                         'foobar')

    def test_esipy_client_with_adapter(self):
        transport_adapter = HTTPAdapter()
        client_with_adapters = EsiClient(transport_adapter=transport_adapter)
        self.assertEqual(client_with_adapters._session.get_adapter('http://'),
                         transport_adapter)
        self.assertEqual(client_with_adapters._session.get_adapter('https://'),
                         transport_adapter)

    def test_esipy_client_without_cache(self):
        client_without_cache = EsiClient(cache=None)
        self.assertTrue(isinstance(client_without_cache.cache, DummyCache))

    def test_esipy_client_with_cache(self):
        cache = DictCache()
        client_with_cache = EsiClient(cache=cache)
        self.assertTrue(isinstance(client_with_cache.cache, BaseCache))
        self.assertEqual(client_with_cache.cache, cache)

    def test_esipy_client_wrong_cache(self):
        with self.assertRaises(ValueError):
            EsiClient(cache=DictCache)

    def test_esipy_request_public(self):
        with httmock.HTTMock(public_incursion):
            incursions = self.client_no_auth.request(
                self.app.op['get_incursions']())
            self.assertEqual(incursions.data[0].type, 'Incursion')
            self.assertEqual(incursions.data[0].faction_id, 500019)

    def test_esipy_request_authed(self):
        with httmock.HTTMock(*_all_auth_mock_):
            self.security.auth('let it bee')
            char_location = self.client.request(
                self.app.op['get_characters_character_id_location'](
                    character_id=123456789))
            self.assertEqual(char_location.data.station_id, 60004756)

            # force expire
            self.security.token_expiry = 0
            char_location_with_refresh = self.client.request(
                self.app.op['get_characters_character_id_location'](
                    character_id=123456789))
            self.assertEqual(char_location_with_refresh.data.station_id,
                             60004756)

    def test_client_cache_request(self):
        @httmock.all_requests
        def fail_if_request(url, request):
            self.fail('Cached data is not supposed to do requests')

        incursion_operation = self.app.op['get_incursions']

        with httmock.HTTMock(public_incursion_no_expires):
            incursions = self.client_no_auth.request(incursion_operation())
            self.assertEqual(incursions.data[0].state, 'mobilizing')

        with httmock.HTTMock(public_incursion_no_expires_second):
            incursions = self.client_no_auth.request(incursion_operation())
            self.assertEqual(incursions.data[0].state, 'established')

        with httmock.HTTMock(public_incursion):
            incursions = self.client_no_auth.request(incursion_operation())
            self.assertEqual(incursions.data[0].state, 'mobilizing')

        with httmock.HTTMock(fail_if_request):
            incursions = self.client_no_auth.request(incursion_operation())
            self.assertEqual(incursions.data[0].state, 'mobilizing')

    def test_client_warning_header(self):
        with httmock.HTTMock(public_incursion_warning):
            warnings.simplefilter('error')
            incursion_operation = self.app.op['get_incursions']

            with self.assertRaises(UserWarning):
                self.client_no_auth.request(incursion_operation())

    def test_client_raw_body_only(self):
        client = EsiClient(raw_body_only=True)
        self.assertEqual(client.raw_body_only, True)

        with httmock.HTTMock(public_incursion):
            incursions = client.request(self.app.op['get_incursions']())
            self.assertIsNone(incursions.data)
            self.assertTrue(len(incursions.raw) > 0)

            incursions = client.request(self.app.op['get_incursions'](),
                                        raw_body_only=False)
            self.assertIsNotNone(incursions.data)

    def test_esipy_reuse_operation(self):
        operation = self.app.op['get_incursions']()
        with httmock.HTTMock(public_incursion):
            incursions = self.client_no_auth.request(operation)
            self.assertEqual(incursions.data[0].faction_id, 500019)

            # this shouldn't create any errors
            incursions = self.client_no_auth.request(operation)
            self.assertEqual(incursions.data[0].faction_id, 500019)

    def test_esipy_multi_request(self):
        operation = self.app.op['get_incursions']()

        with httmock.HTTMock(public_incursion):
            count = 0
            for req, incursions in self.client_no_auth.multi_request(
                [operation, operation, operation], threads=2):
                self.assertEqual(incursions.data[0].faction_id, 500019)
                count += 1

            # Check we made 3 requests
            self.assertEqual(count, 3)

    def test_esipy_backoff(self):
        operation = self.app.op['get_incursions']()

        start_calls = time.time()

        with httmock.HTTMock(public_incursion_server_error):
            incursions = self.client_no_auth.request(operation)
            self.assertEqual(incursions.data.error, 'broke')

        end_calls = time.time()

        # Check we retried 5 times
        self.assertEqual(incursions.data.count, 5)

        # Check that backoff slept for a sum > 2 seconds
        self.assertTrue(end_calls - start_calls > 2)

    def test_esipy_timeout(self):
        def send_function(*args, **kwargs):
            """ manually create a ConnectionError to test the retry and be sure
            no exception is thrown """
            send_function.count += 1
            raise ConnectionError

        send_function.count = 0

        self.client_no_auth._session.send = mock.MagicMock(
            side_effect=send_function)

        operation = self.app.op['get_incursions']()
        with httmock.HTTMock(public_incursion):
            incursions = self.client_no_auth.request(operation)
            # there shouldn't be any exceptions

        self.assertEqual(incursions.status, 500)
        self.assertEqual(send_function.count, 5)
Exemplo n.º 13
0
class ESI:
    def __init__(self):
        self.db = Database()
        self.config = Config()
        self.scopes = self.config.getConfig()["settings"]["esiScopes"]
        self.esi_app = App.create(
            url=self.config.getConfig()["settings"]["esiURL"], )
        self.security = EsiSecurity(
            app=self.esi_app,
            redirect_uri=self.config.getConfig()["settings"]["esiCallback"],
            client_id=self.config.getConfig()["settings"]["esiClientID"],
            secret_key=self.config.getConfig()["settings"]["esiSecretKey"],
            headers={
                'User-Agent':
                self.config.getConfig()["settings"]["esiCustomHeader"]
            })
        self.client = EsiClient(
            security=self.security,
            retry_requests=True,
            headers={
                'User-Agent':
                self.config.getConfig()["settings"]["esiCustomHeader"]
            })

    def getAuthURI(self):
        return self.security.get_auth_uri(scopes=self.scopes)

    def getToken(self, code):
        return self.security.auth(code)

    def getESIChar(self, token):
        self.security.update_token(token)
        try:
            self.security.refresh()
        except APIException as e:
            if str(e) == "HTTP Error 400: invalid_token":
                session.pop('token', None)
                session.pop('char', None)
                return redirect(url_for('page_routes.logout'))

        return self.security.verify()

    def isVerified(self, token):
        try:
            self.security.update_token(token)
        except:
            return False

        try:
            self.security.refresh()
            character = self.security.verify()
        except:
            return False
        session["char"] = character
        return True

    def getESIInfo(self, endpoint, obj):
        info = self.esi_app.op[endpoint](**obj)
        res = self.client.request(info)
        result = res.data
        try:
            if "response" in result:
                result = result["response"]
        except:
            pass
        return result

    def getESIInfoMP(self, endpoint, obj):
        info = self.esi_app.op[endpoint](**obj)
        res = self.client.head(info)

        if res.status == 200:
            number_of_pages = res.header["X-Pages"][0]
            ops = []
            for page in range(1, number_of_pages + 1):
                obj["page"] = page
                ops.append(self.esi_app.op[endpoint](**obj))
            results = self.client.multi_request(ops)
            return results
        return {}

    def subToken(self, refresh_token):
        self.security.update_token({
            'access_token': '',
            'expires_in': -1,
            'refresh_token': refresh_token
        })

    def getForceRefresh(self):
        return self.security.refresh()
Exemplo n.º 14
0
# with url = the swagger spec URL, leave strict to default
app = App.create(
    url="https://esi.tech.ccp.is/latest/swagger.json?datasource=tranquility")

# basic client, for public endpoints only
client = EsiClient(
    retry_requests=True,  # set to retry on http 5xx error (default False)
    header={
        'User-Agent':
        'Something CCP can use to contact you and that define your app'
    },
    raw_body_only=
    False,  # default False, set to True to never parse response and only return raw JSON string content.
)

# generate the operation tuple
# the parameters given are the actual parameters the endpoint requires
market_order_operation = app.op['get_markets_region_id_orders'](
    region_id=10000002,
    type_id=34,
    order_type='all',
)

# do the request
response = client.request(market_order_operation)

# use it: response.data contains the parsed result of the request.
print response.data[0].price

# to get the headers objects, you can get the header attribute
print response.header
Exemplo n.º 15
0
        verify=esi_security.verify()


        #Get access token and time token from esipy code after successful refresh (expiry method is custom changed)
        accesscode = esi_security._EsiSecurity__get_token_auth_header()
        accesscode = accesscode['Authorization'][8:]
        timestp = esi_security.is_token_expired2() #custom changed


        #The following is processing and your required data inquiry from ESI network

        myid = verify['CharacterID']
        myname = verify['CharacterName']

        wallet = esi_app.op['get_characters_character_id_wallets'](
        character_id =myid

                )

        walletdata = esi_client.request(wallet)

        #Present output


        print "%s's ISK:" % (myname)
        print (intWithCommas(int(float(walletdata.data[0]['balance'])/100)))

        #Optional, use dictionary for idcheck = "type_id in question"

        #print  result[str(idcheck)][0]
from esipy import App
from esipy import EsiClient
import json

app = App.create(
    url="https://esi.tech.ccp.is/latest/swagger.json?datasource=tranquility")
client = EsiClient(
    retry_requests=True,
    header={'User-Agent': 'DumpSkills'},
    raw_body_only=False,
)

fields = app.op['get_universe_categories_category_id'](category_id=16, )

response = client.request(fields)
groups = response.data['groups']

gral = {}

for group in groups:
    g = app.op['get_universe_groups_group_id'](group_id=group)
    response = client.request(g)
    group_name = response.data['name']
    skills = response.data['types']
    group_dict = {}

    for skill in skills:
        s = app.op['get_universe_types_type_id'](type_id=skill)
        response = client.request(s)
        group_dict[skill] = response.data['name']
    gral[group_name] = [{'Category ID': group}, group_dict]
Exemplo n.º 17
0
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.114 Safari/537.36'}
print("Downloading json files of killmails")
for date in cfg.dates:
    url = "https://zkillboard.com/api/history/" + date + ".json"
    print("Downloaded killmail list on " + date)
    response = requests.get(url, headers=headers)
    kill_dict = json.loads(response.content)
    print("Parsing kills on " + date)
    count = 0
    for key in kill_dict:
        count = count + 1
        if count % 100 == 0:
            print(count)

        killmail_fetch_operation = app.op['get_killmails_killmail_id_killmail_hash'](
            killmail_id=key,
            killmail_hash=kill_dict[key]
        )

        response = client.request(killmail_fetch_operation)
        kill_as_dict = json.loads(response.raw)
        timestamp = kill_as_dict["killmail_time"]
        timestamp = datetime.datetime.strptime(timestamp, '%Y-%m-%dT%H:%M:%SZ')
        timestamp = timestamp.replace(tzinfo=utc)

        insert_query = (
            "INSERT INTO killmails (killmail_id, killmail_hash, date, data) VALUES (%s, %s, %s, %s) ON CONFLICT DO NOTHING;"
        )
        cursor.execute(insert_query, (key, kill_dict[key], timestamp, json.dumps(kill_as_dict)))

Exemplo n.º 18
0
# and the client object, replace the header user agent value with something reliable !
client = EsiClient(retry_requests=True,
                   header={'User-Agent': '*****@*****.**'},
                   security=security)

# to update the security object,
security.update_token({
    'access_token':
    '',  # leave this empty
    'expires_in':
    -1,  # seconds until expiry, so we force refresh anyway
    'refresh_token':
    'yUI96Q6kOxvQ6ulwDnQ7VLD1I-4LH-Jz8DOY9Di4NhA1'
})

tokens = security.refresh()

# print tokens

op = app.op['get_markets_structures_structure_id'](structure_id=1022734985679,
                                                   page='-1')

structure = client.request(op)

y = 0

for x in structure.data:
    print str(structure.data[y].type_id) + ', ' + str(
        structure.data[y].price) + ', ' + str(structure.data[y].is_buy_order)
    y += 1
Exemplo n.º 19
0
class EsiCommands(Cog):
    def __init__(self, bot):
        self.bot = bot

        self.esi = EsiClient(
            retry_requests=True,
            headers={
                'User-Agent':
                f'application: MercuryBot contact: {self.bot.config["bot"]["user_agent"]}'
            })

    def _get_esi_id(self, search: str, category: str,
                    strict: bool) -> Union[list, int]:
        """
        Returns the ID for the specified query from ESI.
        :param search: string representing the search query
        :param category: the category to search against
        :param strict:
        :return: int ID if strict is true, otherwise list of IDs; -1 if not found
        """
        search_op = self.bot.esi_app.op['get_search'](
            categories=[category],
            search=search,
            strict=strict,
        )

        search_response = self.esi.request(search_op)

        if category not in search_response.data:
            return -1

        if strict:
            return search_response.data[category][0]
        else:
            return search_response.data[category]

    def _get_char_from_esi(self, char_id: int) -> Optional[dict]:
        """
        Gets public data for the specified character_id.
        :param char_id:
        :return:
        """
        char_op = self.bot.esi_app.op['get_characters_character_id'](
            character_id=char_id, )

        try:
            char_response = self.esi.request(char_op)
        except APIException as e:
            logger.error(
                f"Error getting char with id {char_id} from ESI! Error: {e}")
            logger.error(traceback.print_exc())
            return None

        return char_response.data

    def _get_alliance_from_esi(self, ally_id: int) -> Optional[dict]:
        """
        Gets public data for the specified alliance_id
        :param ally_id:
        :return:
        """
        ally_op = self.bot.esi_app.op['get_alliances_alliance_id'](
            alliance_id=ally_id, )

        try:
            ally_response = self.esi.request(ally_op)
        except APIException as e:
            logger.error(
                f"Error getting alliance with id {ally_id} from ESI! Error: {e}"
            )
            logger.error(traceback.print_exc())
            return None

        return ally_response.data

    def _get_corporation_from_esi(self, corp_id: int) -> Optional[dict]:
        """
        Gets public data for the specified corporation_id
        :param corp_id:
        :return:
        """
        corp_op = self.bot.esi_app.op['get_corporations_corporation_id'](
            corporation_id=corp_id, )

        try:
            corp_response = self.esi.request(corp_op)
        except APIException as e:
            logger.error(
                f"Error getting corporation with id {corp_id} from ESI! Error: {e}"
            )
            logger.error(traceback.print_exc())
            return None

        return corp_response.data

    def _get_system_from_esi(self, system_id: int) -> Optional[dict]:
        """
        Gets static system data from esi for the specified system_id
        :param system_id:
        :return:
        """
        sys_op = self.bot.esi_app.op['get_universe_systems_system_id'](
            system_id=system_id, )

        try:
            system_response = self.esi.request(sys_op)
        except APIException as e:
            logger.error(
                f"Error getting system with id {system_id} from ESI! Error: {e}"
            )
            logger.error(traceback.print_exc())
            return None

        return system_response.data

    def _get_region_from_esi(self, region_id: int) -> Optional[dict]:
        """
        Gets static region data from esi for the specified region_id.
        :param region_id:
        :return:
        """
        reg_op = self.bot.esi_app.op['get_universe_regions_region_id'](
            region_id=region_id)

        try:
            region_response = self.esi.request(reg_op)
        except APIException as e:
            logger.error(
                f"Error getting region with id {region_id} from ESI! Error: {e}"
            )
            logger.error(traceback.print_exc())
            return None

        return region_response.data

    def _get_constellation_from_esi(self,
                                    constellation_id: int) -> Optional[dict]:
        """
        Gets static constellation data from ESI for the specified constellation_id.
        :param constellation_id:
        :return:
        """
        const_op = self.bot.esi_app.op[
            'get_universe_constellations_constellation_id'](
                constellation_id=constellation_id)

        try:
            constellation_response = self.esi.request(const_op)
        except APIException as e:
            logger.error(
                f"Error getting constellation with id {constellation_id} from ESI! Error: {e}"
            )
            logger.error(traceback.print_exc())
            return None

        return constellation_response.data

    def _get_star_from_esi(self, star_id: int) -> Optional[dict]:
        """
        Gets the static star data from ESI for the given star_id.
        :param star_id:
        :return:
        """
        star_op = self.bot.esi_app.op['get_universe_stars_star_id'](
            star_id=star_id)

        try:
            star_response = self.esi.request(star_op)
        except APIException as e:
            logger.error(
                f"Error getting star with id {star_id} from ESI! Error: {a}")
            logger.error(traceback.print_exc())
            return None

        return star_response.data

    def _get_system_stats(self, system_id: int) -> Optional[dict]:
        """
        Returns the following data for a given system:
            - Jumps
            - Kills
            - Sovereignty
        :param system_id:
        :return:
        """
        # Get System Stats
        jump_op = self.bot.esi_app.op['get_universe_system_jumps']()
        kills_op = self.bot.esi_app.op['get_universe_system_kills']()
        sov_op = self.bot.esi_app.op['get_sovereignty_map']()

        try:
            jump_response = self.esi.request(jump_op)
            kills_response = self.esi.request(kills_op)
            sov_response = self.esi.request(sov_op)
        except APIException as e:
            logger.error(f"Error getting system stats from ESI! Error: {e}")
            logger.error(traceback.print_exc())
            return None

        ret = dict()
        ret['sov'] = None
        for sys in jump_response.data:
            if sys['system_id'] == system_id:
                ret['ship_jumps'] = sys['ship_jumps']
                break
        for sys in kills_response.data:
            if sys['system_id'] == system_id:
                ret['kills'] = sys
                break
        for sys in sov_response.data:
            if sys['system_id'] == system_id:
                if len(sys) == 1:
                    break
                ret['sov'] = sys
                break

        return ret

    @commands.command(aliases=('char', 'ch'))
    async def character(self, ctx, *, character_name: str):
        """
        Returns public data about the named character.
        """
        # Get ID from ESI
        char_id = self._get_esi_id(character_name, "character", True)
        if char_id == -1:
            return await ctx.send(
                "Character not found. Please check your spelling and try again."
            )

        # Get Public data
        char = self._get_char_from_esi(char_id)
        if char is None:
            return await ctx.send(
                "Something went wrong, please try again later.")

        corp = self._get_corporation_from_esi(char['corporation_id'])
        if corp is None:
            return await ctx.send(
                "Something went wrong, please try again later.")

        urln = quote_plus(char['name'])

        urls = {
            'zkb': f'https://zkillboard.com/character/{char_id}/',
            'who': f'https://evewho.com/pilot/{urln}'
        }

        dob = char['birthday'].v
        age = datetime.now(timezone.utc) - dob

        embed = discord.Embed(title=f'{char["name"]} Character Info')
        embed.set_author(name=self.bot.user.name,
                         icon_url=self.bot.user.avatar_url_as(format='png'))
        embed.set_thumbnail(
            url=f'https://imageserver.eveonline.com/Character/{char_id}_128.jpg'
        )

        # Fields

        embed.add_field(name='Corporation',
                        value=f'{corp["name"]} [{corp["ticker"]}]',
                        inline=True)
        embed.add_field(name='\u200B', value='\u200B',
                        inline=True)  # Empty Field
        if corp['alliance_id'] is not None:
            ally = self._get_alliance_from_esi(corp['alliance_id'])
            if ally is None:
                return await ctx.send(
                    "Something went wrong, please try again later.")
            embed.add_field(name='Alliance',
                            value=f'{ally["name"]} [{ally["ticker"]}]')
        embed.add_field(name='Birthday',
                        value=dob.strftime("%a %d %b, %Y"),
                        inline=True)
        embed.add_field(name='\u200B', value='\u200B',
                        inline=True)  # Empty Field
        embed.add_field(name='Age', value=strftdelta(age), inline=True)
        embed.add_field(name='Additional Information',
                        value=f'{urls["zkb"]}\n{urls["who"]}',
                        inline=False)

        return await ctx.send(embed=embed)

    @commands.command(aliases=('corp', 'co'))
    async def corporation(self, ctx, *, corporation: str):
        """
        Returns public data about the specified corporation.
        """
        # Get ID
        corp_id = self._get_esi_id(corporation, "corporation", True)
        if corp_id == -1:
            return await ctx.send(
                "Corporation not found. Please check your spelling and try again."
            )

        # Get Corp data
        corp = self._get_corporation_from_esi(corp_id)
        if corp is None:
            return await ctx.send(
                "Something went wrong, please try again later.")

        ceo = self._get_char_from_esi(corp['ceo_id'])
        if ceo is None:
            return await ctx.send(
                "Something went wrong, please try again later.")

        urls = {
            'zkb': f'https://zkillboard.com/corporation/{corp_id}/',
            'dotlan': f'https://evemaps.dotlan.net/corp/{corp_id}'
        }

        embed = discord.Embed(title=f'{corp["name"]} Corp Info',
                              color=discord.Color.green())
        embed.set_author(name=self.bot.user.name,
                         icon_url=self.bot.user.avatar_url_as(format='png'))
        embed.set_thumbnail(
            url=
            f'https://imageserver.eveonline.com/Corporation/{corp_id}_128.png')

        # Fields

        embed.add_field(name='Ticker',
                        value=f'[{corp["ticker"]}]',
                        inline=True)
        embed.add_field(name='\u200B', value='\u200B',
                        inline=True)  # Empty Field
        embed.add_field(name='Member Count',
                        value=f'{corp["member_count"]}',
                        inline=True)
        embed.add_field(name='CEO', value=f'{ceo["name"]}', inline=True)
        embed.add_field(name='\u200B', value='\u200B',
                        inline=True)  # Empty Field
        if corp['date_founded'] is not None:
            embed.add_field(
                name='Founded',
                value=corp["date_founded"].v.strftime("%a %d %b, %Y"),
                inline=True)
        if corp['alliance_id'] is not None:
            ally = self._get_alliance_from_esi(corp['alliance_id'])
            if ally is None:
                return ctx.send(
                    "Something went wrong, please try again later.")
            embed.add_field(name='Alliance',
                            value=f'{ally["name"]} [{ally["ticker"]}]',
                            inline=False)
        embed.add_field(name='Additional Information',
                        value=f'{urls["zkb"]}\n{urls["dotlan"]}',
                        inline=False)

        return await ctx.send(embed=embed)

    @commands.command(aliases=('ally', ))
    async def alliance(self, ctx, *, alliance: str):
        """
        Returns public data about the specified alliance.
        """
        ally_id = self._get_esi_id(alliance, "alliance", True)
        if ally_id == -1:
            return await ctx.send(
                "Alliance not found. Please check your spelling and try again."
            )

        ally = self._get_alliance_from_esi(ally_id)
        if ally is None:
            return await ctx.send(
                "Something went wrong, please try again later.")

        found_corp = self._get_corporation_from_esi(
            ally['creator_corporation_id'])
        if found_corp is None:
            return await ctx.send(
                "Something went wrong, please try again later.")

        founder = self._get_char_from_esi(ally['creator_id'])
        if founder is None:
            return await ctx.send(
                "Something went wrong, please try again later.")

        exec_corp = None
        if 'executor_corporation_id' in ally:
            exec_corp = self._get_corporation_from_esi(
                ally['executor_corporation_id'])
            if exec_corp is None:
                return await ctx.send(
                    "Something went wrong, please try again later.")

        urls = {
            'zkb': f'https://zkillboard.com/alliance/{ally_id}/',
            'dotlan': f'https://evemaps.dotlan.net/alliance/{ally_id}'
        }

        title = f'{ally["name"]} Alliance Info'
        if exec_corp is None:
            title = title + ' (Closed)'

        embed = discord.Embed(title=title, color=discord.Color.blue())
        embed.set_author(name=self.bot.user.name,
                         icon_url=self.bot.user.avatar_url_as(format='png'))
        embed.set_thumbnail(
            url=f'https://imageserver.eveonline.com/Alliance/{ally_id}_128.png'
        )

        # Fields

        embed.add_field(name='Ticker',
                        value=f'[{ally["ticker"]}]',
                        inline=True)
        embed.add_field(name='\u200B', value='\u200B',
                        inline=True)  # Empty Field
        if exec_corp is not None:
            embed.add_field(
                name='Executor Corp',
                value=f'{exec_corp["name"]} [{exec_corp["ticker"]}]',
                inline=True)

        embed.add_field(name='Founder',
                        value=f'{founder["name"]}',
                        inline=True)
        embed.add_field(name='\u200B', value='\u200B',
                        inline=True)  # Empty Field
        embed.add_field(name='Founding Corp',
                        value=f'{found_corp["name"]} [{found_corp["ticker"]}]',
                        inline=True)

        embed.add_field(name='Founding Date',
                        value=ally["date_founded"].v.strftime("%a %d %b, %Y"),
                        inline=True)
        embed.add_field(name='Additional Information',
                        value=f'{urls["zkb"]}\n{urls["dotlan"]}',
                        inline=False)

        return await ctx.send(embed=embed)

    @commands.command()
    async def status(self, ctx):
        """
        Returns the current status of Tranquility
        """
        # Get ESI status
        status_op = self.bot.esi_app.op['get_status']()

        try:
            status_response = self.esi.request(status_op)
            status_response = status_response.data
        except APIException as e:
            embed = discord.Embed(title="Tranquility Status",
                                  color=discord.Color.red())
            embed.set_author(
                name=self.bot.user.name,
                icon_url=self.bot.user.avatar_url_as(format='png'))
            embed.set_thumbnail(
                url=
                f'https://en.wikipedia.org/wiki/CCP_Games#/media/File:CCP_Games_Logo.svg'
            )

            embed.add_field(name="Status", value="*Offline*", inline=True)

            return await ctx.send(embed=embed)

        embed = discord.Embed(title="Tranquility Status",
                              color=discord.Color.green())
        embed.set_author(name=self.bot.user.name,
                         icon_url=self.bot.user.avatar_url_as(format='png'))
        embed.set_thumbnail(
            url=f'https://e.dotlan.net/images/Alliance/434243723_128.png')

        status = "Online"
        if "vip" in status_response:
            if status_response["vip"]:
                status = f"*{status} (VIP)*"

        embed.add_field(name="Status", value=status, inline=True)
        embed.add_field(name='\u200B', value='\u200B',
                        inline=True)  # Empty Field
        embed.add_field(name="Player Count",
                        value='{:,}'.format(status_response['players']),
                        inline=True)

        embed.add_field(name="Server Version",
                        value=status_response['server_version'],
                        inline=True)
        embed.add_field(name='\u200B', value='\u200B',
                        inline=True)  # Empty Field
        embed.add_field(name="Uptime",
                        value=strftdelta(
                            datetime.now(timezone.utc) -
                            status_response['start_time'].v),
                        inline=True)

        return await ctx.send(embed=embed)

    @commands.command(aliases=('sys', ))
    async def system(self, ctx, *, system_name: str):
        """
        Returns data about the specified system.
        """
        if re.match(r'[Jj]([0-9]{6})', system_name) or system_name == "Thera":
            return await ctx.send(
                'System Information not available for wormhole systems.')

        # Get System ID
        sys_id = self._get_esi_id(system_name, 'solar_system', True)
        if sys_id == -1:
            return await ctx.send(
                "System not found. Please check your spelling and try again.")

        # Get System Data
        system = self._get_system_from_esi(sys_id)
        if system is None:
            return await ctx.send(
                "Something went wrong, please try again later.")

        if 'planets' in system:
            planets = len(system['planets'])
            moons = 0
            for planet in system['planets']:
                if 'moons' in planet:
                    moons += len(planet['moons'])
        else:
            planets = 0
            moons = 0

        star = self._get_star_from_esi(system['star_id'])

        constellation = self._get_constellation_from_esi(
            system['constellation_id'])
        if constellation is None:
            return await ctx.send(
                "Something went wrong, please try again later.")

        region = self._get_region_from_esi(constellation['region_id'])
        if region is None:
            return await ctx.send(
                "Something went wrong, please try again later.")

        stats = self._get_system_stats(sys_id)
        thumb_url = f'https://images.evetech.net/types/{star["type_id"]}/icon'
        if stats['sov'] is not None:
            if 'faction_id' in stats['sov']:
                thumb_url = f'https://images.evetech.net/corporations/{stats["sov"]["faction_id"]}/logo'
            elif 'alliance_id' in stats['sov']:
                thumb_url = f'https://images.evetech.net/alliances/{stats["sov"]["alliance_id"]}/logo'
            elif 'corporation_id' in stats['sov']:
                thumb_url = f'https://images.evetech.net/corporations/{stats["sov"]["corporation_id"]}/logo'

        dotlan = f'http://evemaps.dotlan.net/system/{sys_id}/'
        zkill = f'https://zkillboard.com/system/{sys_id}/'

        embed = discord.Embed(title=f'{system["name"]} System Information')
        embed.set_author(
            name='CCP Games',
            icon_url='https://e.dotlan.net/images/Alliance/434243723_128.png')
        embed.set_thumbnail(url=thumb_url)

        # Fields

        embed.add_field(
            name='Sec Status / Class',
            value=
            f'{"{:.2f}".format(system["security_status"])} / {system["security_class"]}'
        )
        embed.add_field(name='\u200B', value='\u200B',
                        inline=True)  # Empty Field
        embed.add_field(name='Region (Constellation)',
                        value=f'{region["name"]} ({constellation["name"]})')

        embed.add_field(name='Planets / Moons', value=f'{planets} / {moons}')
        embed.add_field(name='\u200B', value='\u200B',
                        inline=True)  # Empty Field
        if 'stargates' in system:
            embed.add_field(name='Stargates',
                            value=str(len(system['stargates'])))

        embed.add_field(name='Stats (Last Hour)',
                        value=f'**Jumps:** {stats["ship_jumps"]} \n'
                        f'**Ship Kills**: {stats["kills"]["ship_kills"]} \n'
                        f'**NPC Kills:** {stats["kills"]["npc_kills"]}\n'
                        f'**Pod Kills:** {stats["kills"]["pod_kills"]}',
                        inline=False)
        embed.add_field(name='Additional Info', value=f'{dotlan} \n{zkill}')

        return await ctx.send(embed=embed)
Exemplo n.º 20
0
    })
    token = security.refresh()

token

#%%
security.update_token({
    'access_token': '',
    'expires_in': -1,
    'refresh_token': 'Pc4C1iK6p0evpU3dBSkSwg=='
})
token = security.refresh()

#%%
operation = app_latest.op['get_status']()
client.request(operation).data

#%%
server_status = KIN3_Esi.check_server_status(esi_objects)
'players' in server_status

#%%
operation = app_latest.op['get_characters_character_id_fittings'](
    character_id='97199391')
client.request(operation).data

#%%
operation = app_v2.op['get_characters_character_id_fleet'](
    character_id='97199391')
fleet_id = client.request(operation).data['fleet_id']
fleet_id
Exemplo n.º 21
0
'''This was the first attempt using esipy to get kill data from CCP. Quickly transistioned away from using esipy due to its slownes'''

from esipy import App

# App.create(url, strict=True)
# with url = the swagger spec URL, leave strict to default
app = App.create(
    url="https://esi.tech.ccp.is/latest/swagger.json?datasource=tranquility")

#appS = App.create(url="https://esi.tech.ccp.is/latest/swagger.json?datasource=tranquility")

from esipy import EsiClient

# basic client, for public endpoints only
client = EsiClient(
    retry_requests=True,  # set to retry on http 5xx error (default False)
    header={
        'User-Agent':
        'Something CCP can use to contact you and that define your app'
    },
    raw_body_only=
    False,  # default False, set to True to never parse response and only return raw JSON string content.
)

# generate the operation tuple
# the parameters given are the actual parameters the endpoint requires
kills = app.op['get_universe_system_kills']()
response = client.request(kills)

print(response.data)
Exemplo n.º 22
0
class ESI:
    def __init__(self,
                 client_id,
                 secret_key,
                 refresh_token,
                 cache_path,
                 prefix='esipy'):
        self.client_id = client_id
        self.secret_key = secret_key
        self.refresh_token = refresh_token
        self.cache_path = cache_path
        self.prefix = prefix

        self._start()

    def _start(self):
        self.cache = FileCache(path=self.cache_path)
        self.esi_app = EsiApp(cache=self.cache, cache_prefix=self.prefix)
        self.app = self.esi_app.get_latest_swagger
        self.security = EsiSecurity(
            app=self.app,
            redirect_uri='http://localhost/oauth-callback',  # This doesnt matter
            headers={
                'User-Agent':
                'Discord bot by Prozn: https://github.com/prozn/dankcord'
            },
            client_id=self.client_id,
            secret_key=self.secret_key,
        )
        self.esi = EsiClient(
            retry_requests=
            False,  # set to retry on http 5xx error (default False)
            headers={
                'User-Agent':
                'Discord bot by Prozn: https://github.com/prozn/dankcord'
            },
            security=self.security)
        self.security.update_token({
            'access_token': '',  # leave this empty
            'expires_in':
            -1,  # seconds until expiry, so we force refresh anyway
            'refresh_token': self.refresh_token
        })
        self.security.refresh()

    @esiexcept
    def character_info(self, character_id):
        op = self.app.op['get_characters_character_id'](
            character_id=character_id)
        character = self.esi.request(op, raise_on_error=True)
        return character

    def character_name(self, character_id):
        character = self.character_info(character_id)
        if not character:
            return False
        return character.data.name

    @esiexcept
    def id_name(self, id):
        op = self.app.op['post_universe_names'](ids=[id])
        names = self.esi.request(op, raise_on_error=True)
        return names.data[0].name

    @esiexcept
    def corp_contracts(self, corporation_id, raw=False):
        op = self.app.op['get_corporations_corporation_id_contracts'](
            corporation_id=corporation_id)
        contracts = self.esi.request(op,
                                     raise_on_error=True,
                                     raw_body_only=raw)
        if raw:
            return contracts.raw
        else:
            return contracts.data

    @esiexcept
    def get_system_name(self, system_id):
        op = self.app.op['get_universe_systems_system_id'](system_id=system_id)
        system = self.esi.request(op, raise_on_error=True)
        return system.data.name

    @esiexcept
    def location_details(self, location_id):
        if location_id > 1000000000000:  # it is a citadel
            location_type = 'citadel'
            op = self.app.op['get_universe_structures_structure_id'](
                structure_id=location_id)
        else:  # it is a station
            location_type = 'station'
            op = self.app.op['get_universe_stations_station_id'](
                station_id=location_id)
        location = self.esi.request(op, raise_on_error=True)
        if location_type == 'citadel':
            system = location.data.solar_system_id
        else:
            system = location.data.system_id
        details = {
            'location_id': location_id,
            'location_type': location_type,
            'system_id': system,
            'name': location.data.name
        }
        return details

    @esiexcept
    def personal_contracts(self):
        raise NotImplementedError
Exemplo n.º 23
0
    header={'User-Agent': '*****@*****.**'},
    raw_body_only=False,
)

# 'skill_points_required' : {
#   1 : 250 * rank,
#   2 : 1415 if rank == 1 else int(rank * 1414.3 + 0.5),
#   3 : 8000 * rank,
#   # (2.5 * level - 2.5)
#   4 : int(math.ceil((2.5 * 4 - 2.5)**2 * 250 * rank)),
#   5 : 256000 * rank,
# },

# Get market prices into a dict
market_operation = app.op['markets_prices']()
market_response = client.request(market_operation)
market_info = market_response.data
market_prices = {
    price.get('type_id'): price.get("average_price")
    for price in market_info
}

# Get Alpha skills into a dict
alpha_skills = {}
with open(alpha_skill_list, 'r') as fin:
    next(fin)
    reader = csv.reader(fin, delimiter='\t')
    for group, skill, cap, points in reader:
        alpha_skills[skill] = cap

# Get skill groups
Exemplo n.º 24
0
# YOUR_CODE is the code you got from Step 3. (do not forget quotes around it)
tokens = security.auth(authcode)
print(tokens)

# use the verify endpoint to know who we are
api_info = security.verify()

print(api_info)
# api_info contains data like this
# {
#   "Scopes": "esi-wallet.read_character_wallet.v1",
#   "ExpiresOn": "2017-07-14T21:09:20",
#   "TokenType": "Character",
#   "CharacterName": "SOME Char",
#   "IntellectualProperty": "EVE",
#   "CharacterOwnerHash": "4raef4rea8aferfa+E=",
#   "CharacterID": 123456789
# }

# now get the wallet data
op = app.op['get_characters_character_id_wallet'](
    character_id=api_info['CharacterID']
)
wallet = client.request(op)

# and to see the data behind, let's print it
print(wallet.data)

with open('tokens.txt', 'w') as outfile:
    json.dump(tokens, outfile)
Exemplo n.º 25
0
class LinkListener(Cog):
    def __init__(self, bot):
        self.bot = bot

        self.esi = EsiClient(
            retry_requests=True,
            headers={
                'User-Agent':
                f'application: MercuryBot contact: {self.bot.config["bot"]["user_agent"]}'
            })

    async def _get_killmail(self, kill_id: int) -> dict:
        """
        Get killmail from zkill and ESI.
        :param kill_id:
        :return:
        """

        # Get zkill data
        kill_api_url = f'https://zkillboard.com/api/killID/{kill_id}/'
        async with aiohttp.ClientSession() as session:
            zkill_km = await get_json(session, kill_api_url)

        zkill_km = zkill_km['resp'][0]

        # Get KM data via ESI
        km_op = self.bot.esi_app.op['get_killmails_killmail_id_killmail_hash'](
            killmail_id=kill_id,
            killmail_hash=zkill_km['zkb']['hash'],
        )

        km_response = self.esi.request(km_op)

        km = km_response.data
        km['zkb'] = zkill_km['zkb']

        return km

    async def _get_character_name_from_id(self,
                                          character_id: int) -> Optional[str]:
        """
        Returns the name of a character for a given character_id.
            Returns None if the ID is not valid.
        :param character_id:
        :return:
        """
        name_op = self.bot.esi_app.op["get_characters_character_id"](
            character_id=character_id)

        try:
            name_response = self.esi.request(name_op)
        except APIException:
            logger.error(
                f'Error getting name for character with ID {character_id} from ESI.'
            )
            logger.error(traceback.print_exc())
            return None

        return name_response.data['name']

    async def type_from_id(self, type_id: int) -> Optional[dict]:
        """
        Returns a type ID from ESI for a given name.
            Return value of None indicates an invalid type name.
        :param type_id:
        :return:
        """
        post_op = self.bot.esi_app.op['get_universe_types_type_id'](
            type_id=type_id)

        try:
            response = self.esi.request(post_op)
        except APIException:
            logger.error(f"Issue getting Type with ID {type_id} from ESI!")
            logger.error(traceback.print_exc())
            return None

        return response.data

    @Cog.listener()
    async def on_message(self, message: discord.Message):
        if message.author == self.bot.user:
            return

        # Check for links
        re_match = re.match(
            r'(.*)(http[s]?://([A-Za-z]*).[a-zA-z]*(/[a-zA-z]*/?)([0-9]*)[a-zA-Z/]?)',
            message.content)
        """
         Match Groups:
         Group 1 (match[1]): anything preceding the link.
         Group 2 (match[2]): The link in its entirety
         Group 3 (match[3]): The domain of the URL. This is how we determine if/how to process it.
         Group 4 (match[4]): Only used for zkill at the moment, to determine if the URL is a kill or not.
         Group 5 (match[5]): The ID we will need for processing. We know that all the services we want to process use 
                             only numeric IDs, so this is fine. (Though probably not the best if we wanted to add 
                             dscan.me support or something.
        """
        if re_match:
            if re_match[3] == 'zkillboard':
                if re_match[4] == '/kill/':
                    km = await self._get_killmail(re_match[5])
                    data = extract_mail_data(self.bot.esi_app, self.esi, km)
                    embed = await build_kill_embed(data)

                    return await message.reply(embed=embed)
                elif re_match[4] == '/character/':
                    char_id = re_match[5]
                    stats = await get_char_stats_from_zkill(char_id)
                    if stats is None:
                        return
                    char_name = await self._get_character_name_from_id(char_id)

                    embed = await build_threat_embed(stats, char_name, char_id)

                    return await message.reply(embed=embed)
                else:
                    return
            elif re_match[3] == 'evemarketer':
                type_id = re_match[5]
                type_data = await self.type_from_id(type_id)
                # Rename the type_id key for compatability with embed builder.
                type_data['id'] = type_data.pop('type_id')
                market_data = await get_market_data(type_id)

                embed = await build_market_embed(type_data,
                                                 market_data['resp'])

                return await message.reply(embed=embed)
            else:
                return