1
0
mirror of https://github.com/dkmstr/openuds.git synced 2024-12-22 13:34:04 +03:00

* Cleaning up things

* Using pylint to try to find potentials errors
This commit is contained in:
Adolfo Gómez García 2014-09-15 10:19:54 +02:00
parent 6dbe561512
commit 3562e4ca56
11 changed files with 166 additions and 90 deletions

View File

@ -37,29 +37,36 @@ from django.views.decorators.csrf import csrf_exempt
from django.utils.decorators import method_decorator
from django.utils.translation import ugettext as _, activate
from django.conf import settings
from handlers import Handler, HandlerError, AccessDenied, NotFound, RequestError, ResponseError
from uds.REST.handlers import Handler, HandlerError, AccessDenied, NotFound, RequestError, ResponseError
import time
import logging
logger = logging.getLogger(__name__)
__all__ = [str(v) for v in ['Handler', 'Dispatcher']]
__all__ = [str(v) for v in ['Handler', 'Dispatcher']]
AUTH_TOKEN_HEADER = 'X-Auth-Token'
class Dispatcher(View):
'''
This class is responsible of dispatching REST requests
'''
# This attribute will contain all paths-->handler relations, added at Initialized method
services = {'': None} # Will include a default /rest handler, but rigth now this will be fine
@method_decorator(csrf_exempt)
def dispatch(self, request, **kwargs):
'''
Processes the REST request and routes it wherever it needs to be routed
'''
logger.debug('Language in dispatcher: {0}'.format(request.LANGUAGE_CODE))
import processors
from uds.REST import processors
# Remove session, so response middelwares do nothing with this
# Remove session, so response middleware do nothing with this
del request.session
# Now we extract method and posible variables from path
# Now we extract method and possible variables from path
path = kwargs['arguments'].split('/')
del kwargs['arguments']
@ -67,22 +74,23 @@ class Dispatcher(View):
service = Dispatcher.services
full_path = []
# Last element will be
do_break = False
cls = None
while len(path) > 0 and not do_break:
# .json, .xml, ... will break path recursion
do_break = path[0].find('.') != -1
while len(path) > 0:
clean_path = path[0].split('.')[0]
if service.has_key(clean_path):
if clean_path in service:
service = service[clean_path]
full_path.append(path[0])
path = path[1:]
else:
break
# .json, .xml, ... will break path recursion
if path[0].find('.') != -1:
break
full_path = '/'.join(full_path)
logger.debug(full_path)
# Here, service points to the path
cls = service['']
if cls is None:
return http.HttpResponseNotFound('method not found')
@ -91,8 +99,7 @@ class Dispatcher(View):
try:
p = full_path.split('.')
processor = processors.available_processors_ext_dict[p[1]](request)
except:
# TODO: Extract processor from accept and/or content type?
except Exception:
processor = processors.available_processors_mime_dict.get(request.META.get('CONTENT_TYPE', 'json'), processors.default_processor)(request)
# Obtain method to be invoked
@ -115,7 +122,7 @@ class Dispatcher(View):
return http.HttpResponseNotAllowed(allowedMethods)
except AccessDenied:
return http.HttpResponseForbidden('access denied')
except:
except Exception:
logger.exception('error accessing attribute')
logger.debug('Getting attribute {0} for {1}'.format(http_method, full_path))
return http.HttpResponseServerError('Unexcepected error')
@ -130,8 +137,8 @@ class Dispatcher(View):
start = time.time()
response = processor.getResponse(response)
logger.debug('Execution time for encoding: {0}'.format(time.time() - start))
for k, v in handler.headers().iteritems():
response[k] = v
for k, val in handler.headers().iteritems():
response[k] = val
return response
except RequestError as e:
return http.HttpResponseServerError(unicode(e))
@ -149,6 +156,9 @@ class Dispatcher(View):
@staticmethod
def registerSubclasses(classes):
'''
Try to register Handler subclasses that have not been inherited
'''
for cls in classes:
if len(cls.__subclasses__()) == 0: # Only classes that has not been inherited will be registered as Handlers
logger.debug('Found class {0}'.format(cls))

View File

