Merge branch 'esi-noserver' into esi

This commit is contained in:
Ryan Holmes
2018-03-18 00:47:07 -04:00
11 changed files with 238 additions and 187 deletions

View File

@@ -6,5 +6,6 @@ __all__ = [
"pyfaDatabasePreferences",
"pyfaLoggingPreferences",
"pyfaEnginePreferences",
"pyfaEsiPreferences",
"pyfaStatViewPreferences"]

View File

@@ -1,148 +0,0 @@
# noinspection PyPackageRequirements
import wx
from gui.preferenceView import PreferenceView
from gui.bitmap_loader import BitmapLoader
import gui.mainFrame
from service.settings import CRESTSettings
# noinspection PyPackageRequirements
from wx.lib.intctrl import IntCtrl
from service.esi import Esi
class PFCrestPref(PreferenceView):
title = "CREST"
def populatePanel(self, panel):
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
self.settings = CRESTSettings.getInstance()
self.dirtySettings = False
dlgWidth = panel.GetParent().GetParent().ClientSize.width
mainSizer = wx.BoxSizer(wx.VERTICAL)
self.stTitle = wx.StaticText(panel, wx.ID_ANY, self.title, wx.DefaultPosition, wx.DefaultSize, 0)
self.stTitle.Wrap(-1)
self.stTitle.SetFont(wx.Font(12, 70, 90, 90, False, wx.EmptyString))
mainSizer.Add(self.stTitle, 0, wx.ALL, 5)
self.m_staticline1 = wx.StaticLine(panel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL)
mainSizer.Add(self.m_staticline1, 0, wx.EXPAND | wx.TOP | wx.BOTTOM, 5)
self.stInfo = wx.StaticText(panel, wx.ID_ANY,
"Please see the pyfa wiki on GitHub for information regarding these options.",
wx.DefaultPosition, wx.DefaultSize, 0)
self.stInfo.Wrap(dlgWidth - 50)
mainSizer.Add(self.stInfo, 0, wx.EXPAND | wx.TOP | wx.BOTTOM, 5)
rbSizer = wx.BoxSizer(wx.HORIZONTAL)
self.rbMode = wx.RadioBox(panel, -1, "Mode", wx.DefaultPosition, wx.DefaultSize,
['Implicit', 'User-supplied details'], 1, wx.RA_SPECIFY_COLS)
self.rbServer = wx.RadioBox(panel, -1, "Server", wx.DefaultPosition, wx.DefaultSize,
['Tranquility', 'Singularity'], 1, wx.RA_SPECIFY_COLS)
self.rbMode.SetSelection(self.settings.get('mode'))
self.rbServer.SetSelection(self.settings.get('server'))
rbSizer.Add(self.rbMode, 1, wx.TOP | wx.RIGHT, 5)
rbSizer.Add(self.rbServer, 1, wx.ALL, 5)
self.rbMode.Bind(wx.EVT_RADIOBOX, self.OnModeChange)
self.rbServer.Bind(wx.EVT_RADIOBOX, self.OnServerChange)
mainSizer.Add(rbSizer, 1, wx.ALL | wx.EXPAND, 0)
timeoutSizer = wx.BoxSizer(wx.HORIZONTAL)
self.stTimout = wx.StaticText(panel, wx.ID_ANY, "Timeout (seconds):", wx.DefaultPosition, wx.DefaultSize, 0)
self.stTimout.Wrap(-1)
timeoutSizer.Add(self.stTimout, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5)
self.intTimeout = IntCtrl(panel, max=300000, limited=True, value=self.settings.get('timeout'))
timeoutSizer.Add(self.intTimeout, 0, wx.ALL, 5)
self.intTimeout.Bind(wx.lib.intctrl.EVT_INT, self.OnTimeoutChange)
mainSizer.Add(timeoutSizer, 0, wx.ALL | wx.EXPAND, 0)
detailsTitle = wx.StaticText(panel, wx.ID_ANY, "CREST client details", wx.DefaultPosition, wx.DefaultSize, 0)
detailsTitle.Wrap(-1)
detailsTitle.SetFont(wx.Font(12, 70, 90, 90, False, wx.EmptyString))
mainSizer.Add(detailsTitle, 0, wx.ALL, 5)
mainSizer.Add(wx.StaticLine(panel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL), 0,
wx.EXPAND, 5)
fgAddrSizer = wx.FlexGridSizer(2, 2, 0, 0)
fgAddrSizer.AddGrowableCol(1)
fgAddrSizer.SetFlexibleDirection(wx.BOTH)
fgAddrSizer.SetNonFlexibleGrowMode(wx.FLEX_GROWMODE_SPECIFIED)
self.stSetID = wx.StaticText(panel, wx.ID_ANY, "Client ID:", wx.DefaultPosition, wx.DefaultSize, 0)
self.stSetID.Wrap(-1)
fgAddrSizer.Add(self.stSetID, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5)
self.inputClientID = wx.TextCtrl(panel, wx.ID_ANY, self.settings.get('clientID'), wx.DefaultPosition,
wx.DefaultSize, 0)
fgAddrSizer.Add(self.inputClientID, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL | wx.EXPAND, 5)
self.stSetSecret = wx.StaticText(panel, wx.ID_ANY, "Client Secret:", wx.DefaultPosition, wx.DefaultSize, 0)
self.stSetSecret.Wrap(-1)
fgAddrSizer.Add(self.stSetSecret, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5)
self.inputClientSecret = wx.TextCtrl(panel, wx.ID_ANY, self.settings.get('clientSecret'), wx.DefaultPosition,
wx.DefaultSize, 0)
fgAddrSizer.Add(self.inputClientSecret, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL | wx.EXPAND, 5)
self.btnApply = wx.Button(panel, wx.ID_ANY, "Save Client Settings", wx.DefaultPosition, wx.DefaultSize, 0)
self.btnApply.Bind(wx.EVT_BUTTON, self.OnBtnApply)
mainSizer.Add(fgAddrSizer, 0, wx.EXPAND, 5)
mainSizer.Add(self.btnApply, 0, wx.ALIGN_RIGHT, 5)
self.ToggleProxySettings(self.settings.get('mode'))
panel.SetSizer(mainSizer)
panel.Layout()
def OnTimeoutChange(self, event):
self.settings.set('timeout', event.GetEventObject().GetValue())
def OnModeChange(self, event):
self.settings.set('mode', event.GetInt())
self.ToggleProxySettings(self.settings.get('mode'))
def OnServerChange(self, event):
self.settings.set('server', event.GetInt())
def OnBtnApply(self, event):
self.settings.set('clientID', self.inputClientID.GetValue().strip())
self.settings.set('clientSecret', self.inputClientSecret.GetValue().strip())
sEsi = Esi.getInstance()
sEsi.delAllCharacters()
def ToggleProxySettings(self, mode):
if mode:
self.stSetID.Enable()
self.inputClientID.Enable()
self.stSetSecret.Enable()
self.inputClientSecret.Enable()
else:
self.stSetID.Disable()
self.inputClientID.Disable()
self.stSetSecret.Disable()
self.inputClientSecret.Disable()
def getImage(self):
return BitmapLoader.getBitmap("eve", "gui")
PFCrestPref.register()

