Compare commits

...
This repository has been archived on 2023-02-21. You can view files and clone it, but cannot push or open issues or pull requests.

2 Commits

Author SHA1 Message Date
Josue Kouka d320ab039e misc: improve application configuration 2018-03-07 19:59:19 +01:00
Josue Kouka e10c859365 improve application's webservices config (#22064) 2018-03-06 15:47:35 +01:00
3 changed files with 166 additions and 113 deletions

View File

@ -16,11 +16,10 @@
from __future__ import unicode_literals
import os
from importlib import import_module
from django.conf import settings
from django.conf.urls import patterns, url
from django.conf.urls import url
from django.http import Http404
from django.core.exceptions import ImproperlyConfigured
from django.core.urlresolvers import resolve
@ -35,65 +34,120 @@ def get_app_settings():
def app_web_services(request, path):
app = get_app_settings()
if hasattr(app, 'urlpatterns'):
view, args, kwargs = resolve(request.path, urlconf=app)
if hasattr(app, 'SITE_WEBSERVICES'):
view, args, kwargs = resolve(request.path, urlconf=app.SITE_WEBSERVICES)
return view(request, *args, **kwargs)
raise Http404
# App Settings
class AppSettingsMeta(type):
REQUIRED_PARAMS = [
'SITE_LOGIN_PATH',
'SITE_LOCATORS',
'SITE_AUTH_CHECKER',
'SITE_AUTH_COOKIE_KEYS',
]
REQUIRED_KEYS = [
'SITE_LOGIN_PATH',
'SITE_LOCATORS',
'SITE_AUTH_CHECKER',
'SITE_AUTH_COOKIE_KEYS',
]
def __new__(cls, name, bases, dct):
if name != 'AppSettings':
if AppSettings in bases: # Avoid checking keys for inherited classes
class Param(object):
missing_key = set(cls.REQUIRED_KEYS).difference(set(dct.keys())) or None
if missing_key:
raise ImproperlyConfigured('{} is mandatory'.format(missing_key.pop()))
def __init__(self, initval=None, name=None):
self.value = initval
if name:
self.name = name
if not set(('SITE_FORCE_REDIRECT_URL', 'SITE_FORCE_REDIRECT_LOCATOR')).intersection(set(dct.keys())):
raise ImproperlyConfigured(
'one of these settings ({}) must be defined'
.format(('SITE_FORCE_REDIRECT_URL', 'SITE_FORCE_REDIRECT_LOCATOR')))
def __set__(self, instance, value):
self.value = value
# Default form submit element
if not dct.get('SITE_FORM_SUBMIT_ELEMENT', None):
dct['SITE_FORM_SUBMIT_ELEMENT'] = 'input[type=submit], button'
def __get__(self, instance, owner):
if instance is None:
return self
if hasattr(settings, self.name):
return getattr(settings, self.name)
return self.value
return super(AppSettingsMeta, cls).__new__(cls, name, bases, dct)
class LoginPathParam(Param):
name = 'SITE_LOGIN_PATH'
class LocatorsParam(Param):
name = 'SITE_LOCATORS'
class AuthCheckerParam(Param):
name = 'SITE_AUTH_CHECKER'
class AuthCookieKeysParam(Param):
name = 'SITE_AUTH_COOKIE_KEYS'
class ForceRedirctUrlParam(Param):
name = 'SITE_FORCE_REDIRECT_URL'
class ForceRedirectLocatorParam(Param):
name = 'SITE_FORCE_REDIRECT_LOCATOR'
class FormSubmitElementParam(Param):
name = 'SITE_FORM_SUBMIT_ELEMENT'
class LogoutLocatorParam(Param):
name = 'LOGOUT_LOCATOR'
class AppScriptParam(Param):
name = 'APP_SCRIPT'
class AppSettings(object):
__metaclass__ = AppSettingsMeta
def __getattribute__(self, name):
value = getattr(settings, name, None)
if value is not None:
return value
return super(AppSettings, self).__getattribute__(name)
SITE_FORM_SUBMIT_ELEMENT = FormSubmitElementParam('input[type=submit], button')
def get_name(self):
name = getattr(settings, 'SITE_APP_NAME', None)
if name:
return name
return type(self).__name__
def __init__(self, *args, **kwargs):
for param in REQUIRED_PARAMS:
if not hasattr(self, param):
raise ImproperlyConfigured('missing required parameter <%s>' % param)
def get_slug(self):
return slugify(type(self).__name__)
@property
def name(self):
if hasattr(settings, 'SITE_APP_NAME'):
return settings.SITE_APP_NAME
return self.__class__.__name__
@property
def slug(self):
return slugify(self.__class__.__name__)
class AppWebservice(object):
'''- endpoints = [
{'foo': 'https://example.org/foo/'},
{'bar': 'https://example.org/bar/'},
]
- urlpatterns = [
url('user/(?P<username>\w+)/$', views.myapp.user_details, name='user-details'),
url('user/(?P<username>\w+/books/$)', views.myapp.user_books, name='user-books'),
]
'''
def __init__(self, endpoints=None, urlpatterns=None):
self.endpoints = endpoints
self.urlpatterns = urlpatterns
def get_endpoint(self, name):
for endpoint in self.endpoints:
if endpoint.get(name, None):
return endpoint[name]
return None
# Test App Settings
class Test(AppSettings):
SITE_LOGIN_PATH = '/'
SITE_LOCATORS = [
SITE_LOGIN_PATH = LoginPathParam('/')
SITE_LOCATORS = LocatorsParam([
{
'id': '#login',
'label': 'Login',
@ -106,16 +160,16 @@ class Test(AppSettings):
'name': 'password',
'kind': 'password'
}
]
SITE_AUTH_CHECKER = 'js/test/auth.checker.js'
SITE_AUTH_COOKIE_KEYS = ['test']
SITE_FORCE_REDIRECT_URL = '/whatever'
])
SITE_AUTH_CHECKER = AuthCheckerParam('js/test/auth.checker.js')
SITE_AUTH_COOKIE_KEYS = AuthCookieKeysParam(['test'])
SITE_FORCE_REDIRECT_URL = ForceRedirctUrlParam('/whatever')
# Duonet App Settings
class Duonet(AppSettings):
SITE_LOGIN_PATH = '/'
SITE_LOCATORS = [
SITE_LOGIN_PATH = LoginPathParam('/')
SITE_LOCATORS = LocatorsParam([
{
'id': '#txtNomFoyer',
'label': 'Nom de famille',
@ -140,26 +194,26 @@ class Duonet(AppSettings):
'required': True,
'help': ''
},
]
SITE_AUTH_CHECKER = 'duonet/js/auth.checker.js'
SITE_AUTH_COOKIE_KEYS = [
])
SITE_AUTH_CHECKER = AuthCheckerParam('duonet/js/auth.checker.js')
SITE_AUTH_COOKIE_KEYS = AuthCookieKeysParam([
'ASP.NET_SessionId',
]
SITE_APP_SCRIPTS = [
])
SITE_APP_SCRIPTS = AppScriptParam([
'duonet/js/duonet.js',
]
])
SITE_FORCE_REDIRECT_URL = '/Connect.aspx'
SITE_FORCE_REDIRECT_URL = ForceRedirctUrlParam('/Connect.aspx')
SITE_FORM_SUBMIT_ELEMENT = 'input[type=submit]'
SITE_FORM_SUBMIT_ELEMENT = FormSubmitElementParam('input[type=submit]')
SITE_LOGOUT_LOCATOR = '#lnkDisconnect'
SITE_LOGOUT_LOCATOR = LogoutLocatorParam('#lnkDisconnect')
# Archimed App Settings
class Archimed(AppSettings):
SITE_LOGIN_PATH = '/'
SITE_LOCATORS = [
SITE_LOGIN_PATH = LoginPathParam('/')
SITE_LOCATORS = LocatorsParam([
{
'id': '#carte',
'label': 'Identifiant',
@ -176,37 +230,36 @@ class Archimed(AppSettings):
'required': True,
'help': ''
},
]
SITE_AUTH_CHECKER = 'archimed/js/auth.checker.js'
SITE_AUTH_COOKIE_KEYS = [
])
SITE_AUTH_CHECKER = AuthCheckerParam('archimed/js/auth.checker.js')
SITE_AUTH_COOKIE_KEYS = AuthCookieKeysParam([
'S_ARCHIMED_CRYSTAL_AUTH'
]
])
SITE_APP_SCRIPTS = [
SITE_APP_SCRIPTS = AppScriptParam([
'archimed/js/archimed.js'
]
])
SITE_FORCE_REDIRECT_LOCATOR = '.connectBox'
SITE_FORCE_REDIRECT_LOCATOR = ForceRedirectLocatorParam('.connectBox')
SITE_WS_ENDPOINT = {
'account_details': '/DEFAULT/Ermes/Services/ILSClient.svc/RetrieveAccount',
}
urlpatterns = patterns(
'',
url(
r'account/(?P<username>\w+)/$',
'mandayejs.applications.views.archimed_account_details',
name='archimed-account-details'),
SITE_WEBSERVICES = AppWebservice(
[
{'account_details': '/DEFAULT/Ermes/Services/ILSClient.svc/RetrieveAccount'},
{'login_url': '/DEFAULT/Ermes/Recherche/logon.svc/logon'}
],
[
url(r'account/(?P<username>\w+)/$', 'mandayejs.applications.views.archimed_account_details',
name='archimed-account-details')
]
)
SITE_LOGOUT_LOCATOR = '.account_logoff'
SITE_LOGOUT_LOCATOR = LogoutLocatorParam('.account_logoff')
# Arpege App Settings
class Arpege(AppSettings):
SITE_LOGIN_PATH = '/index.do'
SITE_LOCATORS = [
SITE_LOGIN_PATH = LoginPathParam('/index.do')
SITE_LOCATORS = LocatorsParam([
{
'id': '#cdfmll',
'label': 'Code famille',
@ -223,25 +276,25 @@ class Arpege(AppSettings):
'required': True,
'help': '',
}
]
SITE_AUTH_CHECKER = 'arpege/js/auth.checker.js'
SITE_AUTH_COOKIE_KEYS = [
])
SITE_AUTH_CHECKER = AuthCheckerParam('arpege/js/auth.checker.js')
SITE_AUTH_COOKIE_KEYS = AuthCookieKeysParam([
'JSESSIONID',
]
])
SITE_APP_SCRIPTS = [
SITE_APP_SCRIPTS = AppScriptParam([
'arpege/js/arpege.js',
]
])
SITE_FORCE_REDIRECT_LOCATOR = '.formulaire'
SITE_FORCE_REDIRECT_LOCATOR = ForceRedirectLocatorParam(r'.formulaire')
SITE_LOGOUT_LOCATOR = '#espace-login form input[type=submit]'
SITE_LOGOUT_LOCATOR = LogoutLocatorParam('#espace-login form input[type=submit]')
class Imuse(AppSettings):
SITE_LOGIN_PATH = 'extranet/login/gen_index_groupe.php?nav=autre'
SITE_LOGIN_PATH = LoginPathParam('extranet/login/gen_index_groupe.php?nav=autre')
SITE_LOCATORS = [
SITE_LOCATORS = LocatorsParam([
{
'id': '#INDEX_USER_ID',
'label': 'Identifiant',
@ -258,23 +311,23 @@ class Imuse(AppSettings):
'required': True,
'help': ''
}
]
])
SITE_AUTH_CHECKER = 'imuse/js/auth.checker.js'
SITE_AUTH_CHECKER = AuthCheckerParam('imuse/js/auth.checker.js')
SITE_AUTH_COOKIE_KEYS = [
SITE_AUTH_COOKIE_KEYS = AuthCookieKeysParam([
'iMuse-extranet'
]
])
SITE_FORCE_REDIRECT_LOCATOR = '#INDEX_TBL_LOGIN'
SITE_FORCE_REDIRECT_LOCATOR = ForceRedirectLocatorParam('#INDEX_TBL_LOGIN')
SITE_FORM_SUBMIT_ELEMENT = '#INDEX_BT_LOGIN'
SITE_FORM_SUBMIT_ELEMENT = FormSubmitElementParam('#INDEX_BT_LOGIN')
class Sezhame(AppSettings):
SITE_LOGIN_PATH = '/sezhame/page/connexion-abonne?destination=user'
SITE_LOGIN_PATH = LoginPathParam('/sezhame/page/connexion-abonne?destination=user')
SITE_LOCATORS = [
SITE_LOCATORS = LocatorsParam([
{
'id': '#edit-user',
'label': 'Numero de cqrte',
@ -291,22 +344,22 @@ class Sezhame(AppSettings):
'required': True,
'help': ''
}
]
])
SITE_AUTH_CHECKER = 'sezhame/js/auth.checker.js'
SITE_AUTH_CHECKER = AuthCheckerParam('sezhame/js/auth.checker.js')
SITE_AUTH_COOKIE_KEYS = [
SITE_AUTH_COOKIE_KEYS = AuthCookieKeysParam([
'SESSf36da25307ad6240a58ddd4f4b138952',
'ASPSESSIONIDQSDRASTR'
]
])
SITE_FORCE_REDIRECT_LOCATOR = '#dk-opac15-login-form'
SITE_FORCE_REDIRECT_LOCATOR = ForceRedirectLocatorParam('#dk-opac15-login-form')
class Teamnet(AppSettings):
SITE_LOGIN_PATH = '/auth/teamnetauth'
SITE_LOGIN_PATH = LoginPathParam('/auth/teamnetauth')
SITE_LOCATORS = [
SITE_LOCATORS = LocatorsParam([
{
'id': '#login',
'label': 'Mon identifiant',
@ -323,16 +376,16 @@ class Teamnet(AppSettings):
'required': True,
'help': ''
}
]
])
SITE_FORM_SUBMIT_ELEMENT = "input[type=submit][value='Me connecter']"
SITE_FORM_SUBMIT_ELEMENT = FormSubmitElementParam("input[type=submit][value='Me connecter']")
SITE_AUTH_CHECKER = 'teamnet/js/auth.checker.js'
SITE_AUTH_CHECKER = AuthCheckerParam('teamnet/js/auth.checker.js')
SITE_AUTH_COOKIE_KEYS = [
SITE_AUTH_COOKIE_KEYS = AuthCookieKeysParam([
'JSESSIONID',
]
])
SITE_FORCE_REDIRECT_LOCATOR = '#loginForm'
SITE_FORCE_REDIRECT_LOCATOR = ForceRedirectLocatorParam('#loginForm')
SITE_LOGOUT_LOCATOR = ".infoUtilisateur[alt=Deconnexion]"
SITE_LOGOUT_LOCATOR = LogoutLocatorParam(".infoUtilisateur[alt=Deconnexion]")

View File

@ -44,7 +44,7 @@ class ArchimedAccountDetails(APIView):
logger = logging.getLogger(__name__)
app_settings = get_app_settings()
ws_uri = request.build_absolute_uri(
app_settings.SITE_WS_ENDPOINT['account_details'])
app_settings.SITE_WEBSERVICES.get_endpoint('account_details'))
# mellon truncates username to 30 characters
# thus the passed username must be truncated to 30 characters
@ -62,7 +62,7 @@ class ArchimedAccountDetails(APIView):
return Response('User %s is not associated' % username, status=status.HTTP_404_NOT_FOUND)
login_url = request.build_absolute_uri(
'/DEFAULT/Ermes/Recherche/logon.svc/logon')
app_settings.SITE_WEBSERVICES.get_endpoint('login_url'))
with requests.Session() as session:
login_info = credentials.to_login_info(decrypt=True)

View File

@ -126,7 +126,7 @@ def associate(request, *args, **kwargs):
app_settings = get_app_settings()
response = render(request, 'mandaye/associate.html', {
'form': form, 'app': {
'name': app_settings.get_name(), 'slug': app_settings.get_slug()}})
'name': app_settings.name, 'slug': app_settings.slug}})
return response