@ -33,7 +33,6 @@
from __future__ import unicode_literals
from django.contrib.sessions.backends.db import SessionStore
from django.conf import settings
from uds.core.util.Config import GlobalConfig
@ -45,26 +44,44 @@ AUTH_TOKEN_HEADER = 'HTTP_X_AUTH_TOKEN'
class HandlerError(Exception):
'''
Generic error for a REST handler
'''
pass
class NotFound(HandlerError):
'''
Item not found error
'''
pass
class AccessDenied(HandlerError):
'''
Access denied error
'''
pass
class RequestError(HandlerError):
'''
Request is invalid error
'''
pass
class ResponseError(HandlerError):
'''
Generic response error
'''
pass
class Handler(object):
'''
REST requests handler base class
'''
raw = False # If true, Handler will return directly an HttpResponse Object
name = None # If name is not used, name will be the class name in lower case
path = None # Path for this method, so we can do /auth/login, /auth/logout, /auth/auths in a simple way
@ -95,7 +112,7 @@ class Handler(object):
self._session = SessionStore(session_key=self._authToken)
if 'REST' not in self._session:
raise Exception() # No valid session, so auth_token is also invalid
except:
except Exception: # Couldn't authenticate
self._authToken = None
self._session = None
@ -109,26 +126,44 @@ class Handler(object):
raise AccessDenied()
def headers(self):
'''
Returns the headers of the REST request (all)
'''
return self._headers
def header(self, header_):
return self._headers.get(header_)
def header(self, headerName):
'''
Get's an specific header name from REST request
'''
return self._headers.get(headerName)
def addHeader(self, header, value):
'''
Inserts a new header inside the headers list
'''
self._headers[header] = value
def removeHeader(self, header):
'''
Removes an specific header from the headers list
'''
try:
del self._headers[header]
except:
pass
except Exception:
pass # If not found, just ignore it
# Auth related
def getAuthToken(self):
'''
Returns the authentication token for this REST request
'''
return self._authToken
@staticmethod
def storeSessionAuthdata(session, id_auth, username, locale, is_admin, staff_member):
'''
Stores the authentication data inside current session
'''
if is_admin:
staff_member = True # Make admins also staff members :-)
@ -141,6 +176,10 @@ class Handler(object):
}
def genAuthToken(self, id_auth, username, locale, is_admin, staf_member):
'''
Generates the authentication token from a session, that is basically
the session key itself
'''
session = SessionStore()
session.set_expiry(GlobalConfig.ADMIN_IDLE_TIME.getInt())
Handler.storeSessionAuthdata(session, id_auth, username, locale, is_admin, staf_member)
@ -150,6 +189,9 @@ class Handler(object):
return self._authToken
def cleanAuthToken(self):
'''
Cleans up the authentication token
'''
self._authToken = None
if self._session:
self._session.delete()
@ -157,21 +199,33 @@ class Handler(object):
# Session related (from auth token)
def getValue(self, key):
'''
Get REST session related value for a key
'''
try:
return self._session['REST'].get(key)
except:
return None
except Exception:
return None # _session['REST'] does not exists?
def setValue(self, key, value):
'''
Set a session key value
'''
try:
self._session['REST'][key] = value
self._session.accessed = True
self._session.save()
except:
pass
except Exception:
logger.exception('Got an exception setting session value {} to {}'.format(key, value))
def is_admin(self):
'''
True if user of this REST request is administrator
'''
return self.getValue('is_admin') and True or False
def is_staff_member(self):
'''
True if user of this REST request is member of staff
'''
return self.getValue('staff_member') and True or False

View File

@ -199,7 +199,7 @@ class Transports(DetailHandler):
return [{
'id': i.id,
'name': i.name,
'type': self.type_as_dict(i.getType()),
'type': self.typeAsDict(i.getType()),
'comments': i.comments,
'priority': i.priority,
} for i in parent.transports.all()]

View File