View File

@@ -0,0 +1,137 @@
# noinspection PyPackageRequirements
import wx
from gui.preferenceView import PreferenceView
from gui.bitmap_loader import BitmapLoader
import gui.mainFrame
from service.settings import EsiSettings
# noinspection PyPackageRequirements
from wx.lib.intctrl import IntCtrl
from service.esi import Esi
class PFEsiPref(PreferenceView):
title = "EVE SSO"
def populatePanel(self, panel):
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
self.settings = EsiSettings.getInstance()
self.dirtySettings = False
dlgWidth = panel.GetParent().GetParent().ClientSize.width
mainSizer = wx.BoxSizer(wx.VERTICAL)
self.stTitle = wx.StaticText(panel, wx.ID_ANY, self.title, wx.DefaultPosition, wx.DefaultSize, 0)
self.stTitle.Wrap(-1)
self.stTitle.SetFont(wx.Font(12, 70, 90, 90, False, wx.EmptyString))
mainSizer.Add(self.stTitle, 0, wx.ALL, 5)
self.m_staticline1 = wx.StaticLine(panel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL)
mainSizer.Add(self.m_staticline1, 0, wx.EXPAND | wx.TOP | wx.BOTTOM, 5)
self.stInfo = wx.StaticText(panel, wx.ID_ANY,
"Please see the pyfa wiki on GitHub for information regarding these options.",
wx.DefaultPosition, wx.DefaultSize, 0)
self.stInfo.Wrap(dlgWidth - 50)
mainSizer.Add(self.stInfo, 0, wx.EXPAND | wx.TOP | wx.BOTTOM, 5)
rbSizer = wx.BoxSizer(wx.HORIZONTAL)
self.rbMode = wx.RadioBox(panel, -1, "Login Authentication Method", wx.DefaultPosition, wx.DefaultSize,
['Local Server', 'Manual'], 1, wx.RA_SPECIFY_COLS)
self.rbMode.SetItemToolTip(0, "This options starts a local webserver that the web application will call back to with information about the character login.")
self.rbMode.SetItemToolTip(1, "This option prompts users to copy and paste information from the web application to allow for character login. Use this if having issues with the local server.")
# self.rbServer = wx.RadioBox(panel, -1, "Server", wx.DefaultPosition, wx.DefaultSize,
# ['Tranquility', 'Singularity'], 1, wx.RA_SPECIFY_COLS)
self.rbMode.SetSelection(self.settings.get('loginMode'))
# self.rbServer.SetSelection(self.settings.get('server'))
rbSizer.Add(self.rbMode, 1, wx.TOP | wx.RIGHT, 5)
# rbSizer.Add(self.rbServer, 1, wx.ALL, 5)
self.rbMode.Bind(wx.EVT_RADIOBOX, self.OnModeChange)
# self.rbServer.Bind(wx.EVT_RADIOBOX, self.OnServerChange)
mainSizer.Add(rbSizer, 1, wx.ALL | wx.EXPAND, 0)
timeoutSizer = wx.BoxSizer(wx.HORIZONTAL)
# self.stTimout = wx.StaticText(panel, wx.ID_ANY, "Timeout (seconds):", wx.DefaultPosition, wx.DefaultSize, 0)
# self.stTimout.Wrap(-1)
#
# timeoutSizer.Add(self.stTimout, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5)
# self.intTimeout = IntCtrl(panel, max=300000, limited=True, value=self.settings.get('timeout'))
# timeoutSizer.Add(self.intTimeout, 0, wx.ALL, 5)
# self.intTimeout.Bind(wx.lib.intctrl.EVT_INT, self.OnTimeoutChange)
#
# mainSizer.Add(timeoutSizer, 0, wx.ALL | wx.EXPAND, 0)
# detailsTitle = wx.StaticText(panel, wx.ID_ANY, "CREST client details", wx.DefaultPosition, wx.DefaultSize, 0)
# detailsTitle.Wrap(-1)
# detailsTitle.SetFont(wx.Font(12, 70, 90, 90, False, wx.EmptyString))
#
# mainSizer.Add(detailsTitle, 0, wx.ALL, 5)
# mainSizer.Add(wx.StaticLine(panel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL), 0,
# wx.EXPAND, 5)
# fgAddrSizer = wx.FlexGridSizer(2, 2, 0, 0)
# fgAddrSizer.AddGrowableCol(1)
# fgAddrSizer.SetFlexibleDirection(wx.BOTH)
# fgAddrSizer.SetNonFlexibleGrowMode(wx.FLEX_GROWMODE_SPECIFIED)
#
# self.stSetID = wx.StaticText(panel, wx.ID_ANY, "Client ID:", wx.DefaultPosition, wx.DefaultSize, 0)
# self.stSetID.Wrap(-1)
# fgAddrSizer.Add(self.stSetID, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5)
#
# self.inputClientID = wx.TextCtrl(panel, wx.ID_ANY, self.settings.get('clientID'), wx.DefaultPosition,
# wx.DefaultSize, 0)
#
# fgAddrSizer.Add(self.inputClientID, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL | wx.EXPAND, 5)
#
# self.stSetSecret = wx.StaticText(panel, wx.ID_ANY, "Client Secret:", wx.DefaultPosition, wx.DefaultSize, 0)
# self.stSetSecret.Wrap(-1)
#
# fgAddrSizer.Add(self.stSetSecret, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5)
#
# self.inputClientSecret = wx.TextCtrl(panel, wx.ID_ANY, self.settings.get('clientSecret'), wx.DefaultPosition,
# wx.DefaultSize, 0)
#
# fgAddrSizer.Add(self.inputClientSecret, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL | wx.EXPAND, 5)
#
# self.btnApply = wx.Button(panel, wx.ID_ANY, "Save Client Settings", wx.DefaultPosition, wx.DefaultSize, 0)
# self.btnApply.Bind(wx.EVT_BUTTON, self.OnBtnApply)
#
# mainSizer.Add(fgAddrSizer, 0, wx.EXPAND, 5)
# mainSizer.Add(self.btnApply, 0, wx.ALIGN_RIGHT, 5)
# self.ToggleProxySettings(self.settings.get('loginMode'))
panel.SetSizer(mainSizer)
panel.Layout()
def OnTimeoutChange(self, event):
self.settings.set('timeout', event.GetEventObject().GetValue())
def OnModeChange(self, event):
self.settings.set('loginMode', event.GetInt())
def OnServerChange(self, event):
self.settings.set('server', event.GetInt())
def OnBtnApply(self, event):
self.settings.set('clientID', self.inputClientID.GetValue().strip())
self.settings.set('clientSecret', self.inputClientSecret.GetValue().strip())
sEsi = Esi.getInstance()
sEsi.delAllCharacters()
def getImage(self):
return BitmapLoader.getBitmap("eve", "gui")
PFEsiPref.register()

