Move over all esi stuff to it's own class, which the esi service extends from. Also fix an issue in the EVE fittings browser where deleting a fit didn't actually remove it from the list of fits (due to that list being populated by the return data of ESI, which can be cached). More clean up.
This commit is contained in:
@@ -32,23 +32,11 @@ class SsoCharacter(object):
|
||||
self.accessToken = accessToken
|
||||
self.refreshToken = refreshToken
|
||||
self.accessTokenExpires = None
|
||||
self.esi_client = None
|
||||
|
||||
|
||||
@reconstructor
|
||||
def init(self):
|
||||
self.esi_client = None
|
||||
|
||||
def get_sso_data(self):
|
||||
""" Little "helper" function to get formated data for esipy security
|
||||
"""
|
||||
return {
|
||||
'access_token': self.accessToken,
|
||||
'refresh_token': self.refreshToken,
|
||||
'expires_in': (
|
||||
self.accessTokenExpires - datetime.datetime.utcnow()
|
||||
).total_seconds()
|
||||
}
|
||||
pass
|
||||
|
||||
def is_token_expired(self):
|
||||
if self.accessTokenExpires is None:
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import time
|
||||
import webbrowser
|
||||
import json
|
||||
# noinspection PyPackageRequirements
|
||||
import wx
|
||||
@@ -15,8 +13,8 @@ from gui.display import Display
|
||||
import gui.globalEvents as GE
|
||||
|
||||
from logbook import Logger
|
||||
import calendar
|
||||
from service.esi import Esi, APIException
|
||||
from service.esi import Esi
|
||||
from service.esiAccess import APIException
|
||||
from service.port import ESIExportException
|
||||
|
||||
pyfalog = Logger(__name__)
|
||||
@@ -110,11 +108,11 @@ class EveFittings(wx.Frame):
|
||||
waitDialog = wx.BusyInfo("Fetching fits, please wait...", parent=self)
|
||||
|
||||
try:
|
||||
fittings = sEsi.getFittings(self.getActiveCharacter())
|
||||
self.fittings = sEsi.getFittings(self.getActiveCharacter())
|
||||
# self.cacheTime = fittings.get('cached_until')
|
||||
# self.updateCacheStatus(None)
|
||||
# self.cacheTimer.Start(1000)
|
||||
self.fitTree.populateSkillTree(fittings)
|
||||
self.fitTree.populateSkillTree(self.fittings)
|
||||
del waitDialog
|
||||
except requests.exceptions.ConnectionError:
|
||||
msg = "Connection error, please check your internet connection"
|
||||
@@ -149,6 +147,9 @@ class EveFittings(wx.Frame):
|
||||
if dlg.ShowModal() == wx.ID_YES:
|
||||
try:
|
||||
sEsi.delFitting(self.getActiveCharacter(), data['fitting_id'])
|
||||
# repopulate the fitting list
|
||||
self.fitTree.populateSkillTree(self.fittings)
|
||||
self.fitView.update([])
|
||||
except requests.exceptions.ConnectionError:
|
||||
msg = "Connection error, please check your internet connection"
|
||||
pyfalog.error(msg)
|
||||
@@ -156,8 +157,9 @@ class EveFittings(wx.Frame):
|
||||
|
||||
|
||||
class ESIExceptionHandler(object):
|
||||
# todo: make this a generate excetpion handler for all calls
|
||||
def __init__(self, parentWindow, ex):
|
||||
if ex.response['error'] == "invalid_token":
|
||||
if ex.response['error'].startswith('Token is not valid'):
|
||||
dlg = wx.MessageDialog(parentWindow,
|
||||
"There was an error validating characters' SSO token. Please try "
|
||||
"logging into the character again to reset the token.", "Invalid Token",
|
||||
@@ -361,9 +363,13 @@ class FittingsTreeView(wx.Panel):
|
||||
tree = self.fittingsTreeCtrl
|
||||
tree.DeleteChildren(root)
|
||||
|
||||
sEsi = Esi.getInstance()
|
||||
|
||||
dict = {}
|
||||
fits = data
|
||||
for fit in fits:
|
||||
if (fit['fitting_id'] in sEsi.fittings_deleted):
|
||||
continue
|
||||
ship = getItem(fit['ship_type_id'])
|
||||
if ship.name not in dict:
|
||||
dict[ship.name] = []
|
||||
|
||||
211
service/esi.py
211
service/esi.py
@@ -2,82 +2,33 @@
|
||||
import wx
|
||||
from logbook import Logger
|
||||
import threading
|
||||
import uuid
|
||||
import time
|
||||
import config
|
||||
import base64
|
||||
import json
|
||||
import os
|
||||
import config
|
||||
import webbrowser
|
||||
|
||||
import eos.db
|
||||
import datetime
|
||||
from eos.enum import Enum
|
||||
from eos.saveddata.ssocharacter import SsoCharacter
|
||||
from service.esiAccess import APIException
|
||||
import gui.globalEvents as GE
|
||||
from service.server import StoppableHTTPServer, AuthHandler
|
||||
from service.settings import EsiSettings
|
||||
from service.esiAccess import EsiAccess
|
||||
|
||||
import wx
|
||||
from requests import Session
|
||||
|
||||
pyfalog = Logger(__name__)
|
||||
|
||||
from urllib.parse import urlencode
|
||||
|
||||
# todo: reimplement Caching for calls
|
||||
# from esipy.cache import FileCache
|
||||
# file_cache = FileCache(cache_path)
|
||||
# cache_path = os.path.join(config.savePath, config.ESI_CACHE)
|
||||
#
|
||||
# if not os.path.exists(cache_path):
|
||||
# os.mkdir(cache_path)
|
||||
#
|
||||
|
||||
sso_url = "https://www.pyfa.io" # "https://login.eveonline.com" for actual login
|
||||
esi_url = "https://esi.tech.ccp.is"
|
||||
|
||||
oauth_authorize = '%s/oauth/authorize' % sso_url
|
||||
oauth_token = '%s/oauth/token' % sso_url
|
||||
|
||||
|
||||
class APIException(Exception):
|
||||
""" Exception for SSO related errors """
|
||||
|
||||
def __init__(self, url, code, json_response):
|
||||
self.url = url
|
||||
self.status_code = code
|
||||
self.response = json_response
|
||||
super(APIException, self).__init__(str(self))
|
||||
|
||||
def __str__(self):
|
||||
if 'error' in self.response:
|
||||
return 'HTTP Error %s: %s' % (self.status_code,
|
||||
self.response['error'])
|
||||
elif 'message' in self.response:
|
||||
return 'HTTP Error %s: %s' % (self.status_code,
|
||||
self.response['message'])
|
||||
return 'HTTP Error %s' % (self.status_code)
|
||||
|
||||
|
||||
class ESIEndpoints(Enum):
|
||||
CHAR = "/v4/characters/{character_id}/"
|
||||
CHAR_SKILLS = "/v4/characters/{character_id}/skills/" # prepend https://esi.evetech.net/
|
||||
CHAR_FITTINGS = "/v1/characters/{character_id}/fittings/"
|
||||
CHAR_DEL_FIT = "/v1/characters/{character_id}/fittings/{fitting_id}/"
|
||||
|
||||
class Servers(Enum):
|
||||
TQ = 0
|
||||
SISI = 1
|
||||
|
||||
|
||||
class LoginMethod(Enum):
|
||||
SERVER = 0
|
||||
MANUAL = 1
|
||||
|
||||
|
||||
class Esi(object):
|
||||
class Esi(EsiAccess):
|
||||
_instance = None
|
||||
|
||||
@classmethod
|
||||
@@ -88,6 +39,7 @@ class Esi(object):
|
||||
return cls._instance
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.settings = EsiSettings.getInstance()
|
||||
|
||||
# these will be set when needed
|
||||
@@ -97,32 +49,14 @@ class Esi(object):
|
||||
|
||||
self.implicitCharacter = None
|
||||
|
||||
# until I can get around to making proper caching and modifications to said cache, storee deleted fittings here
|
||||
# so that we can easily hide them in the fitting browser
|
||||
self.fittings_deleted = set()
|
||||
|
||||
# need these here to post events
|
||||
import gui.mainFrame # put this here to avoid loop
|
||||
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
|
||||
|
||||
if sso_url is None or sso_url == "":
|
||||
raise AttributeError("sso_url cannot be None or empty "
|
||||
"without app parameter")
|
||||
|
||||
self.oauth_authorize = '%s/oauth/authorize' % sso_url
|
||||
self.oauth_token = '%s/oauth/token' % sso_url
|
||||
|
||||
# use ESI url for verify, since it's better for caching
|
||||
if esi_url is None or esi_url == "":
|
||||
raise AttributeError("esi_url cannot be None or empty")
|
||||
self.oauth_verify = '%s/verify/' % esi_url
|
||||
|
||||
|
||||
# session request stuff
|
||||
self._session = Session()
|
||||
self._session.headers.update({
|
||||
'Accept': 'application/json',
|
||||
'User-Agent': (
|
||||
'pyfa v{}'.format(config.version)
|
||||
)
|
||||
})
|
||||
|
||||
def delSsoCharacter(self, id):
|
||||
char = eos.db.getSsoCharacter(id, config.getClientSecret())
|
||||
|
||||
@@ -139,66 +73,35 @@ class Esi(object):
|
||||
return chars
|
||||
|
||||
def getSsoCharacter(self, id):
|
||||
"""
|
||||
Get character, and modify to include the eve connection
|
||||
"""
|
||||
char = eos.db.getSsoCharacter(id, config.getClientSecret())
|
||||
if char is not None and char.esi_client is None:
|
||||
char.esi_client = Esi.genEsiClient()
|
||||
Esi.update_token(char, Esi.get_sso_data(char)) # don't use update_token on security directly, se still need to apply the values here
|
||||
|
||||
eos.db.commit()
|
||||
return char
|
||||
|
||||
|
||||
def getSkills(self, id):
|
||||
char = self.getSsoCharacter(id)
|
||||
resp = self.get(char, ESIEndpoints.CHAR_SKILLS, character_id=char.characterID)
|
||||
# resp = self.check_response(char.esi_client.request(op))
|
||||
resp = super().getSkills(char)
|
||||
return resp.json()
|
||||
|
||||
def getSecStatus(self, id):
|
||||
char = self.getSsoCharacter(id)
|
||||
resp = self.get(char, ESIEndpoints.CHAR, character_id=char.characterID)
|
||||
resp = super().getSecStatus(char)
|
||||
return resp.json()
|
||||
|
||||
def getFittings(self, id):
|
||||
char = self.getSsoCharacter(id)
|
||||
resp = self.get(char, ESIEndpoints.CHAR_FITTINGS, character_id=char.characterID)
|
||||
resp = super().getFittings(char)
|
||||
return resp.json()
|
||||
|
||||
def postFitting(self, id, json_str):
|
||||
# @todo: new fitting ID can be recovered from resp.data,
|
||||
char = self.getSsoCharacter(id)
|
||||
resp = self.post(char, ESIEndpoints.CHAR_FITTINGS, json_str, character_id=char.characterID)
|
||||
resp = super().postFitting(char, json_str)
|
||||
return resp.json()
|
||||
|
||||
def delFitting(self, id, fittingID):
|
||||
char = self.getSsoCharacter(id)
|
||||
self.delete(char, ESIEndpoints.CHAR_DEL_FIT, character_id=char.characterID, fitting_id=fittingID)
|
||||
|
||||
def check_response(self, resp):
|
||||
# if resp.status >= 400:
|
||||
# raise EsiException(resp.status)
|
||||
return resp
|
||||
|
||||
@staticmethod
|
||||
def get_sso_data(char):
|
||||
""" Little "helper" function to get formated data for esipy security
|
||||
"""
|
||||
return {
|
||||
'access_token': char.accessToken,
|
||||
'refresh_token': config.cipher.decrypt(char.refreshToken).decode(),
|
||||
'expires_in': (char.accessTokenExpires - datetime.datetime.utcnow()).total_seconds()
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def update_token(char, tokenResponse):
|
||||
""" helper function to update token data from SSO response """
|
||||
char.accessToken = tokenResponse['access_token']
|
||||
char.accessTokenExpires = datetime.datetime.fromtimestamp(time.time() + tokenResponse['expires_in'])
|
||||
if 'refresh_token' in tokenResponse:
|
||||
char.refreshToken = config.cipher.encrypt(tokenResponse['refresh_token'].encode())
|
||||
super().delFitting(char, fittingID)
|
||||
self.fittings_deleted.add(fittingID)
|
||||
|
||||
def login(self):
|
||||
serverAddr = None
|
||||
@@ -213,24 +116,6 @@ class Esi(object):
|
||||
self.httpd.stop()
|
||||
self.httpd = None
|
||||
|
||||
def getLoginURI(self, redirect=None):
|
||||
self.state = str(uuid.uuid4())
|
||||
|
||||
args = {
|
||||
'state': self.state,
|
||||
'pyfa_version': config.version,
|
||||
'login_method': self.settings.get('loginMode'),
|
||||
'client_hash': config.getClientSecret()
|
||||
}
|
||||
|
||||
if redirect is not None:
|
||||
args['redirect'] = redirect
|
||||
|
||||
return '%s?%s' % (
|
||||
oauth_authorize,
|
||||
urlencode(args)
|
||||
)
|
||||
|
||||
def startServer(self): # todo: break this out into two functions: starting the server, and getting the URI
|
||||
pyfalog.debug("Starting server")
|
||||
|
||||
@@ -248,44 +133,6 @@ class Esi(object):
|
||||
|
||||
return 'http://localhost:{}'.format(port)
|
||||
|
||||
def get_oauth_header(self, token):
|
||||
""" Return the Bearer Authorization header required in oauth calls
|
||||
|
||||
:return: a dict with the authorization header
|
||||
"""
|
||||
return {'Authorization': 'Bearer %s' % token}
|
||||
|
||||
def get_refresh_token_params(self, refreshToken):
|
||||
""" Return the param object for the post() call to get the access_token
|
||||
from the refresh_token
|
||||
|
||||
:param code: the refresh token
|
||||
:return: a dict with the url, params and header
|
||||
"""
|
||||
if refreshToken is None:
|
||||
raise AttributeError('No refresh token is defined.')
|
||||
|
||||
return {
|
||||
'data': {
|
||||
'grant_type': 'refresh_token',
|
||||
'refresh_token': refreshToken,
|
||||
},
|
||||
'url': self.oauth_token,
|
||||
}
|
||||
|
||||
def refresh(self, ssoChar):
|
||||
request_data = self.get_refresh_token_params(config.cipher.decrypt(ssoChar.refreshToken).decode())
|
||||
res = self._session.post(**request_data)
|
||||
if res.status_code != 200:
|
||||
raise APIException(
|
||||
request_data['url'],
|
||||
res.status_code,
|
||||
res.json()
|
||||
)
|
||||
json_res = res.json()
|
||||
self.update_token(ssoChar, json_res)
|
||||
return json_res
|
||||
|
||||
def handleLogin(self, ssoInfo):
|
||||
auth_response = json.loads(base64.b64decode(ssoInfo))
|
||||
|
||||
@@ -326,33 +173,3 @@ class Esi(object):
|
||||
|
||||
self.handleLogin(message['SSOInfo'][0])
|
||||
|
||||
def __before_request(self, ssoChar):
|
||||
if ssoChar.is_token_expired():
|
||||
json_response = self.refresh(ssoChar)
|
||||
# AFTER_TOKEN_REFRESH.send(**json_response)
|
||||
|
||||
if ssoChar.accessToken is not None:
|
||||
self._session.headers.update(self.get_oauth_header(ssoChar.accessToken))
|
||||
|
||||
def get(self, ssoChar, endpoint, *args, **kwargs):
|
||||
self.__before_request(ssoChar)
|
||||
endpoint = endpoint.format(**kwargs)
|
||||
return self._session.get("{}{}".format(esi_url, endpoint))
|
||||
|
||||
# check for warnings, also status > 400
|
||||
|
||||
|
||||
def post(self, ssoChar, endpoint, json, *args, **kwargs):
|
||||
self.__before_request(ssoChar)
|
||||
endpoint = endpoint.format(**kwargs)
|
||||
return self._session.post("{}{}".format(esi_url, endpoint), data=json)
|
||||
|
||||
# check for warnings, also status > 400
|
||||
|
||||
def delete(self, ssoChar, endpoint, *args, **kwargs):
|
||||
self.__before_request(ssoChar)
|
||||
endpoint = endpoint.format(**kwargs)
|
||||
return self._session.delete("{}{}".format(esi_url, endpoint))
|
||||
|
||||
# check for warnings, also status > 400
|
||||
|
||||
|
||||
211
service/esiAccess.py
Normal file
211
service/esiAccess.py
Normal file
@@ -0,0 +1,211 @@
|
||||
# noinspection PyPackageRequirements
|
||||
from logbook import Logger
|
||||
import uuid
|
||||
import time
|
||||
import config
|
||||
|
||||
import datetime
|
||||
from eos.enum import Enum
|
||||
from eos.saveddata.ssocharacter import SsoCharacter
|
||||
from service.settings import EsiSettings
|
||||
|
||||
from requests import Session
|
||||
from urllib.parse import urlencode
|
||||
|
||||
pyfalog = Logger(__name__)
|
||||
|
||||
# todo: reimplement Caching for calls
|
||||
# from esipy.cache import FileCache
|
||||
# file_cache = FileCache(cache_path)
|
||||
# cache_path = os.path.join(config.savePath, config.ESI_CACHE)
|
||||
#
|
||||
# if not os.path.exists(cache_path):
|
||||
# os.mkdir(cache_path)
|
||||
#
|
||||
|
||||
# todo: move these over to getters that automatically determine which endpoint we use.
|
||||
sso_url = "https://www.pyfa.io" # "https://login.eveonline.com" for actual login
|
||||
esi_url = "https://esi.tech.ccp.is"
|
||||
|
||||
oauth_authorize = '%s/oauth/authorize' % sso_url
|
||||
oauth_token = '%s/oauth/token' % sso_url
|
||||
|
||||
|
||||
class APIException(Exception):
|
||||
""" Exception for SSO related errors """
|
||||
|
||||
def __init__(self, url, code, json_response):
|
||||
self.url = url
|
||||
self.status_code = code
|
||||
self.response = json_response
|
||||
super(APIException, self).__init__(str(self))
|
||||
|
||||
def __str__(self):
|
||||
if 'error' in self.response:
|
||||
return 'HTTP Error %s: %s' % (self.status_code,
|
||||
self.response['error'])
|
||||
elif 'message' in self.response:
|
||||
return 'HTTP Error %s: %s' % (self.status_code,
|
||||
self.response['message'])
|
||||
return 'HTTP Error %s' % (self.status_code)
|
||||
|
||||
|
||||
class ESIEndpoints(Enum):
|
||||
CHAR = "/v4/characters/{character_id}/"
|
||||
CHAR_SKILLS = "/v4/characters/{character_id}/skills/"
|
||||
CHAR_FITTINGS = "/v1/characters/{character_id}/fittings/"
|
||||
CHAR_DEL_FIT = "/v1/characters/{character_id}/fittings/{fitting_id}/"
|
||||
|
||||
|
||||
# class Servers(Enum):
|
||||
# TQ = 0
|
||||
# SISI = 1
|
||||
|
||||
class EsiAccess(object):
|
||||
def __init__(self):
|
||||
if sso_url is None or sso_url == "":
|
||||
raise AttributeError("sso_url cannot be None or empty "
|
||||
"without app parameter")
|
||||
|
||||
self.settings = EsiSettings.getInstance()
|
||||
|
||||
self.oauth_authorize = '%s/oauth/authorize' % sso_url
|
||||
self.oauth_token = '%s/oauth/token' % sso_url
|
||||
|
||||
# use ESI url for verify, since it's better for caching
|
||||
if esi_url is None or esi_url == "":
|
||||
raise AttributeError("esi_url cannot be None or empty")
|
||||
self.oauth_verify = '%s/verify/' % esi_url
|
||||
|
||||
|
||||
# session request stuff
|
||||
self._session = Session()
|
||||
self._session.headers.update({
|
||||
'Accept': 'application/json',
|
||||
'User-Agent': (
|
||||
'pyfa v{}'.format(config.version)
|
||||
)
|
||||
})
|
||||
|
||||
def getSkills(self, char):
|
||||
return self.get(char, ESIEndpoints.CHAR_SKILLS, character_id=char.characterID)
|
||||
|
||||
def getSecStatus(self, char):
|
||||
return self.get(char, ESIEndpoints.CHAR, character_id=char.characterID)
|
||||
|
||||
def getFittings(self, char):
|
||||
return self.get(char, ESIEndpoints.CHAR_FITTINGS, character_id=char.characterID)
|
||||
|
||||
def postFitting(self, char, json_str):
|
||||
# @todo: new fitting ID can be recovered from resp.data,
|
||||
return self.post(char, ESIEndpoints.CHAR_FITTINGS, json_str, character_id=char.characterID)
|
||||
|
||||
def delFitting(self, char, fittingID):
|
||||
return self.delete(char, ESIEndpoints.CHAR_DEL_FIT, character_id=char.characterID, fitting_id=fittingID)
|
||||
|
||||
@staticmethod
|
||||
def update_token(char, tokenResponse):
|
||||
""" helper function to update token data from SSO response """
|
||||
char.accessToken = tokenResponse['access_token']
|
||||
char.accessTokenExpires = datetime.datetime.fromtimestamp(time.time() + tokenResponse['expires_in'])
|
||||
if 'refresh_token' in tokenResponse:
|
||||
char.refreshToken = config.cipher.encrypt(tokenResponse['refresh_token'].encode())
|
||||
|
||||
def getLoginURI(self, redirect=None):
|
||||
self.state = str(uuid.uuid4())
|
||||
|
||||
args = {
|
||||
'state': self.state,
|
||||
'pyfa_version': config.version,
|
||||
'login_method': self.settings.get('loginMode'),
|
||||
'client_hash': config.getClientSecret()
|
||||
}
|
||||
|
||||
if redirect is not None:
|
||||
args['redirect'] = redirect
|
||||
|
||||
return '%s?%s' % (
|
||||
oauth_authorize,
|
||||
urlencode(args)
|
||||
)
|
||||
|
||||
def get_oauth_header(self, token):
|
||||
""" Return the Bearer Authorization header required in oauth calls
|
||||
|
||||
:return: a dict with the authorization header
|
||||
"""
|
||||
return {'Authorization': 'Bearer %s' % token}
|
||||
|
||||
def get_refresh_token_params(self, refreshToken):
|
||||
""" Return the param object for the post() call to get the access_token
|
||||
from the refresh_token
|
||||
|
||||
:param code: the refresh token
|
||||
:return: a dict with the url, params and header
|
||||
"""
|
||||
if refreshToken is None:
|
||||
raise AttributeError('No refresh token is defined.')
|
||||
|
||||
return {
|
||||
'data': {
|
||||
'grant_type': 'refresh_token',
|
||||
'refresh_token': refreshToken,
|
||||
},
|
||||
'url': self.oauth_token,
|
||||
}
|
||||
|
||||
def refresh(self, ssoChar):
|
||||
request_data = self.get_refresh_token_params(config.cipher.decrypt(ssoChar.refreshToken).decode())
|
||||
res = self._session.post(**request_data)
|
||||
if res.status_code != 200:
|
||||
raise APIException(
|
||||
request_data['url'],
|
||||
res.status_code,
|
||||
res.json()
|
||||
)
|
||||
json_res = res.json()
|
||||
self.update_token(ssoChar, json_res)
|
||||
return json_res
|
||||
|
||||
def _before_request(self, ssoChar):
|
||||
if ssoChar.is_token_expired():
|
||||
pyfalog.info("Refreshing token for {}".format(ssoChar.characterName))
|
||||
self.refresh(ssoChar)
|
||||
|
||||
if ssoChar.accessToken is not None:
|
||||
self._session.headers.update(self.get_oauth_header(ssoChar.accessToken))
|
||||
|
||||
def _after_request(self, resp):
|
||||
if ("warning" in resp.headers):
|
||||
pyfalog.warn("{} - {}".format(resp.headers["warning"], resp.url))
|
||||
|
||||
if resp.status_code >= 400:
|
||||
raise APIException(
|
||||
resp.url,
|
||||
resp.status_code,
|
||||
resp.json()
|
||||
)
|
||||
|
||||
return resp
|
||||
|
||||
def get(self, ssoChar, endpoint, *args, **kwargs):
|
||||
self._before_request(ssoChar)
|
||||
endpoint = endpoint.format(**kwargs)
|
||||
return self._after_request(self._session.get("{}{}".format(esi_url, endpoint)))
|
||||
|
||||
# check for warnings, also status > 400
|
||||
|
||||
def post(self, ssoChar, endpoint, json, *args, **kwargs):
|
||||
self._before_request(ssoChar)
|
||||
endpoint = endpoint.format(**kwargs)
|
||||
return self._after_request(self._session.post("{}{}".format(esi_url, endpoint), data=json))
|
||||
|
||||
# check for warnings, also status > 400
|
||||
|
||||
def delete(self, ssoChar, endpoint, *args, **kwargs):
|
||||
self._before_request(ssoChar)
|
||||
endpoint = endpoint.format(**kwargs)
|
||||
return self._after_request(self._session.delete("{}{}".format(esi_url, endpoint)))
|
||||
|
||||
# check for warnings, also status > 400
|
||||
|
||||
Reference in New Issue
Block a user