# coding: utf-8
# python
import traceback
import string
import json
import types
import datetime
import os
import re
import copy
# django
from django.http import HttpResponse, Http404
from django.core.mail import send_mail
from django.utils.translation import ugettext as _
from django.db.models import Q
from django.contrib.auth.models import User
from django.contrib.auth import login, authenticate, logout
from django.shortcuts import render_to_response
from django.template import RequestContext
from django.core.cache import cache
from business import WorkFlowBusiness
from models import get_result_ERROR, XpMsgException
from util import TemplateParser, AppTemplateParser, get_instances, get_app_path
from models import SearchIndex, Context
from data import ParamDAO, ApplicationDAO, TemplateDAO, ViewTmplDAO
from data import MenuParamDAO, ViewMenuDAO, ActionDAO, ServiceMenuDAO, ApplicationMediaDAO
from data import SearchIndexDAO, SearchIndexParamDAO, WordDAO, SearchIndexWordDAO, ViewMenuConditionDAO, ServiceMenuConditionDAO
from ximpia.util import resources
from choices import Choices
from ximpia.util import ut_email
from models import JsResultDict, ctx
# Constants
import constants as K
# Settings
from ximpia.xpcore.util import get_class
from ximpia.xpsite.data import SettingDAO
settings = get_class(os.getenv("DJANGO_SETTINGS_MODULE"))
# Logging
import logging.config
logging.config.dictConfig(settings.LOGGING)
logger = logging.getLogger(__name__)
from data import ViewDAO
from forms import DefaultForm
from ximpia.util.js import Form as _jsf
class CommonWorker(object):
"""
Common worker class
"""
pass
class EmailService(object):
#python -m smtpd -n -c DebuggingServer localhost:1025
@staticmethod
def send(xml_message, subs_dict, from_addr, recipient_list):
"""Send email
@staticmethod
Run this to simulate email server:
python -m smtpd -n -c DebuggingServer localhost:1025
and have this in your settings.py:
EMAIL_HOST = 'localhost'
EMAIL_PORT = 1025
**Attributes**
``xmlMessage`` : Xml message (from settings)
``subsDict`` : Substitution dictionary, like...
{'scheme': settings.XIMPIA_SCHEME,
'host': settings.XIMPIA_BACKEND_HOST,
'appSlug': K.Slugs.SITE,
'activate': K.Slugs.ACTIVATE_USER,
'firstName': self._f()['firstName'],
'user': self._f()['ximpiaId'],
'activationCode': activationCode}
Email Xml message should have variables marked with '$', like $host, $appslug, etc...
``fromAddr``:String
``recipientList``:List<String>
**Returns**
None
"""
#logger.debug( 'subsDict: %s' % (subsDict) )
subject, message = ut_email.getMessage(xml_message)
message = string.Template(message).substitute(**subs_dict)
#logger.debug( message )
send_mail(subject, message, from_addr, recipient_list)
# ****************************************************
# ** DECORATORS **
# ****************************************************
class service(object):
"""Build response from jsData"""
_pageError = False
_form = None
_isServerTmpl = False
def __init__(self, *argsTuple, **argsDict):
"""
Options
=======
pageError: Show error detail as a list in a popup or show error in a message bar. pageError=True : Show error message bar
form: Form class attached to the view
isServerTmpl: True | False : If result is jsData or Http json representation
"""
#logger.debug( 'service :: argsDict: %s argsTuple: %s' % (argsDict, argsTuple) )
if argsDict.has_key('pageError'):
self._pageError = argsDict['pageError']
else:
self._pageError = False
if argsDict.has_key('form'):
self._form = argsDict['form']
"""if argsDict.has_key('isServerTmpl'):
self._isServerTmpl = argsDict['isServerTmpl']"""
def __call__(self, f):
def wrapped_f(*argsTuple, **argsDict):
obj = argsTuple[0]
logger.debug( 'service :: data: %s %s' % (argsTuple, argsDict) )
try:
doRedirect = False
redirectUrl = ''
self._isServerTmpl = obj._ctx.isServerTmpl
logger.debug('service :: isServerTmpl: %s' % (self._isServerTmpl) )
#logger.debug( 'service :: ctx: %s' % (obj._ctx.keys()) )
obj._ctx.jsData = JsResultDict()
if self._form != None:
obj._set_main_form(self._form())
f(*argsTuple, **argsDict)
if not obj._ctx.doneResult:
# Instances
dbApp = ApplicationDAO(obj._ctx)
# View
logger.debug( 'service :: viewNameTarget: %s' % (str(obj._ctx.viewNameTarget)) )
logger.debug( 'service :: viewNameSource: %s' % (str(obj._ctx.viewNameSource)) )
if len(obj._ctx.viewNameTarget) > 1:
viewName = obj._ctx.viewNameTarget
else:
viewName = obj._ctx.viewNameSource
logger.debug( 'service :: viewName: %s' % (viewName) )
# Views
obj._ctx.jsData['response']['view'] = viewName
logger.debug( 'service :: view: %s' % ('*' + str(obj._ctx.jsData['response']['view']) + '*') )
# App
obj._ctx.jsData['response']['app'] = obj._ctx.app
obj._ctx.jsData['response']['appSlug'] = dbApp.get(name=obj._ctx.app).slug
obj._ctx.jsData['response']['isDefaultApp'] = obj._ctx.app == settings.XIMPIA_DEFAULT_APP
# winType
if len(obj._ctx.jsData['response']['view'].strip()) != 0:
dbView = ViewDAO(obj._ctx)
view = dbView.get(application__name=obj._ctx.app, name=obj._ctx.jsData['response']['view'])
logger.debug( 'service :: winType: %s' % (str(view.winType)) )
obj._ctx.jsData['response']['winType'] = view.winType
obj._ctx.jsData['response']['viewSlug'] = view.slug
# User authenticate and session
logger.debug('service :: User: %s' % (obj._ctx.user) )
if obj._ctx.user.is_authenticated():
# login: context variable isLogin = True
obj._ctx.jsData.addAttr('isLogin', True)
#obj._ctx.jsData.addAttr('userid', self._ctx['user'].pk)
keyList = obj._ctx.session.keys()
session = {}
for key in keyList:
if key[0] != '_':
try:
# We try to serialize using django serialize
dataEncoded = _jsf.encodeObj(obj._ctx.session[key])
dataReal = json.loads(dataEncoded)
if type(obj._ctx.session[key]) == types.ListType:
session[key] = dataReal
else:
session[key] = dataReal[0]
except:
# If we cant, we try json encode
dataEncoded = json.dumps(obj._ctx.session[key])
session[key] = json.loads(dataEncoded)
obj._ctx.jsData['response']['session'] = session
else:
obj._ctx.jsData.addAttr('isLogin', False)
# Template
tmpl = TemplateService(obj._ctx)
if len(obj._ctx.jsData['response']['view'].strip()) != 0:
templates = tmpl.resolve(obj._ctx.jsData['response']['view'])
if templates.has_key(obj._ctx.jsData['response']['view']):
tmplName = templates[obj._ctx.jsData['response']['view']] #@UnusedVariable
#tmplName = tmpl.resolve(obj._ctx.jsData['response']['view'])
logger.debug( 'service :: tmplName: %s' % (tmplName) )
else:
raise XpMsgException(None, _('Error in resolving template for view'))
obj._ctx.jsData['response']['tmpl'] = templates
else:
# In case we show only msg with no view, no template
logger.debug( 'service :: no View, no template...' )
obj._ctx.jsData['response']['tmpl'] = ''
# Forms
logger.debug( 'service :: forms: %s' % (obj._ctx.forms) )
for formId in obj._ctx.forms:
form = obj._ctx.forms[formId]
if not obj._ctx.jsData.has_key(formId):
form.build_js_data(obj._ctx.app, obj._ctx.jsData)
logger.debug( 'service :: form: %s app: %s' % (formId, form.base_fields['app'].initial) )
#logger.debug( 'service :: response keys : %s' % (obj._ctx.jsData['response'].keys()) )
# Result
#logger.debug( 'service :: isServerTmpl: %s' % (self._isServerTmpl) )
# Settings
if not obj._ctx.jsData['response'].has_key('settings'):
obj._ctx.jsData['response']['settings'] = {}
# Get settings with mustAutoLoad=true for global and for this app
dbSetting = SettingDAO(obj._ctx, related_depth=1)
settingsApp = dbSetting.search_settings(obj._ctx.app)
for setting in settingsApp:
try:
value = eval(setting.value)
except NameError:
value = setting.value
obj._ctx.jsData['response']['settings'][setting.name.name] = value
# Menu
menu = MenuService(obj._ctx)
menuDict = menu.get_menus(viewName)
obj._ctx.jsData['response']['menus'] = menuDict
if self._isServerTmpl == False:
result = obj._build_JSON_result(obj._ctx.jsData)
#logger.debug( obj._ctx.jsData )
################# Print response
logger.debug('')
logger.debug( 'service :: #################### RESPONSE ##################' )
#logger.debug( 'service :: response keys: %s' % (obj._ctx.jsData['response'].keys()) )
keys = obj._ctx.jsData['response'].keys()
for key in keys:
keyValue = obj._ctx.jsData['response'][key]
#logger.debug( 'key: %s' % (key, type(keyValue)) )
if type(keyValue) == types.DictType and keyValue.has_key('value'):
logger.debug( 'service :: response %s : %s' % (key, str(keyValue['value'])) )
elif type(keyValue) != types.DictType:
logger.debug( 'service :: response %s: %s' % (key, str(keyValue)) )
else:
for newKey in keyValue:
#logger.debug( 'newKey: ', newKey )
#logger.debug( keyValue[newKey] )
if type(keyValue[newKey]) == types.DictType and keyValue[newKey].has_key('value'):
logger.debug( 'service :: response %s %s: %s' % (key, newKey, str(keyValue[newKey]['value'])) )
elif type(keyValue[newKey]) != types.DictType:
logger.debug( 'service :: response %s %s: %s' % (key, newKey, str(keyValue[newKey])) )
################# Print response
logger.debug( 'service :: #################### RESPONSE ##################' )
logger.debug( '' )
else:
result = obj._ctx.jsData
#logger.debug( result )
################# Print response
logger.debug( '' )
logger.debug( 'service :: #################### RESPONSE ##################' )
#logger.debug( 'service :: response keys: %s' % (obj._ctx.jsData['response'].keys()) )
keys = obj._ctx.jsData['response'].keys()
for key in keys:
keyValue = obj._ctx.jsData['response'][key]
#logger.debug( 'key: ', key, type(keyValue) )
if type(keyValue) == types.DictType and keyValue.has_key('value'):
logger.debug( 'service :: response %s: %s' % (key, str(keyValue['value'])) )
elif type(keyValue) != types.DictType:
logger.debug( 'service :: response %s: %s' % (key, str(keyValue)) )
else:
for newKey in keyValue:
#logger.debug( 'newKey: %s' % (newKey) )
#logger.debug( keyValue[newKey] )
if type(keyValue[newKey]) == types.DictType and keyValue[newKey].has_key('value'):
logger.debug( 'service :: response %s %s: %s' % (key, newKey, str(keyValue[newKey]['value'])) )
elif type(keyValue[newKey]) != types.DictType:
logger.debug( 'service :: response %s %s: %s' % (key, newKey, str(keyValue[newKey])) )
################# Print response
logger.debug( 'service :: #################### RESPONSE ##################' )
logger.debug( '' )
logger.debug( obj._ctx.jsData['response'].keys() )
#obj._ctx['_doneResult'] = True
obj._ctx.doneResult = True
else:
logger.debug( 'service :: I skip building response, since I already did it!!!!!' )
if self._isServerTmpl == False:
result = obj._build_JSON_result(obj._ctx.jsData)
else:
result = obj._ctx.jsData
return result
except XpMsgException as e:
logger.debug( 'service :: ERROR!!!! service!!!!!' )
errorDict = obj._get_errors()
if len(errorDict) != 0:
if self._isServerTmpl == False:
result = obj._build_JSON_result(obj._get_error_result_dict(errorDict, page_error=self._pageError))
else:
result = obj._get_error_result_dict(errorDict, page_error=self._pageError)
logger.debug( result )
else:
if settings.DEBUG == True:
logger.debug( errorDict )
logger.debug( e )
logger.debug( e.myException )
traceback.print_exc()
raise
return result
return wrapped_f
class validation(object):
"""Business validation"""
_pageError = False
_form = None
_isServerTmpl = False
def __init__(self, *argsTuple, **argsDict):
pass
def __call__(self, f):
def wrapped_f(*argsTuple, **argsDict):
obj = argsTuple[0]
f(*argsTuple, **argsDict)
obj._is_valid()
return wrapped_f
class validate_form(object):
"""Checks that form is valid, builds result, builds errors"""
_form = None
_pageError = False
def __init__(self, *argsTuple, **argsDict):
"""
Options
=======
form: Form class
"""
# Sent by decorator
self._form = argsTuple[0]
"""if argsDict.has_key('pageError'):
self._pageError = argsDict['pageError']
else:
self._pageError = False"""
def __call__(self, f):
"""Decorator call method"""
def wrapped_f(*argsTuple, **argsDict):
"""Doc."""
#logger.debug( 'validate_form :: %s %s' % (argsTuple, argsDict) )
obj = argsTuple[0]
#result = f(*argsTuple, **argsDict)
obj._ctx.jsData = JsResultDict()
obj._ctx.form = self._form(obj._ctx.post, ctx=obj._ctx)
bForm = obj._ctx.form.is_valid()
#obj._ctx.form = obj._f
#logger.debug( 'validate_form :: Form Validation: %s' % (bForm) )
if bForm == True:
obj._set_main_form(obj._ctx.form)
result = f(*argsTuple, **argsDict)
return result
"""try:
f(*argsTuple, **argsDict)
obj._f.buildJsData(obj._ctx.jsData)
result = obj.build_JSON_result(obj._ctx.jsData)
#logger.debug( result )
return result
except XpMsgException as e:
errorDict = obj.getErrors()
if settings.DEBUG == True:
logger.debug( errorDict )
logger.debug( e )
logger.debug( e.myException )
traceback.printl_exc()
if len(errorDict) != 0:
result = obj.build_JSON_result(obj.getErrorResultDict(errorDict, page_error=self._pageError))
else:
raise
return result"""
"""except Exception as e:
if settings.DEBUG == True:
logger.debug( e )
traceback.printl_exc()"""
else:
if settings.DEBUG == True:
logger.debug( 'Validation error!!!!!' )
#logger.debug( obj._f )
logger.debug( obj._ctx.form.errors )
if obj._ctx.form.errors.has_key('invalid'):
logger.debug( obj._ctx.form.errors['invalid'] )
traceback.print_exc()
if obj._ctx.form.errors.has_key('invalid'):
errorDict = {'': obj._ctx.form.errors['invalid'][0]}
logger.debug( 'errorDict: %s' % (errorDict) )
result = obj._build_JSON_result(obj._getErrorResultDict(errorDict, page_error=True))
else:
#errorDict = {'': 'Error validating your data. Check it out and send again'}
# Build errordict
errorDict = {}
for field in obj._ctx.form.errors:
if field != '__all__':
errorDict[field] = obj._ctx.form.errors[field][0]
logger.debug( 'errorDict: %s' % (errorDict) )
result = obj._build_JSON_result(obj._getErrorResultDict(errorDict, page_error=False))
return result
return wrapped_f
class wf_view( object ):
__flowCode = ''
def __init__(self, *argsTuple, **argsDict):
"""resetStart, jumpToView"""
self.__flowCode = argsTuple[0]
def __call__(self, f):
"""Doc."""
def wrapped_f(*argsTuple, **argsDict):
#logger.debug( 'WFViewstartDecorator :: %s %s' % (argsTuple, argsDict) )
obj = argsTuple[0]
#obj._wf = WorkFlowBusiness(obj._ctx)
obj._ctx.flowCode = self.__flowCode
obj._ctx.isFlow = True
logger.debug( 'wf_view :: flowCode: %s' % (self.__flowCode) )
flow = obj._wf.get(self.__flowCode)
viewName = obj._ctx.viewNameSource
logger.debug( 'wf_view :: View Current: %s' % (obj._ctx.viewNameSource) )
# WorKflow User Id
"""if obj._ctx.cookies.has_key('wfUserId'):
obj._ctx.wfUserId = obj._ctx.cookies['wfUserId']
logger.debug( 'wf_view :: COOKIE :: WF User Id: %s' % (obj._ctx.wfUserId) )
else:
obj._ctx.wfUserId = obj._wf.genUserId()
obj._set_cookie('wfUserId', obj._ctx.wfUserId)
logger.debug( 'wf_view :: WF UserId: %s' % (obj._ctx.wfUserId) )"""
obj._ctx.wfUserId = obj._getWFUser()
logger.debug( 'wf_view :: WF UserId: %s' % (obj._ctx.wfUserId) )
hasFlow = True
try:
flowData = obj._wf.getFlowDataDict(obj._ctx.wfUserId, self.__flowCode)
logger.debug( 'wf_view :: flowData: %s' % (flowData) )
except XpMsgException:
hasFlow = False
logger.debug( 'wf_view :: hasFlow: %s' % (hasFlow) )
if flow.jumpToView == True and hasFlow == True:
# Get flow data, display view in flow data
try:
viewName = obj._wf.getView(obj._ctx.wfUserId, self.__flowCode)
logger.debug( 'wf_view :: Jump to View: %s %s' % (obj._ctx.viewNameSource, viewName) )
except XpMsgException:
pass
else:
isFirstView = obj._wf.isFirstView(self.__flowCode, obj._ctx.viewNameSource)
logger.debug( 'wf_view :: Flow Data: %s %s' % (hasFlow, isFirstView) )
# Check that this view is first in flow
if hasFlow == False and isFirstView == True:
logger.debug( 'wf_view :: reset Flow... no flow and first window' )
obj._wf.resetFlow(obj._ctx.wfUserId, self.__flowCode, obj._ctx.viewNameSource)
elif isFirstView == True and flow.resetStart == True:
logger.debug( 'wf_view :: reset Flow... resetStart=True and first view in flow...' )
obj._wf.resetFlow(obj._ctx.wfUserId, self.__flowCode, obj._ctx.viewNameSource)
obj._ctx.viewNameTarget = viewName
# Jump to View in case jumpToView = True and viewName resolved from flow is different from current view
#logger.debug( 'wf_view :: Jumps... %s %s' % (viewName, obj._ctx.viewNameSource) )
if viewName != obj._ctx.viewNameSource:
logger.debug( 'wf_view :: redirect to ... %s' % (viewName) )
dbView = ViewDAO(obj._ctx)
view = dbView.get(name=viewName)
viewAttrs = obj._wf.getViewParams(self.__flowCode, viewName)
# Show View
impl = view.implementation
implFields = impl.split('.')
method = implFields[len(implFields)-1]
classPath = ".".join(implFields[:-1])
cls = get_class( classPath )
objView = cls(obj._ctx) #@UnusedVariable
obj._ctx.viewNameSource = viewName
if (len(viewAttrs) == 0) :
result = eval('objView.' + method)()
else:
result = eval('objView.' + method)(**viewAttrs)
else:
result = f(*argsTuple, **argsDict)
return result
return wrapped_f
class menu_action(object):
__viewName = ''
def __init__(self, *argsTuple, **argsDict):
self.__viewName = argsTuple[0]
def __call__(self, f):
"""Decorator call method"""
def wrapped_f(*argsTuple, **argsDict):
obj = argsTuple[0]
f(*argsTuple, **argsDict)
# Show View
dbView = ViewDAO(obj._ctx)
view = dbView.get(name=self.__viewName)
logger.debug( 'MenuAction :: %s' % (view.name) )
obj._ctx.viewNameSource = view.name
impl = view.implementation
implFields = impl.split('.')
method = implFields[len(implFields)-1]
classPath = ".".join(implFields[:-1])
cls = get_class( classPath )
objView = cls(obj._ctx) #@UnusedVariable
result = eval('objView.' + method)()
return result
return wrapped_f
class wf_action(object):
__app = ''
__flowCode = ''
def __init__(self, *argsTuple, **argsDict):
"""
Options
=======
app: String : Application code
"""
# Sent by decorator
"""if argsDict.has_key('app'):
self._app = argsDict['app']"""
#self.__flowCode = argsTuple[0]
pass
def __call__(self, f):
"""Decorator call method"""
def wrapped_f(*argsTuple, **argsDict):
obj = argsTuple[0]
try:
#logger.debug( 'viewNameSource: %s' % (obj._ctx.viewNameSource) )
#logger.debug( 'viewNameTarget: %s' % (obj._ctx.viewNameTarget) )
#logger.debug( 'actionName: %s' % (obj._ctx.action) )
#obj._wf = WorkFlowBusiness()
actionName = obj._ctx.action
flow = obj._wf.getFlowViewByAction(actionName).flow
self.__app = flow.application.name
logger.debug( 'app: %s' % (self.__app) )
obj._ctx.flowCode = flow.code
obj._ctx.isFlow = True
#logger.debug( 'wf_action :: flowCode: %s' % (obj._ctx.flowCode) )
obj._ctx.wfUserId = obj._ctx.cookies['wfUserId']
logger.debug( 'COOKIE :: WF User Id: %s' % (obj._ctx.wfUserId) )
result = f(*argsTuple, **argsDict)
# Resolve View
#logger.debug( 'session' % (obj._ctx.session) )
viewTarget = obj._wf.resolveView(obj._ctx.wfUserId, self.__app, obj._ctx.flowCode,
obj._ctx.viewNameSource, obj._ctx.action)
viewName = viewTarget.name
#logger.debug( 'viewName: %s' % (viewName) )
# Insert view into workflow
obj._wf.setViewName(viewName)
viewAttrs = obj._wf.getViewParams(obj._ctx.flowCode, viewName)
#logger.debug( 'viewAttrs: %s' % (viewAttrs) )
# Save workflow
flowData = obj._wf.save(obj._ctx.wfUserId, obj._ctx.flowCode)
# Set Flow data dictionary into context
obj._ctx.flowData = obj._wf.buildFlowDataDict(flowData)
#logger.debug( 'flowDataDict: %s' % (obj._ctx.flowData) )
# Delete user flow if deleteOnEnd = True
if flow.deleteOnEnd == True and obj._wf.isLastView(obj._ctx.viewNameSource, viewName, obj._ctx.action):
obj._wf.removeData(obj._ctx.wfUserId, obj._ctx.flowCode)
obj._ctx.viewNameTarget = viewName
# Show View
impl = viewTarget.implementation
implFields = impl.split('.')
method = implFields[len(implFields)-1]
classPath = ".".join(implFields[:-1])
cls = get_class( classPath )
objView = cls(obj._ctx) #@UnusedVariable
if (len(viewAttrs) == 0) :
result = eval('objView.' + method)()
else:
result = eval('objView.' + method)(**viewAttrs)
except XpMsgException as e:
logger.debug( 'ERROR!!!! wf_action!!!!!' )
errorDict = obj._getErrors()
if len(errorDict) != 0:
result = obj._build_JSON_result(obj._getErrorResultDict(errorDict, page_error=True))
logger.debug( result )
else:
if settings.DEBUG == True:
logger.debug( errorDict )
logger.debug( e )
logger.debug( e.myException )
traceback.print_exc()
raise
return result
return wrapped_f
class view_tmpl(object):
""""Decorator for django views in core module."""
__viewName = ''
__APP = ''
__APP_OBJ = None
__APP_SLUG = ''
__package = ''
_settings = {}
def __init__(self, *argsTuple, **argsDict):
if len(argsTuple) != 0:
logger.debug('view_tmpl :: argList: %s' % (argsTuple) )
#self.__APP = '.'.join(argsTuple[0].split('.')[:2])
self.__package = argsTuple[0].split('.')[0]
self.__APP = argsTuple[0].split('.')[1]
def __call__(self, f):
"""Decorator call method"""
def wrapped_f(request, **args):
logger.debug( 'view_tmpl :: args: %s' % args )
# Data instances
dbApp = ApplicationDAO(args['ctx'])
dbView = ViewDAO(args['ctx'])
ctx = args['ctx']
if False: ctx = Context()
if args.has_key('appSlug') and len(args['appSlug']) != 0:
self.__APP_OBJ = dbApp.get(slug=args['appSlug'])
self.__APP = self.__APP_OBJ.name
self.__APP_SLUG = self.__APP_OBJ.slug
if args.has_key('viewSlug'):
logger.debug( 'view_tmpl :: set from args view name' )
try:
view = dbView.get(slug=args['viewSlug'], application__name = self.__APP)
args['ctx'].viewAuth = view.hasAuth
except XpMsgException as e:
raise Http404
logger.debug('view_tmpl :: viewName: %s' % (view.name) )
self.__viewName = view.name
else:
self.__viewName = ''
else:
# TODO: Use here the default app for project settings and default view...
#self.__APP = 'ximpia.xpsite'
self.__viewName = 'home'
logger.debug('view_tmpl :: app: %s' % (self.__APP) )
ctx.viewNameSource = self.__viewName
resultJs = f(request, **args)
logger.debug('view_tmpl :: viewNameSource: %s viewNameTarget: %s' % (args['ctx'].viewNameSource, args['ctx'].viewNameTarget) )
if self.__viewName != args['ctx'].viewNameSource:
self.__viewName = args['ctx'].viewNameSource
if len(ctx.viewNameTarget) != 0:
self.__viewName = ctx.viewNameTarget
logger.debug( 'view_tmpl :: resultJs: %s' % resultJs )
logger.debug( 'view_tmpl :: viewName: %s target: %s source: %s ' %
(self.__viewName, args['ctx'].viewNameTarget, args['ctx'].viewNameSource) )
template = TemplateService(ctx)
templates = template.resolve(self.__viewName)
logger.debug( 'view_tmpl :: templates: %s' % templates )
if resultJs['status'] == 'ERROR':
raise XpMsgException(None, resultJs['errors'][0][1])
if templates.has_key(self.__viewName):
tmplName = templates[self.__viewName]
logger.debug( 'view_tmpl :: tmplName: %s' % tmplName )
# Get template data
tmplService = TemplateService(ctx)
tmplData = tmplService.get(self.__APP, 'window', tmplName)
# Get application template data with footer, scripts and styles
tmplApp = tmplService.get_app(self.__APP)
#logger.debug('view_tmpl :: tmplApp: %s' % (tmplApp) )
parserApp = AppTemplateParser()
parserApp.feed_app(tmplApp, self.__APP)
logger.debug('view_tmpl :: styles: %s' % (parserApp.styles) )
#logger.debug('view_tmpl :: tmplData: %s' % (tmplData) )
parser = TemplateParser()
parser.feed(tmplData)
try:
if self.__APP.find('.') != -1:
masterTmpl = self.__APP.split('.')[1] + '.html'
else:
masterTmpl = self.__APP + '.html'
logger.debug('view_tmpl :: masterTmpl: %s' % (masterTmpl) )
logger.debug('view_tmpl :: title: %s' % (parser.title) )
result = render_to_response( 'xp-base.html', RequestContext(request,
{ 'id_view': parser.id_view,
'title': parser.title,
'titleBar': parser.titleBar,
'content': parser.content,
'buttons': parser.buttons,
'result': json.dumps(resultJs),
'settings': settings,
'view': resultJs['response']['view'],
'viewSlug': resultJs['response']['viewSlug'],
'app': self.__APP,
'appSlug': self.__APP_SLUG,
'scripts': parserApp.scripts,
'styles': parserApp.styles,
'footer': parserApp.footer
}))
except AttributeError as e:
raise XpMsgException(e, _('Error in getting attributes from template. Check that title, titleBar, content and bottom button area exists.'))
#result = result.replace('{{result}}', json.dumps(resultJs))
else:
raise XpMsgException(None, _('Error in resolving template for view %s' % (self.__viewName) ))
return result
return wrapped_f
class view ( object ):
"""
Decorator for ximpia views
"""
__form = None
def __init__(self, form):
self.__form = form
def __call__(self, f):
"""Decorator call method"""
@service(form=self.__form)
def wrapped_f(request, *argsTuple, **argsDict):
result = f(request, *argsTuple, **argsDict)
return result
return wrapped_f
class action ( object ):
"""
Decorator for ximpia actions
"""
__form = None
def __init__(self, form):
self.__form = form
def __call__(self, f):
"""Decorator call method"""
@validate_form(self.__form)
@service()
def wrapped_f(request, *argsTuple, **argsDict):
logger.debug('action :: form: %s' % self.__form)
result = f(request, *argsTuple, **argsDict)
return result
return wrapped_f
class workflow_view ( object ):
"""
Decorator for workflow views
"""
__form = None
__flowCode = None
def __init__(self, flowCode, form):
self.__flowCode = flowCode
self.__form = form
def __call__(self, f):
"""Decorator call method"""
@wf_view(self.__flowCode)
@service(form = self.__form)
def wrapped_f(request, *argsTuple, **argsDict):
logger.debug('workflow_view :: flowCode: %s form: %s' % (self.__flowCode, self.__form))
result = f(request, *argsTuple, **argsDict)
return result
return wrapped_f
class workflow_action ( object ):
"""
Decorator for workflow actions
"""
__form = None
__flowCode = None
def __init__(self, flowCode, form):
self.__flowCode = flowCode
self.__form = form
def __call__(self, f):
"""Decorator call method"""
@validate_form(self.__form)
@wf_action()
def wrapped_f(request, *argsTuple, **argsDict):
logger.debug('workflow_action :: form: %s' % (self.__form) )
result = f(request, *argsTuple, **argsDict)
return result
return wrapped_f
# ****************************************************
# ** DECORATORS **
# ****************************************************
class MenuService( object ):
_ctx = None
def __init__(self, ctx):
"""Menu building and operations"""
self._ctx = ctx
def __checkRender(self, menuItem, conditions):
"""
Check menu condition for render
** Attributes **
* ``viewMenu``:Object : View menu model instance
** Returns **
* ``checkRender``:Boolean
"""
checkRender = True
for conditionItem in conditions:
conditionRule = conditionItem.condition.rule
logger.debug('MenuService.__checkRule :: conditionItem: %s menuItem: %s' % (conditionItem.serviceMenu, menuItem) )
if conditionRule != None and conditionRule != '' and conditionItem.serviceMenu.menu.name == menuItem.menu.name:
# Replace javascript condition-like operators to python-like
conditionRule = conditionRule.replace('&&', 'and')\
.replace('||','or')\
.replace('true','True')\
.replace('false','False')
resp = self._ctx.jsData.response
patts = ['([a-zA-Z0-9._]+\ *==)','([a-zA-Z0-9._]+\ *!=)','([a-zA-Z0-9._]+\ *>)','([a-zA-Z0-9._]+\ *<)',\
'([a-zA-Z0-9._]+\ *>=)','([a-zA-Z0-9._]+\ *<=)']
for patt in patts:
index = re.search(patt, conditionRule)
if index != None:
conditionRule = re.sub(patt, r'resp.\1', conditionRule)
logger.debug('MenuService :: conditionRule: %s' % (conditionRule) )
checkCondition = eval(conditionRule)
logger.debug('MenuService :: checkCondition: %s %s' % (checkCondition, conditionItem.action) )
if conditionItem.action == 'render':
if checkCondition == False and conditionItem.value == True:
logger.debug('MenuService.__checkRule :: conditionRule False and condition render set to True, no render')
checkRender = False
if checkCondition == True and conditionItem.value == False:
logger.debug('MenuService.__checkRule :: conditionRule True and condition render set to False, no render')
checkRender = False
return checkRender
def __getList(self, menuDict, menuList, conditionList):
"""
Append menu dictionary to list of menu items
**Attributes**
* ``menuDict`` : Menu data in dictionary format with atributes about menu item attributes
* ``menuList`` : Queryset with menu items
**Returns**
None
"""
container = {}
for menuItem in menuList:
#logger.debug( 'getMenus :: menuItem: %s' % (menuItem) )
#logger.debug( 'getMenus :: action: %s' % (menuItem.menu.action) )
#logger.debug( 'getMenus :: view: %s' % (menuItem.menu.view) )
# TODO: Check condition
checkRender = self.__checkRender(menuItem, conditionList)
if not checkRender:
continue
menuObj = {}
if menuItem.menu.view != None:
menuObj['service'] = menuItem.menu.view.service.name
if menuItem.menu.action != None:
menuObj['service'] = menuItem.menu.action.service.name
menuObj['action'] = menuItem.menu.action.name if menuItem.menu.action != None else ''
menuObj['view'] = menuItem.menu.view.name if menuItem.menu.view != None else ''
menuObj['viewSlug'] = menuItem.menu.view.slug if menuItem.menu.view != None else ''
if menuItem.menu.view != None and menuItem.menu.view.image != None:
menuObj['image'] = menuItem.menu.view.image
else:
menuObj['image'] = ''
menuObj['winType'] = menuItem.menu.view.winType if menuItem.menu.view != None else ''
menuObj['sep'] = menuItem.hasSeparator
menuObj['name'] = menuItem.menu.name
menuObj['title'] = menuItem.menu.title
menuObj['description'] = menuItem.menu.description
menuObj['icon'] = menuItem.menu.icon.value if menuItem.menu.icon != None else ''
menuObj['zone'] = menuItem.zone
if menuItem.menu.view != None:
menuObj['app'] = menuItem.menu.view.application.name
menuObj['appSlug'] = menuItem.menu.view.application.slug
elif menuItem.menu.action != None:
menuObj['app'] = menuItem.menu.action.application.name
menuObj['appSlug'] = menuItem.menu.action.application.slug
# params
params = self._dbMenuParam.search(menu=menuItem.menu)
paramDict = {}
# name, operator, value
for param in params:
if param.operator == Choices.OP_EQ:
paramDict[param.name] = param.value
menuObj['params'] = paramDict
if menuItem.menu.view.application.name == settings.XIMPIA_DEFAULT_APP:
menuObj['isDefaultApp'] = True
container[menuItem.menu.name] = menuObj
if menuItem.menu.view != None:
menuObj['isCurrent'] = True if menuItem.menu.view.name == self.__viewName else False
#logger.debug( 'menuObj: %s' % (menuObj) )
if menuItem.parent == None:
menuObj['items'] = []
menuDict[menuItem.zone].append(menuObj)
"""if menuItem.zone in ['sys','main']:
if self._ctx.isLogin:
menuDict[menuItem.zone].append(menuObj)
else:
if menuItem.menu.name == 'home':
menuDict[menuItem.zone].append(menuObj)
else:
menuDict[menuItem.zone].append(menuObj)"""
else:
parentMenuObj = container[menuItem.parent.menu.name]
parentMenuObj['items'].append(menuObj)
logger.debug( 'getMenus :: menuDict: %s' % (menuDict) )
def get_menus(self, view_Name):
"""
Build menus in dictionary format
**Attributes**
* ``view_Name`` : View name
**Returns**
menuDict:DictType having the format:
{
'sys': [...],
'main': [...],
'service': [
{
'service' : StringType,
'action': StringType,
'view': StringType,
'winType': StringType,
'hasSep' : BooleanType,
'name' : StringType,
'title' : StringType,
'description' : StringType,
'icon' : StringType,
'zone' : StringType,
'app' : StringType,
'params' : DictType,
'items' : ListType<DictType>,
'isCurrent' : BooleanType,
'isDefaultApp' : BooleanType
}
],
'view': [...]
}
items value will be a list of dictionaries with menu dict keys (action, view, etc..)
params have format key -> value as normal dictionaries.
"""
self.__viewName = view_Name
# db instances
self._dbView = ViewDAO(self._ctx, related_depth=2)
self._dbViewMenu = ViewMenuDAO(self._ctx, related_depth=3)
self._dbServiceMenu = ServiceMenuDAO(self._ctx, related_depth=3)
self._dbMenuParam = MenuParamDAO(self._ctx, related_depth=3)
self._dbViewMenuCondition = ViewMenuConditionDAO(self._ctx, related_depth=2)
self._dbServiceMenuCondition = ServiceMenuConditionDAO(self._ctx, related_depth=2)
# logic
logger.debug( 'getMenus...' )
logger.debug( 'getMenus :: appName: %s' % (self._ctx.app) )
view = self._dbView.get(name=view_Name, application__name=self._ctx.app)
logger.debug( 'getMenus :: view: %s' % (view) )
#viewMenus = self._dbViewMenu.search( view=view ).order_by('order')
#logger.debug( 'getMenus :: viewMenus: %s' % (viewMenus) )
#logger.debug( 'getMenus :: viewMenus All: %s' % (self._dbViewMenu.getAll()) )
logger.debug('getMenus :: user: %s %s' % (self._ctx.user, type(self._ctx.user)) )
menuDict = {}
menuDict[Choices.MENU_ZONE_SYS] = []
menuDict[Choices.MENU_ZONE_MAIN] = []
menuDict[Choices.MENU_ZONE_SERVICE] = []
menuDict[Choices.MENU_ZONE_VIEW] = []
# TODO: Get main and sys without link, from settings ???
# linked to service
# TODO: Move this to data layer????
if self._ctx.user.is_anonymous():
menuList = self._dbServiceMenu.search( menu__application__isSubscription=False,
menu__view__hasAuth=False,
service=view.service ).order_by('order')
else:
menuList = self._dbServiceMenu.search( Q(menu__application__isSubscription=False) |
Q(menu__application__isSubscription=True) &
Q(menu__application__accessGroup__group__user=self._ctx.user) ,
service=view.service ).order_by('order')
conditionList = self._dbServiceMenuCondition.search(serviceMenu__in=menuList)
logger.debug('menuList Services: %s' % (menuList) )
logger.debug('conditionList Services: %s' % (conditionList) )
self.__getList(menuDict, menuList, conditionList)
# linked to view
if self._ctx.user.is_anonymous():
menuList = self._dbViewMenu.search( menu__application__isSubscription=False,
menu__view__hasAuth=False,
view=view ).order_by('order')
else:
menuList = self._dbViewMenu.search( Q(menu__application__isSubscription=False) |
Q(menu__application__isSubscription=True) &
Q(menu__application__accessGroup__group__user=self._ctx.user) ,
view=view ).order_by('order')
conditionList = self._dbViewMenuCondition.search(viewMenu__in=menuList)
logger.debug('menuList Views: %s' % (menuList) )
logger.debug('conditionList Views: %s' % (conditionList) )
self.__getList(menuDict, menuList, conditionList)
return menuDict
class SearchService ( object ):
_ctx = None
def __init__(self, ctx):
"""Search index operations"""
self._ctx = ctx
self._dbApp = ApplicationDAO(self._ctx)
self._dbView = ViewDAO(self._ctx, related_depth=2)
self._dbAction = ActionDAO(self._ctx, related_depth=2)
self._dbSearch = SearchIndexDAO(self._ctx, related_depth=3)
self._dbIndexWord = SearchIndexWordDAO(self._ctx, related_depth=2)
self._dbWord = WordDAO(self._ctx)
self._dbIndexParam = SearchIndexParamDAO(self._ctx, related_depth=3)
self._dbParam = ParamDAO(self._ctx)
def add_index(self, text, app_code, view_name=None, action_name=None, params={}):
"""Add data to search index
** Required Attributes **
* ``text``:str : Text to index
* ``app_code``:str : Application code
** Optional Attributes **
* ``view_name``:str : View name
* ``action_name``:str : Action name. Either view name or action name must be called.
* ``params``:dict : Parameters associated with the search entry.
** Returns**
None"""
wordList = resources.Index.parseText(text)
view = self._dbView.get(name=view_name) if view_name != None else None
action = self._dbAction.get(name=action_name) if action_name != None else None
app = self._dbApp.get(code=app_code)
# delete search index
try:
search = self._dbSearch.get(application=app, view=view) if view_name != '' else (None, None)
search = self._dbSearch.get(application=app, action=action) if action_name != '' else (None, None)
search.delete()
except SearchIndex.DoesNotExist:
pass
# Create search index
search = self._dbSearch.create(application=app, view=view, action=action, title=text)
for wordName in wordList:
# Word
word, created = self._dbWord.getCreate(word=wordName) #@UnusedVariable
# SearchIndexWord
searchWord = self._dbIndexWord.create(word=word, index=search) #@UnusedVariable
for paramName in params:
param = self._dbParam.getCreate(application=app, name=paramName)
indexParam = self._dbIndexParam.create(searchIndex=search, name=param, operator=Choices.OP_EQ, #@UnusedVariable
value=params[paramName])
def search(self, text):
"""Search for views and actions
** Attributes **
* ``text``:str : text to search
** Returns**
List of dictionaries with "id", "text", "image" and "extra" fields."""
# Search first 100 matches
# return best 15 matches with titile, link information and application icon
# return results in format needed by autocomplete plugin
wordList = resources.Index.parseText(text)
logger.debug( 'wordList: %s' % (wordList) )
#results = self._dbIndexWord.search(word__word__in=wordList)[:100]
# Build Q instance
# TODO: Get views / actions I have access and comply with states (logged in, etc...)
myQ = Q(word__word__startswith=wordList[0])
for word in wordList[1:]:
myQ = myQ | Q(word__word__startswith=word)
logger.debug( 'Q: %s' % (str(myQ)) )
results = self._dbIndexWord.search(myQ)[:100]
logger.debug( 'search :: results: %s' % (results) )
logger.debug( results.query )
container = {}
containerData = {}
apps = []
for data in results:
logger.debug( 'data: %s' % (data) )
if not container.has_key(data.index.pk):
container[data.index.pk] = 0
container[data.index.pk] += 1
containerData[data.index.pk] = data
apps.append(data.index.application)
logger.debug( 'conatiner: %s' % (container) )
logger.debug( 'containerData: %s' % (containerData) )
logger.debug('apps: {}'.format(apps))
tupleList = []
for pk in container:
tupleList.append((container[pk], containerData[pk]))
tupleList.sort()
tupleListFinal = tupleList[:15]
resultsFinal = []
for theTuple in tupleListFinal:
data = theTuple[1]
myDict = {}
extraDict = {}
myDict['id'] = data.index.id
myDict['text'] = data.index.title
# get full path for image version: static...
myDict['image'] = data.index.view.image.version_generate('thumbnail').url if data.index.view and data.index.view.image else ''
myDict['image'] = data.index.action.image.version_generate('thumbnail').url if data.index.action and data.index.action.image else myDict['image']
# app image
if myDict['image'] == '':
try:
image = data.index.application.applicationmedia_set.get(type__name=K.PARAM_ICON).image
myDict['image'] = image.version_generate('thumbnail').url
except:
pass
extraDict['view'] = data.index.view.name if data.index.view != None else ''
if data.index.view:
extraDict['winType'] = data.index.view.winType
extraDict['action'] = data.index.action.name if data.index.action != None else ''
params = data.index.params.all()
paramDict = {}
for param in params:
paramDict[param.name] = param.value
extraDict['params'] = paramDict
extraDict['app'] = data.index.application.name
myDict['extra'] = extraDict
resultsFinal.append(myDict)
return resultsFinal
class TemplateService ( object ):
"""
Template service with operations to resolve and obtain templates
"""
_ctx = None
__MODES = ['window','popup']
__app = ''
__mode = ''
__tmplName = ''
def __init__(self, ctx):
"""Menu building and operations"""
self._ctx = ctx
self._dbViewTmpl = ViewTmplDAO(self._ctx, related_depth=2)
self._dbTemplate = TemplateDAO(self._ctx)
def __findTemplPath(self, module):
"""
Find template searching on templates/ directory in application
**Attributes**
* ``module``:Object : Application module. For app='ximpia.xpsite', module would be same as from ximpia import site
* ``mode``:String : window or popup
**Returns**
* ``path``:String : Path to template
"""
#path = m.__file__.split('__init__')[0] + 'templates/' + mode + '/' + tmplName + '.html'
path = ''
pathMain = module.__file__.split('__init__')[0] + 'templates'
logger.debug('TemplateService.__findTemplPath :: pathMain: %s' % (pathMain) )
fileList = os.listdir(pathMain)
logger.debug('TemplateService.__findTemplPath :: fileList: %s' % (fileList) )
logger.debug('TemplateService.__findTemplPath :: tmplName: %s mode: %s' % (self.__tmplName, self.__mode) )
for item in fileList:
if item != 'site' and os.path.isdir(pathMain + '/' + item):
if item in self.__MODES:
fileList = os.listdir(pathMain + '/' + item)
for myFile in fileList:
if myFile == self.__tmplName + '.html':
path = pathMain + '/' + item + '/' + myFile
break
else:
if os.path.exists(pathMain + '/' + item + '/' + self.__mode):
fileList = os.listdir(pathMain + '/' + item + '/' + self.__mode)
for myFile in fileList:
if myFile == self.__tmplName + '.html':
path = pathMain + '/' + item + '/' + self.__mode + '/' + myFile
break
else:
raise XpMsgException(None, _('Template directory has no ' + ' or '.join(self.__MODES) + ' modes') )
if path != '':
break
if path == '':
raise XpMsgException(None, _('Could not get template file for application=%s, mode=%s, templName=%s' %\
(self.__app, self.__mode, self.__tmplName) ))
return path
def __discover_site_path(self, app):
project_name, app_name = app.split('.')
site_path = cache.get('app_' + app_name + '_site_path')
if not site_path:
appModulePath = settings.__file__.split('settings')[0]
file_list = os.listdir(appModulePath)
site_path = ''
for app in file_list:
try:
if os.path.isdir(appModulePath + app) and 'xpsite' in os.listdir(appModulePath + app + '/templates'):
site_path = appModulePath + app + '/templates/xpsite'
except OSError:
# templates directory not found
pass
cache.set('app_' + app_name + '_xpsite_path', site_path)
return site_path
def get_app(self, app):
"""
Get application template with styles, scripts and footer
** Attributes **
* ``app``:string : Application, like 'ximpia.xpsite'
** Returns **
* ``tmpl``:string
"""
self.__app = app
logger.debug('TemplateService.get_app :: app: %s' % app)
# go to project. Search in all apps for site templates, write path into cache
if settings.DEBUG == True:
package, module = get_app_path(app).split('.')
m = get_class(package + '.' + module)
if app == 'ximpia.xpsite':
#appModulePath = settings.__file__.split('settings')[0]
# would get this from cache
pathSite = self.__discover_site_path(app)
#pathSite = appModulePath + 'web/templates/site'
if os.path.exists(pathSite) and os.path.isdir(pathSite):
path = pathSite + '/' + app.split('.')[1] + '.html'
else:
path = m.__file__.split('__init__')[0] + 'templates/' + module + '/' + module + '.html'
logger.debug('path: {}'.format(path))
if os.path.isfile(path):
with open(path) as f:
tmpl = f.read()
cache.set('tmpl/' + app, tmpl)
else:
raise XpMsgException(None, _('application template is not found.'))
else:
tmpl = cache.get('tmpl/' + app)
if not tmpl:
package, module = app.split('.')
m = get_class(package + '.' + module)
path = m.__file__.split('__init__')[0] + 'templates/' + module + '/' + module + '.html'
if os.path.isfile(path):
with open(path) as f:
tmpl = f.read()
else:
raise XpMsgException(None, _('application template is not found.'))
return tmpl
def get(self, app, mode, tmpl_name):
"""
Get template
**Attributes**
* ``app``:String
* ``mode``:String
* ``tmplName``:String
**Returns**
* ``tmpl``:String
"""
self.__app, self.__mode, self.__tmplName = app, mode, tmpl_name
logger.debug('TemplateService.get :: app: %s tmpl_name: %s' % (app, tmpl_name))
if settings.DEBUG == True:
if app.find('.') != -1:
package, module = app.split('.')
else:
logger.debug('path: {}'.format(get_app_path(app)))
package, module = get_app_path(app).split('.')
m = get_class(package + '.' + module)
if app == 'ximpia.xpsite':
#appModulePath = settings.__file__.split('settings')[0]
pathSite = self.__discover_site_path(app)
if os.path.exists(pathSite) and os.path.isdir(pathSite):
path = pathSite + '/' + mode + '/' + tmpl_name + '.html'
else:
raise XpMsgException(None, _('site directory inside templates does not exist'))
else:
path = self.__findTemplPath(m)
logger.debug('TemplateService.get :: path: %s' % (path) )
with open(path) as f:
tmpl = f.read()
cache.set('tmpl/' + app + '/' + mode + '/' + tmpl_name, tmpl)
else:
tmpl = cache.get('tmpl/' + app + '/' + mode + '/' + tmpl_name)
if not tmpl:
package, module = app.split('.')
m = get_class(package + '.' + module)
if app == 'ximpia.xpsite':
#appModulePath = settings.__file__.split('settings')[0]
pathSite = self.__discover_site_path(app)
if os.path.exists(pathSite) and os.path.isdir(pathSite):
path = pathSite + '/' + mode + '/' + tmpl_name + '.html'
else:
raise XpMsgException(None, _('site directory inside templates does not exist'))
else:
path = self.__findTemplPath(m)
logger.debug('TemplateService.get :: path: %s' % (path) )
with open(path) as f:
tmpl = f.read()
cache.set('tmpl/' + app + '/' + mode + '/' + tmpl_name, tmpl)
return tmpl
def resolve(self, view_name):
"""Resolve template """
# Context: device, lang, country
#tmplName = ''
templates = {}
if self._ctx.lang != 'en' or self._ctx.country != '' or self._ctx.device != Choices.DEVICE_PC:
# TODO: Complete for language and device templates
"""tmplList = self._dbViewTmpl.search(view__name=viewName, template__language=self._ctx.lang)
if len(tmplList) > 1:
tmplName = tmplList.filter(template__winType=Choices.WIN_TYPE_WINDOW)[0].template.name
else:
if len(tmplList) != 0:
tmplName = tmplList[0].template.name
else:
pass"""
else:
tmplList = self._dbViewTmpl.search(view__name=view_name, template__language=self._ctx.lang)
logger.debug('TemplateService.resolve :: tmplList: {}'.format(tmplList))
for viewTmpl in tmplList:
tmpl = viewTmpl.template
# alias? name?
templates[tmpl.alias] = tmpl.name
"""if len(tmplList) > 1:
#tmplName = tmplList.filter(template__winType=Choices.WIN_TYPE_WINDOW)[0].template.name
tmpl = tmplList.filter(template__winType=Choices.WIN_TYPE_WINDOW)[0].template
templates[tmpl.alias] = tmpl.name
else:
if len(tmplList) != 0:
tmplName = tmplList[0].template.name
else:
pass"""
logger.debug( 'TemplateService.resolve :: templates: {}'.format(templates))
return templates
[docs]class CommonService( object ):
_ctx = None
_request = None
_errorDict = {}
_resultDict = {}
_form = None
_postDict = {}
_businessOK = False
_viewNameTarget = ''
_isFormOK = None
_views = {}
_actions = {}
_wf = None
_wfUserId = ''
request = None
def __init__(self, ctx):
self._ctx = ctx
self._ctx_min = copy.copy(self._ctx)
self._ctx_min.to_min()
if False: self._ctx = ctx()
self._resultDict = get_result_ERROR([])
self._postDict = ctx.post
self._errorDict = {}
self._resultDict = {}
self._isFormOK = None
self._wf = WorkFlowBusiness(self._ctx)
self._viewNameTarget = ''
self._wfUserId = ''
def get_request(self):
return self.__request
def set_request(self, value):
self.__request = value
def del_request(self):
del self.__request
def _build_JSON_result(self, result_dict):
"""Builds json result
@param resultDict: dict : Dictionary with json data
@return: result : HttpResponse"""
#logger.debug( 'Dumping...' )
sResult = json.dumps(result_dict)
#logger.debug( 'sResult : %s' % (sResult) )
result = HttpResponse(sResult)
return result
def _add_error_fields(self, id_error, form, error_field):
"""Add error
@param id_error: String : Id of error
@param form: Form
@param error_field: String : The field inside class form"""
if not self._errorDict.has_key(id_error):
self._errorDict[id_error] = {}
self._errorDict[id_error] = form.fields[error_field].initial
[docs] def _put_flow_params(self, **args):
"""Put parameters into workflow or navigation system.
@param args: Arguments to insert into persistence"""
self._wf.putParams(**args)
"""if self._ctx.isFlow:
self._wf.putParams(**args)
else:
dd = json.loads(self._ctx.form.base_fields['entryFields'].initial)
for name in args:
dd[name] = args[name]
self._ctx.form.base_fields['entryFields'].initial = json.dumps(dd)"""
def _add_attr(self, name, value):
"""
Add attribute to jsData response object
**Attributes**
* ``name``
* ``value``
** Returns **
"""
self._ctx.jsData.addAttr(name, value)
def _set_target_view(self, view_name):
"""Set the target view for navigation."""
self._viewNameTarget = view_name
self._ctx.viewNameTarget = view_name
def _show_view(self, view_name, view_attrs={}):
"""Show view.
@param view_name:
@param view_attrs:
@return: result"""
self._set_target_view(view_name)
db = ViewDAO(self._ctx)
viewTarget = db.get(name=view_name)
impl = viewTarget.implementation
implFields = impl.split('.')
method = implFields[len(implFields)-1]
classPath = ".".join(implFields[:-1])
cls = get_class( classPath )
objView = cls(self._ctx) #@UnusedVariable
if (len(view_attrs) == 0) :
result = eval('objView.' + method)()
else:
result = eval('objView.' + method)(**view_attrs)
return result
[docs] def _get_target_view(self):
"""Get target view."""
return self._viewNameTarget
[docs] def _get_flow_params(self, *name_list):
"""Get parameter for list given, either from workflow dictionary or parameter dictionary in view.
@param name_list: List of parameters to fetch"""
logger.debug( 'wfUserId: %s flowCode: %s' % (self._ctx.wfUserId, self._ctx.flowCode) )
valueDict = self._wf.getFlowDataDict(self._ctx.wfUserId, self._ctx.flowCode)['data']
logger.debug( 'valueDict: %s' % (valueDict) )
"""valueDict = {}
for name in nameList:
#value = self._wf.getParam(name)
value = self._wf.getParamFromCtx(name)
valueDict[name] = value"""
"""if self._ctx.isFlow:
logger.debug( 'flow!!!!' )
for name in nameList:
#value = self._wf.getParam(name)
value = self._wf.getParamFromCtx(name)
valueDict[name] = value
else:
logger.debug( 'navigation!!!' )
dd = json.loads(self._ctx.form.base_fields['entryFields'].initial)
for name in nameList:
if dd.has_key(name):
valueDict[name] = dd[name]"""
return valueDict
[docs] def _get_wf_user(self):
"""Get Workflow user."""
if self._ctx.cookies.has_key('XP_WFUID'):
self._ctx.wfUserId = self._ctx.cookies['XP_WFUID']
else:
self._ctx.wfUserId = self._wf.genUserId()
self._set_cookie('XP_WFUID', self._ctx.wfUserId)
self._wfUserId = self._ctx.wfUserId
return self._wfUserId
def _get_error_result_dict(self, error_dict, page_error=False):
"""Get sorted error list to show in pop-up window
@return: self._result_dict : ResultDict"""
#dict = self._errorDict
keyList = error_dict.keys()
keyList.sort()
myList = []
for key in keyList:
message = error_dict[key]
index = key.find('id_')
if page_error == False:
if index == -1:
myList.append(('id_' + key, message, False))
else:
myList.append((key, message, False))
else:
if index == -1:
myList.append(('id_' + key, message, True))
else:
myList.append((key, message, True))
self._result_dict = get_result_ERROR(myList)
return self._result_dict
def _get_setting(self, setting_name):
"""
Get setting model instance.
** Attributes **
* ``settingName``:String : Setting name
** Returns **
models.site.Setting model instance
"""
self._dbSetting = SettingDAO(self._ctx, related_depth=2)
setting = self._dbSetting.get(name__name=setting_name)
return setting
def _do_validations(self, validation_dict):
"""Do all validations defined in validation dictionary"""
bFormOK = self._ctx.form.is_valid()
if bFormOK:
keys = self.validationDict.keys()
for key in keys:
oVal = eval(key)(self._ctx)
for sFunc in self.validationDict[key]:
oVal.eval(sFunc)()
self._doErrors(oVal.getErrors())
"""if self.isBusinessOK() and bFormOK:
result = f(*argsTuple, **argsDict)
# check errors
return wrapped_f
else:
# Errors
result = self._build_JSON_result(self._getErrorResultDict())
return result"""
def _get_form(self):
"""Get form"""
#logger.debug( 'form: %s' % (self._ctx.form) )
return self._ctx.form
def _set_form(self, form_instance):
"""Sets the form instance"""
self._ctx.form = form_instance
self._isFormOK = self._ctx.form.is_valid()
def _get_main_form_id(self):
""""
Get main form id, like ``form_xxxx`` where xxxx is the returned value
"""
logger.debug('main formId: %s' % (self._ctx.form._XP_FORM_ID) )
return self._ctx.form._XP_FORM_ID
def _get_post_dict(self):
"""Get post dictionary. This will hold data even if form is not validated. If not validated cleaned_value will have no values"""
return self._postDict
def _is_business_ok(self):
"""Checks that no errors have been generated in the validation methods
@return: isOK : boolean"""
if len(self._errorDict) == 0:
self._businessOK = True
return self._businessOK
def _is_form_valid(self):
"""Is form valid?"""
if self._isFormOK == None:
self._isFormOK = self._ctx.form.is_valid()
return self._isFormOK
def _is_form_bs_ok(self):
"""Is form valid and business validations passed?"""
bDo = False
if len(self._errorDict.keys()) == 0:
self._isBusinessOK = True
if self._isFormOK == True and self._isBusinessOK == True:
bDo = True
return bDo
def _f(self):
"""Returns form from context"""
return self._ctx.form
def _add_error(self, field_name, err_msg):
"""Add error
"""
#form = self._getForm()
#logger.debug( 'form: %s' % (form) )
#msgDict = _jsf.decodeArray(form.fields['errorMessages'].initial)
idError = 'id_' + field_name
if not self._errorDict.has_key(idError):
self._errorDict[idError] = {}
self._errorDict[idError] = err_msg
logger.debug( '_errorDict : %s' % (self._errorDict) )
def _get_errors(self):
"""Get error dict
@return: errorDict : Dictionary"""
return self._errorDict
def _get_post(self):
"""Get post dictionary"""
return self._ctx.post
def _validate_exists(self, db_data_list):
"""Validates that db data provided exists. Error is shown in case does not exist.
Db data contains data instance, query arguments in a dictionary
and errorName for error message display at the front
@param dbDataList: [dbObj, queryArgs, fieldName, errMsg]"""
logger.debug( 'validateExists...' )
logger.debug( 'dbDataList : %s' % (db_data_list) )
for dbData in db_data_list:
dbObj, qArgs, fieldName, errMsg = dbData
exists = dbObj.check(**qArgs)
logger.debug( 'validate Exists Data: args: %s exists: %s fieldName: %s errMsg: %s' %
(qArgs, str(exists), str(fieldName), str(errMsg)) )
if not exists:
self._add_error(fieldName, errMsg)
def _validate_not_exists(self, db_data_list):
"""Validates that db data provided does not exist. Error is shown in case exists.
Db data contains data instance, query arguments in a dictionary
and errorName for error message display at the front
@param dbDataList: [dbObj, queryArgs, fieldName, errMsg]"""
logger.debug( 'validateNotExists...' )
logger.debug( 'dbDataList : %s' % (db_data_list) )
for dbData in db_data_list:
dbObj, qArgs, fieldName, errMsg = dbData
exists = dbObj.check(**qArgs)
logger.debug( 'Exists : %s' % (exists) )
if exists:
logger.debug( 'I add error: %s %s' % (fieldName, errMsg) )
self._add_error(fieldName, errMsg)
def _validate_context(self, ctx_data_list):
"""Validates context variable. [[name, value, fieldName, errName],...]"""
for ctxData in ctx_data_list:
name, value, fieldName, errMsg = ctxData
if self._ctx[name] != value:
self._add_error(fieldName, errMsg)
def _authenticate_user(self, ximpia_id, password, field_name, error_msg):
"""Authenticates user and password"""
q_args = {'username': ximpia_id, 'password': password}
user = authenticate(**q_args)
if user:
pass
else:
self._add_error(field_name, error_msg)
return user
def _authenticate_user_soc_net(self, social_id, social_token, auth_source, field_name, error_msg):
"""Authenticates user and password"""
q_args = {'socialId': social_id, 'socialToken': social_token}
logger.debug('_authenticateUsersocNet :: Arguments: %s' % (q_args) )
user = authenticate(**q_args)
if user:
pass
else:
self._add_error(field_name, error_msg)
return user
def _is_valid(self):
"""Checks if no errors have been written to error container.
If not, raises XpMsgException """
self._errorDict = self._get_errors()
logger.debug( '_isValid() :: errorDict : %s %s' % (self._errorDict, self._is_business_ok()) )
if not self._is_business_ok():
# Here throw the BusinessException
logger.debug( 'I raise error on business validation!!!!!!!!!!!!!!!!!!' )
raise XpMsgException(None, _('Error in validating business layer'))
def _set_ok_msg(self, idOK):
"""Sets the ok message id"""
msgDict = _jsf.decodeArray(self._ctx.form.fields['okMessages'].initial)
self._ctx.form.fields['msg_ok'].initial = msgDict[idOK]
logger.debug('ok message: %s' % (self._ctx.form.fields['msg_ok'].initial) )
def _set_cookie(self, key, value):
"""
Add key and value to context cookies data.
** Attributes **
* ``key``
* ``value``
** Returns **
None
"""
self._ctx.set_cookies.append({'key': key, 'value': value, 'domain': settings.SESSION_COOKIE_DOMAIN,
'expires': datetime.timedelta(days=365*5)+datetime.datetime.utcnow()})
def _set_main_form(self, form_instance):
"""Set form as main form: We set to context variable 'form' as add into form container 'forms'.
@param formInstance: Form instance"""
self._ctx.form = form_instance
self._ctx.forms[form_instance.get_form_id()] = form_instance
def _add_form(self, form_instance):
"""Set form as regular form. We add to form container 'forms'. Context variable form is not modified.
@param formInstance: Form instance"""
self._ctx.forms[form_instance.get_form_id()] = form_instance
def _put_form_value(self, field_name, field_value, form_id=None):
"""
Add form value to field already defined in the forms for the service
** Required Attributes **
* ``fieldName`` : field name as appears in form definition
* ``fieldValue`` : Field value
** Optional Attributes **
* ``formId`` : Id for the form ro modify field, like ``signup``. Default value None. In case None,
we get formId from self._getMainFormId()
** Returns **
None
"""
if form_id == None:
form_id = self._get_main_form_id()
self._ctx.forms[form_id].fields[field_name].initial = field_value
def _get_user_channel_name(self):
"""Get user social name"""
if self._ctx.cookies.has_key('userChannelName'):
userChannelName = self._ctx.cookies['userChannelName']
logger.debug( 'COOKIE :: userChannelName: %s' % (userChannelName) )
else:
userChannelName = K.USER
self._set_cookie('userChannelName', userChannelName)
return userChannelName
def _login(self):
"""Do login"""
login(self.request, self._ctx.user)
self._ctx.isLogin = True
def _logout(self):
"""Do logout"""
logout(self.request)
self._ctx.isLogin = False
def _add_list(self, name, values):
"""Add name to list_$name in the result JSON object
** Attributes **
* ``name``:str
* ``values``:list<dict>
** Returns **
"""
# TODO: Check option to have values() for queryset and include values() list of dicts in 'list_xxxx'
dictList = []
for entry in values:
dd = {}
keys = entry.keys()
for key in keys:
dd[key] = entry[key]
dictList.append(dd)
self._ctx.jsData.addAttr('list_' + name, dictList)
@service()
def save(self):
"""
Save data associated to form
"""
logger.debug('CommonService.save ...')
self._f().save()
@service()
def delete(self):
"""
Delete register associated with form
"""
logger.debug('CommonService.delete ...')
instances = {}
dbObjects = json.loads(self._ctx.post['dbObjects'].replace("'", '"'))
logger.debug('CommonService.delete :: dbObjects: %s' % (dbObjects) )
for key in dbObjects:
# Get instance model by pk
impl = dbObjects[key]['impl']
cls = get_class( impl )
instances[key] = cls.objects.using('default').get(pk=dbObjects[key]['pk'])
logger.debug('CommonService.delete :: instances: %s' % (instances) )
if len(instances) == 1:
instances[instances.keys()[0]].delete()
logger.debug('CommonService.delete :: deleted instance: %s pk: %s' % (instances.keys()[0], instances[instances.keys()[0]].pk) )
else:
# Get instances to delete from button parameters
# TODO: Include support for deleting more than one instance for forms with multiple instances associated
pass
def _get_list_pk_values(self, field_name):
pks = [int(x) for x in self._ctx.request.getlist(field_name)]
return pks
request = property(get_request, set_request, del_request, "service request object")
def _instances(self, *args):
"""
Builds instances list from list of classes. Inyects context.
** Attributes **
* ``*args``: List of class names or path to class names.
** Returns **
List of business, data instances with context inyected
"""
instances = get_instances(args, self._ctx_min)
return instances
class DefaultService ( CommonService ):
def __init__(self, ctx):
super(DefaultService, self).__init__(ctx)
@service(form=DefaultForm)
def show(self):
"""Method to execute for view with no business code, only showing a html template."""
pass