View File

@@ -781,8 +781,7 @@ class APIView(wx.Panel):
def addCharacter(self, event):
sEsi = Esi.getInstance()
uri = sEsi.startServer()
webbrowser.open(uri)
sEsi.login()
def getActiveCharacter(self):
selection = self.charChoice.GetCurrentSelection()

View File

@@ -344,8 +344,7 @@ class SsoCharacterMgmt(wx.Dialog):
@staticmethod
def addChar(event):
sEsi = Esi.getInstance()
uri = sEsi.startServer()
webbrowser.open(uri)
sEsi.login()
def delChar(self, event):
item = self.lcCharacters.GetFirstSelected()

View File

@@ -5,5 +5,6 @@ FitChanged, FIT_CHANGED = wx.lib.newevent.NewEvent()
CharListUpdated, CHAR_LIST_UPDATED = wx.lib.newevent.NewEvent()
CharChanged, CHAR_CHANGED = wx.lib.newevent.NewEvent()
SsoLoggingIn, EVT_SSO_LOGGING_IN = wx.lib.newevent.NewEvent()
SsoLogin, EVT_SSO_LOGIN = wx.lib.newevent.NewEvent()
SsoLogout, EVT_SSO_LOGOUT = wx.lib.newevent.NewEvent()

View File

@@ -57,6 +57,7 @@ from gui.setEditor import ImplantSetEditorDlg
from gui.devTools import DevTools
from gui.preferenceDialog import PreferenceDialog
from gui.graphFrame import GraphFrame
from gui.ssoLogin import SsoLogin
from gui.copySelectDialog import CopySelectDialog
from gui.utils.clipboard import toClipboard, fromClipboard
from gui.updateDialog import UpdateDialog
@@ -82,7 +83,7 @@ import threading
import webbrowser
import wx.adv
from service.esi import Esi
from service.esi import Esi, LoginMethod
from gui.esiFittings import EveFittings, ExportToEve, SsoCharacterMgmt
disableOverrideEditor = False
@@ -237,6 +238,15 @@ class MainFrame(wx.Frame):
self.sUpdate.CheckUpdate(self.ShowUpdateBox)
self.Bind(GE.EVT_SSO_LOGIN, self.onSSOLogin)
self.Bind(GE.EVT_SSO_LOGGING_IN, self.ShowSsoLogin)
def ShowSsoLogin(self, event):
if getattr(event, "login_mode", LoginMethod.SERVER) == LoginMethod.MANUAL:
dlg = SsoLogin(self)
if dlg.ShowModal() == wx.ID_OK:
sEsi = Esi.getInstance()
# todo: verify that this is a correct SSO Info block
sEsi.handleLogin(dlg.ssoInfoCtrl.Value.strip())
def ShowUpdateBox(self, release, version):
dlg = UpdateDialog(self, release, version)