@ -37,14 +37,14 @@ from django.utils.translation import ugettext as _
from django.db import IntegrityError
from uds.core.ui.UserInterface import gui as uiGui
from uds.REST.handlers import Handler
from uds.REST.handlers import Handler, HandlerError
from uds.core.util import log
import logging
logger = logging.getLogger(__name__)
__updated__ = '2014-05-19'
__updated__ = '2014-09-15'
# a few constants
@ -56,7 +56,10 @@ LOG = 'log'
# Exception to "rethrow" on save error
class SaveException(Exception):
class SaveException(HandlerError):
'''
Exception thrown if couldn't save
'''
pass
@ -64,6 +67,9 @@ class SaveException(Exception):
class BaseModelHandler(Handler):
def addField(self, gui, field):
'''
Add a field to a "gui" description
'''
gui.append({
'name': field.get('name', ''),
'value': '',
@ -84,6 +90,9 @@ class BaseModelHandler(Handler):
return gui
def addDefaultFields(self, gui, flds):
'''
Adds default fields (based in a list) to a "gui" description
'''
if 'name' in flds:
self.addField(gui, {
'name': 'name',
@ -94,40 +103,47 @@ class BaseModelHandler(Handler):
})
if 'comments' in flds:
self.addField(gui, {
'name': 'comments',
'label': _('Comments'),
'tooltip': _('Comments for this element'),
'length': 256,
'order': 0 - 99,
'name': 'comments',
'label': _('Comments'),
'tooltip': _('Comments for this element'),
'length': 256,
'order': 0 - 99,
})
if 'priority' in flds:
self.addField(gui, {
'name': 'priority',
'type': 'numeric',
'label': _('Priority'),
'tooltip': _('Selects the priority of this element (lower number means higher priority)'),
'required': True,
'value': 1,
'length': 4,
'order': 0 - 98,
'name': 'priority',
'type': 'numeric',
'label': _('Priority'),
'tooltip': _('Selects the priority of this element (lower number means higher priority)'),
'required': True,
'value': 1,
'length': 4,
'order': 0 - 98,
})
if 'small_name' in flds:
self.addField(gui, {
'name': 'small_name',
'type': 'text',
'label': _('Short name'),
'tooltip': _('Short name of this element'),
'required': True,
'length': 128,
'order': 0 - 97,
'name': 'small_name',
'type': 'text',
'label': _('Short name'),
'tooltip': _('Short name of this element'),
'required': True,
'length': 128,
'order': 0 - 97,
})
return gui
def typeInfo(self, type_):
'''
Returns info about the type
In fact, right now, it returns an empty dict, that will be extended by typeAsDict
'''
return {}
def type_as_dict(self, type_):
def typeAsDict(self, type_):
'''
Returns a dictionary describing the type (the name, the icon, description, etc...)
'''
res = self.typeInfo(type_)
res.update({
'name': _(type_.name()),
@ -138,6 +154,9 @@ class BaseModelHandler(Handler):
return res
def processTableFields(self, title, fields, row_style):
'''
Returns a dict containing the table fields description
'''
return {
'title': unicode(title),
'fields': fields,
@ -369,10 +388,11 @@ class ModelHandler(BaseModelHandler):
needs_staff = True
# Which model does this manage
model = None
# This is an array of tuples of two items, where first is method and second inticates if method needs parent id
# For example ('services', True) -- > .../id_parent/services
# ('services', False) --> ..../services
custom_methods = [] # If this model respond to "custom" methods, we will declare them here
# This is an array of tuples of two items, where first is method and second inticates if method needs parent id
# For example ('services', True) -- > .../id_parent/services
# ('services', False) --> ..../services
# If this model has details, which ones
detail = None # Dictionary containing detail routing
# Put needed fields
@ -394,7 +414,7 @@ class ModelHandler(BaseModelHandler):
def getTypes(self, *args, **kwargs):
for type_ in self.enum_types():
yield self.type_as_dict(type_)
yield self.typeAsDict(type_)
def getType(self, type_):
found = None
@ -480,14 +500,14 @@ class ModelHandler(BaseModelHandler):
try:
operation = getattr(self, self._args[1])
item = self.model.objects.get(pk=self._args[0])
except:
except Exception:
self.invalidMethodException()
return operation(item)
elif self._args[0] == cm[0]:
try:
operation = getattr(self, self._args[0])
except:
except Exception:
self.invalidMethodException()
return operation()
@ -538,6 +558,9 @@ class ModelHandler(BaseModelHandler):
self.invalidRequestException()
def post(self):
'''
Processes a POST request
'''
# right now
logger.debug('method POST for {0}, {1}'.format(self.__class__.__name__, self._args))
if len(self._args) == 2:

View File

@ -32,9 +32,10 @@
from __future__ import unicode_literals
from django.conf.urls import patterns
__updated__ = '2014-02-19'
__updated__ = '2014-09-15'
urlpatterns = patterns('uds.admin.views',
urlpatterns = patterns(
'uds.admin.views',
(r'^$', 'index'),
(r'^tmpl/(?P<template>[a-zA-Z0-9_-]*)$', 'tmpl'),
(r'^sample$', 'sample'),

View File

@ -41,7 +41,7 @@ from uds.core.util.decorators import denyBrowsers
import logging
__updated__ = '2014-06-11'
__updated__ = '2014-09-15'
logger = logging.getLogger(__name__)

View File

@ -43,7 +43,7 @@ from uds.core.ui.UserInterface import gui
import logging
__updated__ = '2014-06-11'
__updated__ = '2014-09-15'
logger = logging.getLogger(__name__)

View File

@ -36,12 +36,12 @@ js_info_dict = {
}
from django.conf import settings
from django.conf.urls import patterns, include, url
from uds.core.util.modfinder import loadModulesUrls
from uds import REST
urlpatterns = patterns('uds',
urlpatterns = patterns(
'uds',
(r'^$', 'web.views.index'),
(r'^login/$', 'web.views.login'),
(r'^login/(?P<smallName>.+)$', 'web.views.login'),

View File

@ -34,13 +34,13 @@ This package contains all xmlrpc related stuff
'''
from __future__ import unicode_literals
from django.utils.translation import ugettext_noop as _
# from django.utils.translation import ugettext_noop as _
from uds.core.managers.DownloadsManager import DownloadsManager
import os.path
import sys
# from uds.core.managers.DownloadsManager import DownloadsManager
# import os.path
# import sys
DownloadsManager.manager().registerDownloadable('UDSAdminSetup.exe',
_('UDS Client Administration Interface <b>(Important!! Requires .net framework 3.5 sp1)</b>'),
os.path.dirname(sys.modules[__package__].__file__) + '/files/UDSAdminSetup.exe',
'application/x-msdownload')
# DownloadsManager.manager().registerDownloadable('UDSAdminSetup.exe',
# _('UDS Client Administration Interface <b>(Important!! Requires .net framework 3.5 sp1)</b>'),
# os.path.dirname(sys.modules[__package__].__file__) + '/files/UDSAdminSetup.exe',
# 'application/x-msdownload')

View File

@ -31,7 +31,6 @@
@author: Adolfo Gómez, dkmaster at dkmon dot com
'''
from django.db import transaction
from uds.models import UserService
from uds.core.util.State import State
from uds.core.util import log
@ -48,7 +47,8 @@ def test():
logger.debug("Test called")
return True
def message(id_, message, data):
def message_fnc(id_, message, data):
'''
Process a message from the actor.
@param _id: Ids used by actors to identify themself and locate services to witch they belongs
@ -84,4 +84,4 @@ def registerActorFunctions(dispatcher):
Utility function to register methods at xmlrpc server for actor
'''
dispatcher.register_function(test, 'test')
dispatcher.register_function(message, 'message')
dispatcher.register_function(message_fnc, 'message')

View File

@ -40,7 +40,7 @@ from django.views.decorators.csrf import csrf_exempt
# from services.DeployedServices import registerDeployedServicesFunctions
# from services.Publications import registerPublicationsFunctions
# from services.UserDeployedServices import registerUserDeployedServiceFunctions
from actor.Actor import registerActorFunctions
from uds.xmlrpc.actor.Actor import registerActorFunctions
# from util.Callbacks import registerCallbackFunctions
# from auths.AdminAuth import registerAdminAuthFunctions
# from auths.Authenticators import registerAuthenticatorFunctions
@ -59,6 +59,7 @@ import logging
logger = logging.getLogger(__name__)
class XMLRPCDispatcher(SimpleXMLRPCDispatcher):
'''
Own dispatchers, to allow the pass of the request to the methods.
@ -73,7 +74,6 @@ class XMLRPCDispatcher(SimpleXMLRPCDispatcher):
def __init__(self):
SimpleXMLRPCDispatcher.__init__(self, allow_none=False, encoding=None)
def dispatch(self, request, **kwargs):
import xmlrpclib
xml = request.body
@ -91,13 +91,15 @@ class XMLRPCDispatcher(SimpleXMLRPCDispatcher):
except Exception as e:
response = xmlrpclib.dumps(
xmlrpclib.Fault(1, "Exception caught!: {0}".format(e))
)
)
logger.exception('Excaption processing xmlrpc message')
return HttpResponse(response, content_type='text/xml')
dispatcher = XMLRPCDispatcher()
# csrf_exempt is needed because we don't expect xmlrcp to be called from a web form
@csrf_exempt
def xmlrpc(request):
@ -108,20 +110,6 @@ def xmlrpc(request):
response = HttpResponse()
response.write("<b>This is an XML-RPC Service.</b><br>")
response.write("You need to invoke it using an XML-RPC Client!<br>")
# response.write("The following methods are available:<ul>")
# methods = dispatcher.system_listMethods()
# for method in methods:
# right now, my version of SimpleXMLRPCDispatcher always
# returns "signatures not supported"... :(
# but, in an ideal world it will tell users what args are expected
# sig = dispatcher.system_methodSignature(method)
# this just reads your docblock, so fill it in!
# help = dispatcher.system_methodHelp(method)
# response.write("<li><b>%s</b>: [%s] %s" % (method, sig, help))
# response.write("</ul>")
response['Content-length'] = str(len(response.content))
return response