View File

@@ -43,7 +43,7 @@ from gui.builtinPreferenceViews import ( # noqa: E402, F401
pyfaGeneralPreferences,
pyfaNetworkPreferences,
pyfaHTMLExportPreferences,
# pyfaCrestPreferences,
pyfaEsiPreferences,
pyfaContextMenuPreferences,
pyfaStatViewPreferences,
pyfaUpdatePreferences,

25
gui/ssoLogin.py Normal file
View File

@@ -0,0 +1,25 @@
import wx
class SsoLogin(wx.Dialog):
def __init__(self, parent):
wx.Dialog.__init__(self, parent, id=wx.ID_ANY, title="SSO Login", size=wx.Size(400, 240))
bSizer1 = wx.BoxSizer(wx.VERTICAL)
text = wx.StaticText(self, wx.ID_ANY, "Copy and paste the block of text provided by pyfa.io, then click OK")
bSizer1.Add(text, 0, wx.ALL | wx.EXPAND, 10)
self.ssoInfoCtrl = wx.TextCtrl(self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, (-1, -1), style=wx.TE_MULTILINE)
self.ssoInfoCtrl.SetFont(wx.Font(8, wx.FONTFAMILY_TELETYPE, wx.NORMAL, wx.NORMAL))
self.ssoInfoCtrl.Layout()
bSizer1.Add(self.ssoInfoCtrl, 1, wx.LEFT | wx.RIGHT | wx.EXPAND, 10)
bSizer3 = wx.BoxSizer(wx.VERTICAL)
bSizer3.Add(wx.StaticLine(self, wx.ID_ANY), 0, wx.BOTTOM | wx.EXPAND, 10)
bSizer3.Add(self.CreateStdDialogButtonSizer(wx.OK | wx.CANCEL), 0, wx.EXPAND)
bSizer1.Add(bSizer3, 0, wx.ALL | wx.EXPAND, 10)
self.SetSizer(bSizer1)
self.Center()

View File

@@ -9,6 +9,7 @@ import base64
import json
import os
import config
import webbrowser
import eos.db
import datetime
@@ -16,6 +17,7 @@ from eos.enum import Enum
from eos.saveddata.ssocharacter import SsoCharacter
import gui.globalEvents as GE
from service.server import StoppableHTTPServer, AuthHandler
from service.settings import EsiSettings
from .esi_security_proxy import EsiSecurityProxy
from esipy import EsiClient, EsiApp
@@ -38,6 +40,11 @@ class Servers(Enum):
SISI = 1
class LoginMethod(Enum):
SERVER = 0
MANUAL = 1
class Esi(object):
esiapp = None
esi_v1 = None
@@ -74,6 +81,8 @@ class Esi(object):
def __init__(self):
Esi.initEsiApp()
self.settings = EsiSettings.getInstance()
AFTER_TOKEN_REFRESH.add_receiver(self.tokenUpdate)
# these will be set when needed
@@ -118,7 +127,7 @@ class Esi(object):
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
print(repr(char))
eos.db.commit()
return char
@@ -179,12 +188,34 @@ class Esi(object):
if char.esi_client is not None:
char.esi_client.security.update_token(tokenResponse)
def login(self):
serverAddr = None
if self.settings.get('loginMode') == LoginMethod.SERVER:
serverAddr = self.startServer()
uri = self.getLoginURI(serverAddr)
webbrowser.open(uri)
wx.PostEvent(self.mainFrame, GE.SsoLoggingIn(login_mode=self.settings.get('loginMode')))
def stopServer(self):
pyfalog.debug("Stopping Server")
self.httpd.stop()
self.httpd = None
def startServer(self):
def getLoginURI(self, redirect=None):
self.state = str(uuid.uuid4())
esisecurity = EsiSecurityProxy(sso_url=config.ESI_AUTH_PROXY)
args = {
'state': self.state,
'pyfa_version': config.version,
}
if redirect is not None:
args['redirect'] = redirect
return esisecurity.get_auth_uri(**args)
def startServer(self): # todo: break this out into two functions: starting the server, and getting the URI
pyfalog.debug("Starting server")
# we need this to ensure that the previous get_request finishes, and then the socket will close
@@ -192,32 +223,17 @@ class Esi(object):
self.stopServer()
time.sleep(1)
self.state = str(uuid.uuid4())
self.httpd = StoppableHTTPServer(('localhost', 0), AuthHandler)
port = self.httpd.socket.getsockname()[1]
esisecurity = EsiSecurityProxy(sso_url=config.ESI_AUTH_PROXY)
uri = esisecurity.get_auth_uri(state=self.state, redirect='http://localhost:{}'.format(port), pyfa_version=config.version)
self.serverThread = threading.Thread(target=self.httpd.serve, args=(self.handleLogin,))
self.serverThread = threading.Thread(target=self.httpd.serve, args=(self.handleServerLogin,))
self.serverThread.name = "SsoCallbackServer"
self.serverThread.daemon = True
self.serverThread.start()
return uri
return 'http://localhost:{}'.format(port)
def handleLogin(self, message):
if not message:
raise Exception("Could not parse out querystring parameters.")
if message['state'][0] != self.state:
pyfalog.warn("OAUTH state mismatch")
raise Exception("OAUTH State Mismatch.")
pyfalog.debug("Handling SSO login with: {0}", message)
auth_response = json.loads(base64.b64decode(message['SSOInfo'][0]))
def handleLogin(self, ssoInfo):
auth_response = json.loads(base64.b64decode(ssoInfo))
# We need to preload the ESI Security object beforehand with the auth response so that we can use verify to
# get character information
@@ -239,5 +255,16 @@ class Esi(object):
Esi.update_token(currentCharacter, auth_response) # this also sets the esi security token
eos.db.save(currentCharacter)
wx.PostEvent(self.mainFrame, GE.SsoLogin(character = currentCharacter))
wx.PostEvent(self.mainFrame, GE.SsoLogin(character=currentCharacter))
def handleServerLogin(self, message):
if not message:
raise Exception("Could not parse out querystring parameters.")
if message['state'][0] != self.state:
pyfalog.warn("OAUTH state mismatch")
raise Exception("OAUTH State Mismatch.")
pyfalog.debug("Handling SSO login with: {0}", message)
self.handleLogin(message['SSOInfo'][0])

View File

@@ -352,32 +352,32 @@ class UpdateSettings(object):
self.serviceUpdateSettings[type] = value
class CRESTSettings(object):
class EsiSettings(object):
_instance = None
@classmethod
def getInstance(cls):
if cls._instance is None:
cls._instance = CRESTSettings()
cls._instance = EsiSettings()
return cls._instance
def __init__(self):
# mode
# 0 - Implicit authentication
# 1 - User-supplied client details
serviceCRESTDefaultSettings = {"mode": 0, "server": 0, "clientID": "", "clientSecret": "", "timeout": 60}
# LoginMode:
# 0 - Server Start Up
# 1 - User copy and paste data from website to pyfa
defaults = {"loginMode": 0, "clientID": "", "clientSecret": "", "timeout": 60}
self.serviceCRESTSettings = SettingsProvider.getInstance().getSettings(
"pyfaServiceCRESTSettings",
serviceCRESTDefaultSettings
self.settings = SettingsProvider.getInstance().getSettings(
"pyfaServiceEsiSettings",
defaults
)
def get(self, type):
return self.serviceCRESTSettings[type]
return self.settings[type]
def set(self, type, value):
self.serviceCRESTSettings[type] = value
self.settings[type] = value
class StatViewSettings(object):