def __get__(self, inst, cls): from ..model import Model if inst is None: return self with Transaction().set_context(getattr(inst, '_context', {})): selection = cls.fields_get([self.name])[self.name]['selection'] if not isinstance(selection, (tuple, list)): sel_func = getattr(cls, selection) if not is_instance_method(cls, selection): selection = sel_func() else: selection = sel_func(inst) selection = dict(selection) value = getattr(inst, self.name) # None and '' are equivalent if value is None or value == '': if value not in selection: switch_value = {None: '', '': None}[value] if switch_value in selection: value = switch_value # Use Model __name__ for Reference field elif isinstance(value, Model): value = value.__name__ if isinstance(value, (list, tuple)): values = [] for item in value: values.append(selection.get(item, item)) return values else: return selection.get(value, value)
def get(self, ids, Model, name, values=None): ''' Call the getter. If the function has ``names`` in the function definition then it will call it with a list of name. ''' with Transaction().set_context(_check_access=False): method = getattr(Model, self.getter) instance_method = is_instance_method(Model, self.getter) def call(name): records = Model.browse(ids) if not instance_method: return method(records, name) else: return dict((r.id, method(r, name)) for r in records) if isinstance(name, list): names = name # Test is the function works with a list of names if 'names' in inspect.getargspec(method)[0]: return call(names) return dict((name, call(name)) for name in names) else: # Test is the function works with a list of names if 'names' in inspect.getargspec(method)[0]: name = [name] return call(name)
def test_selection_fields(self): 'Test selection values' for mname, model in Pool().iterobject(): if not isregisteredby(model, self.module): continue for field_name, field in model._fields.items(): selection = getattr(field, 'selection', None) if selection is None: continue selection_values = field.selection if not isinstance(selection_values, (tuple, list)): sel_func = getattr(model, field.selection) if not is_instance_method(model, field.selection): selection_values = sel_func() else: record = model() selection_values = sel_func(record) self.assertTrue( all(len(v) == 2 for v in selection_values), msg='Invalid selection values "%(values)s" on field ' '"%(field)s" of model "%(model)s"' % { 'values': selection_values, 'field': field_name, 'model': model.__name__, })
def _dispatch(request, pool, *args, **kwargs): DatabaseOperationalError = backend.get('DatabaseOperationalError') obj, method = get_object_method(request, pool) if method in obj.__rpc__: rpc = obj.__rpc__[method] else: raise UserError('Calling method %s on %s is not allowed' % (method, obj)) log_message = '%s.%s(*%s, **%s) from %s@%s/%s' log_args = (obj, method, args, kwargs, request.authorization.username, request.remote_addr, request.path) logger.info(log_message, *log_args) user = request.user_id for count in range(config.getint('database', 'retry'), -1, -1): with Transaction().start(pool.database_name, user, readonly=rpc.readonly) as transaction: Cache.clean(pool.database_name) try: c_args, c_kwargs, transaction.context, transaction.timestamp \ = rpc.convert(obj, *args, **kwargs) meth = getattr(obj, method) if (rpc.instantiate is None or not is_instance_method(obj, method)): result = rpc.result(meth(*c_args, **c_kwargs)) else: assert rpc.instantiate == 0 inst = c_args.pop(0) if hasattr(inst, method): result = rpc.result(meth(inst, *c_args, **c_kwargs)) else: result = [rpc.result(meth(i, *c_args, **c_kwargs)) for i in inst] except DatabaseOperationalError: if count and not rpc.readonly: transaction.rollback() continue logger.error(log_message, *log_args, exc_info=True) raise except (ConcurrencyException, UserError, UserWarning): logger.debug(log_message, *log_args, exc_info=True) raise except Exception: logger.error(log_message, *log_args, exc_info=True) raise # Need to commit to unlock SQLite database transaction.commit() Cache.resets(pool.database_name) if request.authorization.type == 'session': try: with Transaction().start(pool.database_name, 0) as transaction: Session = pool.get('ir.session') Session.reset(request.authorization.get('session')) except DatabaseOperationalError: logger.debug('Reset session failed', exc_info=True) logger.debug('Result: %s', result) return result
def __post_setup__(cls): super(ModelView, cls).__post_setup__() # Update __rpc__ for field_name, field in cls._fields.iteritems(): field.set_rpc(cls) for button in cls._buttons: if not is_instance_method(cls, button): cls.__rpc__.setdefault(button, RPC(readonly=False, instantiate=0)) else: cls.__rpc__.setdefault( button, RPC(instantiate=0, result=on_change_result)) # Update depend on methods for (field_name, attribute), others in (cls.__depend_methods.iteritems()): field = getattr(cls, field_name) for other in others: other_field = getattr(cls, other) setattr( field, attribute, getattr(field, attribute) | getattr(other_field, attribute))
def get(self, ids, Model, name, values=None): ''' Call the getter. If the function has ``names`` in the function definition then it will call it with a list of name. ''' with Transaction().set_context(_check_access=False): method = getattr(Model, self.getter) instance_method = is_instance_method(Model, self.getter) signature = inspect.signature(method) uses_names = 'names' in signature.parameters def call(name): records = Model.browse(ids) if not instance_method: return method(records, name) else: return dict((r.id, method(r, name)) for r in records) if isinstance(name, list): names = name if uses_names: return call(names) return dict((name, call(name)) for name in names) else: if uses_names: name = [name] return call(name)
def __post_setup__(cls): super(ModelView, cls).__post_setup__() # Update __rpc__ for field_name, field in cls._fields.iteritems(): field.set_rpc(cls) for button in cls._buttons: if not is_instance_method(cls, button): cls.__rpc__.setdefault(button, RPC(readonly=False, instantiate=0)) else: cls.__rpc__.setdefault( button, RPC(instantiate=0, result=on_change_result)) # Update depend on methods for (field_name, attribute), others in (cls.__depend_methods.iteritems()): field = getattr(cls, field_name) for other in others: other_field = getattr(cls, other) setattr( field, attribute, getattr(field, attribute) | getattr(other_field, attribute)) # JMO : work around BUG#8723 func = getattr(cls, attribute + '_' + field_name, None) if func: if not hasattr(func, 'depends'): setattr(func, 'depends', set()) deps = getattr(func, 'depends') deps |= getattr(other_field, attribute, set())
def __post_setup__(cls): super(ModelView, cls).__post_setup__() # Update __rpc__ for field_name, field in cls._fields.items(): field.set_rpc(cls) for button in cls._buttons: if not is_instance_method(cls, button): cls.__rpc__.setdefault(button, RPC(readonly=False, instantiate=0)) else: cls.__rpc__.setdefault(button, RPC(instantiate=0, result=on_change_result)) for parent_cls in cls.__mro__: parent_meth = getattr(parent_cls, button, None) if not parent_meth: continue cls.__change_buttons[button] |= getattr( parent_meth, 'change', set()) for method_name, rpc in cls.__rpc__.items(): if not rpc.cache: continue cache_name = 'rpc.%s.%s' % (cls.__name__, method_name) cache_duration = config.getint('cache', cache_name, default=None) if cache_duration is not None: rpc.cache.duration = datetime.timedelta(seconds=cache_duration)
def test_workflow_transitions(self): 'Test all workflow transitions exist' with Transaction().start(DB_NAME, USER, context=CONTEXT): for mname, model in Pool().iterobject(): # Don't test model not registered by the module if not any(issubclass(model, cls) for cls in Pool().classes['model'].get(self.module, [])): continue if not issubclass(model, Workflow): continue field = getattr(model, model._transition_state) if isinstance(field.selection, (tuple, list)): values = field.selection else: # instance method may not return all the possible values if is_instance_method(model, field.selection): continue values = getattr(model, field.selection)() states = set(dict(values)) transition_states = set(chain(*model._transitions)) assert transition_states <= states, ( ('Unknown transition states "%(states)s" ' 'in model "%(model)s". ') % { 'states': list(transition_states - states), 'model': model.__name__, })
def test_workflow_transitions(self): 'Test all workflow transitions exist' for mname, model in Pool().iterobject(): if not isregisteredby(model, self.module): continue if not issubclass(model, Workflow): continue field = getattr(model, model._transition_state) if isinstance(field.selection, (tuple, list)): values = field.selection else: # instance method may not return all the possible values if is_instance_method(model, field.selection): continue values = getattr(model, field.selection)() states = set(dict(values)) transition_states = set(chain(*model._transitions)) self.assertLessEqual( transition_states, states, msg='Unknown transition states "%(states)s" ' 'in model "%(model)s". ' % { 'states': list(transition_states - states), 'model': model.__name__, })
def convert_order(self, name, tables, Model): if getattr(Model, 'order_%s' % name, None): return super(Selection, self).convert_order(name, tables, Model) assert name == self.name table, _ = tables[None] selections = Model.fields_get([name])[name]['selection'] if not isinstance(selections, (tuple, list)): if not is_instance_method(Model, selections): selections = getattr(Model, selections)() else: selections = [] column = self.sql_column(table) if not self.sort: else_ = len(selections) + 1 selections = ((k, i) for i, (k, v) in enumerate(selections)) else: else_ = column whens = [] for key, value in selections: whens.append((column == key, value)) if whens: return [Case(*whens, else_=else_)] else: return [column]
def get_selection(cls, model, name, inst): selection = model.fields_get([name])[name]['selection'] if not isinstance(selection, (tuple, list)): sel_func = getattr(model, selection) if not is_instance_method(model, selection): selection = sel_func() else: selection = sel_func(inst) return dict(selection)
def test_is_instance_method(self): 'Test is_instance_method' class Foo(object): @staticmethod def static(): pass @classmethod def klass(cls): pass def instance(self): pass self.assertFalse(is_instance_method(Foo, 'static')) self.assertFalse(is_instance_method(Foo, 'klass')) self.assertTrue(is_instance_method(Foo, 'instance'))
def __post_setup__(cls): super(ModelView, cls).__post_setup__() # Update __rpc__ for field_name, field in cls._fields.items(): field.set_rpc(cls) for button in cls._buttons: if not is_instance_method(cls, button): cls.__rpc__.setdefault(button, RPC(readonly=False, instantiate=0)) else: cls.__rpc__.setdefault( button, RPC(instantiate=0, result=on_change_result))
def __post_setup__(cls): super(ModelView, cls).__post_setup__() # Update __rpc__ for field_name, field in cls._fields.iteritems(): if (isinstance(field, (fields.Selection, fields.Reference)) or (isinstance(field, fields.Function) and isinstance(field._field, (fields.Selection, fields.Reference)))) \ and not isinstance(field.selection, (list, tuple)) \ and field.selection not in cls.__rpc__: instantiate = 0 if field.selection_change_with else None cls.__rpc__.setdefault(field.selection, RPC(instantiate=instantiate)) for attribute in ('on_change', 'on_change_with', 'autocomplete'): function_name = '%s_%s' % (attribute, field_name) if getattr(cls, function_name, None): result = None if attribute == 'on_change': result = on_change_result cls.__rpc__.setdefault(function_name, RPC(instantiate=0, result=result)) for button in cls._buttons: if not is_instance_method(cls, button): cls.__rpc__.setdefault(button, RPC(readonly=False, instantiate=0)) else: cls.__rpc__.setdefault(button, RPC(instantiate=0, result=on_change_result)) # Update depend on methods for (field_name, attribute), others in ( cls.__depend_methods.iteritems()): field = getattr(cls, field_name) for other in others: other_field = getattr(cls, other) setattr(field, attribute, getattr(field, attribute) | getattr(other_field, attribute))
def __post_setup__(cls): super(ModelView, cls).__post_setup__() # Update __rpc__ for field_name, field in cls._fields.items(): field.set_rpc(cls) for button in cls._buttons: if not is_instance_method(cls, button): cls.__rpc__.setdefault(button, RPC(readonly=False, instantiate=0)) else: cls.__rpc__.setdefault( button, RPC(instantiate=0, result=on_change_result)) for parent_cls in cls.__mro__: parent_meth = getattr(parent_cls, button, None) if not parent_meth: continue cls.__change_buttons[button] |= getattr( parent_meth, 'change', set())
def __post_setup__(cls): super(ModelView, cls).__post_setup__() # Update __rpc__ for field_name, field in cls._fields.iteritems(): if isinstance(field, (fields.Selection, fields.Reference)) \ and not isinstance(field.selection, (list, tuple)) \ and field.selection not in cls.__rpc__: instantiate = 0 if field.selection_change_with else None cls.__rpc__.setdefault(field.selection, RPC(instantiate=instantiate)) for attribute in ('on_change', 'on_change_with', 'autocomplete'): function_name = '%s_%s' % (attribute, field_name) if getattr(cls, function_name, None): result = None if attribute == 'on_change': result = on_change_result cls.__rpc__.setdefault(function_name, RPC(instantiate=0, result=result)) for button in cls._buttons: if not is_instance_method(cls, button): cls.__rpc__.setdefault(button, RPC(readonly=False, instantiate=0)) else: cls.__rpc__.setdefault(button, RPC(instantiate=0, result=on_change_result)) # Update depend on methods for (field_name, attribute), others in ( cls.__depend_methods.iteritems()): field = getattr(cls, field_name) for other in others: other_field = getattr(cls, other) setattr(field, attribute, getattr(field, attribute) | getattr(other_field, attribute))
def test_workflow_transitions(self): 'Test all workflow transitions exist' for mname, model in Pool().iterobject(): if not isregisteredby(model, self.module): continue if not issubclass(model, Workflow): continue field = getattr(model, model._transition_state) if isinstance(field.selection, (tuple, list)): values = field.selection else: # instance method may not return all the possible values if is_instance_method(model, field.selection): continue values = getattr(model, field.selection)() states = set(dict(values)) transition_states = set(chain(*model._transitions)) assert transition_states <= states, ( ('Unknown transition states "%(states)s" ' 'in model "%(model)s". ') % { 'states': list(transition_states - states), 'model': model.__name__, })
def get(self, ids, Model, name, values=None): ''' Call the getter. If the function has ``names`` in the function definition then it will call it with a list of name. ''' with Transaction().set_context(_check_access=False): method = getattr(Model, self.getter) instance_method = is_instance_method(Model, self.getter) multiple = self.getter_multiple(method) records = Model.browse(ids) for record, value in zip(records, values): assert record.id == value['id'] for fname, val in value.items(): field = Model._fields.get(fname) if field and field._type not in { 'many2one', 'reference', 'one2many', 'many2many', 'one2one' }: record._local_cache[record.id][fname] = val def call(name): if not instance_method: return method(records, name) else: return dict((r.id, method(r, name)) for r in records) if isinstance(name, list): names = name if multiple: return call(names) return dict((name, call(name)) for name in names) else: if multiple: name = [name] return call(name)
def __call__(self, *args, **kwargs): from trytond.rpc import RPC from trytond.tools import is_instance_method from trytond.transaction import Transaction from trytond.worker import run_task if self._name in self._object.__rpc__: rpc = self._object.__rpc__[self._name] elif self._name in getattr(self._object, '_buttons', {}): rpc = RPC(readonly=False, instantiate=0) else: raise TypeError('%s is not callable' % self._name) with Transaction().start(self._config.database_name, self._config.user, readonly=rpc.readonly) as transaction: args, kwargs, transaction.context, transaction.timestamp = \ rpc.convert(self._object, *args, **kwargs) meth = getattr(self._object, self._name) if (rpc.instantiate is None or not is_instance_method(self._object, self._name)): result = rpc.result(meth(*args, **kwargs)) else: assert rpc.instantiate == 0 inst = args.pop(0) if hasattr(inst, self._name): result = rpc.result(meth(inst, *args, **kwargs)) else: result = [ rpc.result(meth(i, *args, **kwargs)) for i in inst ] transaction.commit() while transaction.tasks: task_id = transaction.tasks.pop() run_task(self._config.database_name, task_id) return result
def _dispatch(request, pool, *args, **kwargs): # AKE: perf analyzer hooks try: PerfLog().on_enter() except Exception: perf_logger.exception('on_enter failed') DatabaseOperationalError = backend.get('DatabaseOperationalError') obj, method = get_object_method(request, pool) if method in obj.__rpc__: rpc = obj.__rpc__[method] else: raise UserError('Calling method %s on %s is not allowed' % (method, obj)) log_message = '%s.%s(*%s, **%s) from %s@%s/%s' username = request.authorization.username if isinstance(username, bytes): username = username.decode('utf-8') log_args = (obj, method, args, kwargs, username, request.remote_addr, request.path) logger.info(log_message, *log_args) # JCA: log slow RPC if slow_threshold >= 0: slow_msg = '%s.%s (%s s)' slow_args = (obj, method) slow_start = time.time() user = request.user_id # AKE: add session to transaction context if request.authorization.type == 'session': session = request.authorization.get('session') party = None elif request.authorization.type == 'token': session = request.authorization.get('token') party = request.authorization.get('party_id') # AKE: perf analyzer hooks try: PerfLog().on_execute(user, session, request.rpc_method, args, kwargs) except Exception: perf_logger.exception('on_execute failed') for count in range(config.getint('database', 'retry'), -1, -1): # AKE: add session to transaction context with Transaction().start(pool.database_name, user, readonly=rpc.readonly, context={ 'session': session, 'party': party }) as transaction: try: c_args, c_kwargs, transaction.context, transaction.timestamp \ = rpc.convert(obj, *args, **kwargs) meth = getattr(obj, method) # AKE: perf analyzer hooks try: wrapped_meth = profile(meth) except Exception: perf_logger.exception('profile failed') else: meth = wrapped_meth if (rpc.instantiate is None or not is_instance_method(obj, method)): result = rpc.result(meth(*c_args, **c_kwargs)) else: assert rpc.instantiate == 0 inst = c_args.pop(0) if hasattr(inst, method): result = rpc.result(meth(inst, *c_args, **c_kwargs)) else: result = [ rpc.result(meth(i, *c_args, **c_kwargs)) for i in inst ] except DatabaseOperationalError: if count and not rpc.readonly: transaction.rollback() continue logger.error(log_message, *log_args, exc_info=True) # JCA: log slow RPC if slow_threshold >= 0: slow_args += (str(time.time() - slow_start), ) log_exception(slow_logger.error, slow_msg, *slow_args) raise except (ConcurrencyException, UserError, UserWarning, LoginException): logger.debug(log_message, *log_args, exc_info=True) # JCA: log slow RPC if slow_threshold >= 0: slow_args += (str(time.time() - slow_start), ) log_exception(slow_logger.debug, slow_msg, *slow_args) raise except Exception: logger.error(log_message, *log_args, exc_info=True) # JCA: log slow RPC if slow_threshold >= 0: slow_args += (str(time.time() - slow_start), ) log_exception(slow_logger.error, slow_msg, *slow_args) raise # Need to commit to unlock SQLite database transaction.commit() if request.authorization.type == 'session': # AKE: moved all session ops to security script security.reset(pool.database_name, user, request.authorization.get('session')) logger.debug('Result: %s', result) # JCA: log slow RPC if slow_threshold >= 0: slow_diff = time.time() - slow_start slow_args += (str(slow_diff), ) if slow_diff > slow_threshold: slow_logger.info(slow_msg, *slow_args) else: slow_logger.debug(slow_msg, *slow_args) # AKE: perf analyzer hooks try: PerfLog().on_leave(result) except Exception: perf_logger.exception('on_leave failed') return result
def __view_look_dom(cls, element, type, fields_width=None, fields_attrs=None): pool = Pool() Translation = pool.get('ir.translation') ModelData = pool.get('ir.model.data') ModelAccess = pool.get('ir.model.access') Button = pool.get('ir.model.button') User = pool.get('res.user') if fields_width is None: fields_width = {} if not fields_attrs: fields_attrs = {} else: fields_attrs = copy.deepcopy(fields_attrs) def set_view_ids(element): view_ids = [] if element.get('view_ids'): for view_id in element.get('view_ids').split(','): try: view_ids.append(int(view_id)) except ValueError: view_ids.append(ModelData.get_id(*view_id.split('.'))) element.attrib['view_ids'] = ','.join(map(str, view_ids)) return view_ids def get_relation(field): if hasattr(field, 'model_name'): return field.model_name elif hasattr(field, 'get_target'): return field.get_target().__name__ def get_views(relation, view_ids, mode): Relation = pool.get(relation) views = {} if field._type in ['one2many', 'many2many']: # Prefetch only the first view to prevent infinite loop if view_ids: for view_id in view_ids: view = Relation.fields_view_get(view_id=view_id) views[str(view_id)] = view break else: for view_type in mode: views[view_type] = (Relation.fields_view_get( view_type=view_type)) break return views for attr in ('name', 'icon'): if not element.get(attr): continue fields_attrs.setdefault(element.get(attr), {}) if element.tag == 'field' and type in ['tree', 'form']: for attr in ('name', 'icon'): fname = element.get(attr) if not fname: continue view_ids = set_view_ids(element) if type != 'form': continue field = cls._fields[fname] relation = get_relation(field) if not relation: continue mode = (element.attrib.pop('mode', None) or 'tree,form').split(',') views = get_views(relation, view_ids, mode) element.attrib['mode'] = ','.join(mode) fields_attrs[fname].setdefault('views', {}).update(views) if type == 'tree' and element.get('name') in fields_width: element.set('width', str(fields_width[element.get('name')])) encoder = PYSONEncoder() if element.tag == 'button': button_name = element.attrib['name'] if button_name in cls._buttons: states = cls._buttons[button_name] else: states = {} groups = set(User.get_groups()) button_groups = Button.get_groups(cls.__name__, button_name) if ((button_groups and not groups & button_groups) or (not button_groups and not ModelAccess.check( cls.__name__, 'write', raise_exception=False))): states = states.copy() states['readonly'] = True element.set('states', encoder.encode(states)) button_rules = Button.get_rules(cls.__name__, button_name) if button_rules: element.set('rule', '1') change = cls.__change_buttons[button_name] if change: element.set('change', encoder.encode(list(change))) if not is_instance_method(cls, button_name): element.set('type', 'class') else: element.set('type', 'instance') # translate view if Transaction().language != 'en': for attr in ('string', 'sum', 'confirm', 'help'): if element.get(attr): trans = Translation.get_source(cls.__name__, 'view', Transaction().language, element.get(attr)) if trans: element.set(attr, trans) if element.tag == 'tree' and element.get('sequence'): fields_attrs.setdefault(element.get('sequence'), {}) if element.tag == 'calendar': for attr in ['dtstart', 'dtend', 'color', 'background_color']: if element.get(attr): fields_attrs.setdefault(element.get(attr), {}) for field in element: fields_attrs = cls.__view_look_dom(field, type, fields_width=fields_width, fields_attrs=fields_attrs) return fields_attrs
def dispatch(host, port, protocol, database_name, user, session, object_type, object_name, method, *args, **kwargs): Database = backend.get('Database') DatabaseOperationalError = backend.get('DatabaseOperationalError') if object_type == 'common': if method == 'login': try: database = Database(database_name).connect() cursor = database.cursor() cursor.close() except Exception: return False res = security.login(database_name, user, session) with Transaction().start(database_name, 0): Cache.clean(database_name) Cache.resets(database_name) msg = res and 'successful login' or 'bad login or password' logger.info('%s \'%s\' from %s:%d using %s on database \'%s\'', msg, user, host, port, protocol, database_name) return res or False elif method == 'logout': name = security.logout(database_name, user, session) logger.info('logout \'%s\' from %s:%d ' 'using %s on database \'%s\'', name, host, port, protocol, database_name) return True elif method == 'version': return __version__ elif method == 'list_lang': return [ ('bg_BG', 'Български'), ('ca_ES', 'Català'), ('cs_CZ', 'Čeština'), ('de_DE', 'Deutsch'), ('en_US', 'English'), ('es_AR', 'Español (Argentina)'), ('es_EC', 'Español (Ecuador)'), ('es_ES', 'Español (España)'), ('es_CO', 'Español (Colombia)'), ('es_MX', 'Español (México)'), ('fr_FR', 'Français'), ('hu_HU', 'Magyar'), ('it_IT', 'Italiano'), ('lt_LT', 'Lietuvių'), ('nl_NL', 'Nederlands'), ('pt_BR', 'Português (Brasil)'), ('ru_RU', 'Russian'), ('sl_SI', 'Slovenščina'), ] elif method == 'db_exist': try: database = Database(*args, **kwargs).connect() cursor = database.cursor() cursor.close(close=True) return True except Exception: return False elif method == 'list': if not config.getboolean('database', 'list'): raise Exception('AccessDenied') with Transaction().start(None, 0, close=True) as transaction: return transaction.database.list(transaction.cursor) elif method == 'create': return create(*args, **kwargs) elif method == 'restore': return restore(*args, **kwargs) elif method == 'drop': return drop(*args, **kwargs) elif method == 'dump': return dump(*args, **kwargs) return elif object_type == 'system': database = Database(database_name).connect() database_list = Pool.database_list() pool = Pool(database_name) if database_name not in database_list: pool.init() if method == 'listMethods': res = [] for type in ('model', 'wizard', 'report'): for object_name, obj in pool.iterobject(type=type): for method in obj.__rpc__: res.append(type + '.' + object_name + '.' + method) return res elif method == 'methodSignature': return 'signatures not supported' elif method == 'methodHelp': res = [] args_list = args[0].split('.') object_type = args_list[0] object_name = '.'.join(args_list[1:-1]) method = args_list[-1] obj = pool.get(object_name, type=object_type) return pydoc.getdoc(getattr(obj, method)) for count in range(config.getint('database', 'retry'), -1, -1): try: user = security.check(database_name, user, session) except DatabaseOperationalError: if count: continue raise break database_list = Pool.database_list() pool = Pool(database_name) if database_name not in database_list: with Transaction().start(database_name, user, readonly=True) as transaction: pool.init() obj = pool.get(object_name, type=object_type) if method in obj.__rpc__: rpc = obj.__rpc__[method] else: raise UserError('Calling method %s on %s %s is not allowed!' % (method, object_type, object_name)) log_message = '%s.%s.%s(*%s, **%s) from %s@%s:%d/%s' log_args = (object_type, object_name, method, args, kwargs, user, host, port, database_name) logger.info(log_message, *log_args) for count in range(config.getint('database', 'retry'), -1, -1): with Transaction().start(database_name, user, readonly=rpc.readonly) as transaction: Cache.clean(database_name) try: c_args, c_kwargs, transaction.context, transaction.timestamp \ = rpc.convert(obj, *args, **kwargs) meth = getattr(obj, method) if (rpc.instantiate is None or not is_instance_method(obj, method)): result = rpc.result(meth(*c_args, **c_kwargs)) else: assert rpc.instantiate == 0 inst = c_args.pop(0) if hasattr(inst, method): result = rpc.result(meth(inst, *c_args, **c_kwargs)) else: result = [rpc.result(meth(i, *c_args, **c_kwargs)) for i in inst] if not rpc.readonly: transaction.cursor.commit() except DatabaseOperationalError: transaction.cursor.rollback() if count and not rpc.readonly: continue raise except (NotLogged, ConcurrencyException, UserError, UserWarning): logger.debug(log_message, *log_args, exc_info=True) transaction.cursor.rollback() raise except Exception: logger.error(log_message, *log_args, exc_info=True) transaction.cursor.rollback() raise Cache.resets(database_name) with Transaction().start(database_name, 0) as transaction: pool = Pool(database_name) Session = pool.get('ir.session') try: Session.reset(session) except DatabaseOperationalError: logger.debug('Reset session failed', exc_info=True) # Silently fail when reseting session transaction.cursor.rollback() else: transaction.cursor.commit() logger.debug('Result: %s', result) return result
def _dispatch(request, pool, *args, **kwargs): # AKE: perf analyzer hooks try: PerfLog().on_enter() except Exception: perf_logger.exception('on_enter failed') obj, method = get_object_method(request, pool) if method in obj.__rpc__: rpc = obj.__rpc__[method] else: abort(HTTPStatus.FORBIDDEN) user = request.user_id session = None if request.authorization.type == 'session': session = request.authorization.get('session') if rpc.fresh_session and session: context = {'_request': request.context} if not security.check_timeout( pool.database_name, user, session, context=context): abort(http.client.UNAUTHORIZED) log_message = '%s.%s(*%s, **%s) from %s@%s%s' username = request.authorization.username if isinstance(username, bytes): username = username.decode('utf-8') log_args = (obj, method, args, kwargs, username, request.remote_addr, request.path) logger.debug(log_message, *log_args) # JCA: log slow RPC if slow_threshold >= 0: slow_msg = '%s.%s (%s s)' slow_args = (obj, method) slow_start = time.time() # JCA: Format parameters if format_json_parameters and logger.isEnabledFor(logging.DEBUG): try: for line in json.dumps(args, indent=2, sort_keys=True, cls=DEBUGEncoder).split('\n'): logger.debug('Parameters: %s' % line) except Exception: logger.debug('Could not format parameters in log', exc_info=True) user = request.user_id # AKE: add session and token to transaction context token = None if request.authorization.type == 'token': token = { 'key': request.authorization.get('token'), 'user': user, 'party': request.authorization.get('party_id'), } # AKE: perf analyzer hooks try: PerfLog().on_execute(user, session, request.rpc_method, args, kwargs) except Exception: perf_logger.exception('on_execute failed') retry = config.getint('database', 'retry') for count in range(retry, -1, -1): if count != retry: time.sleep(0.02 * (retry - count)) with Transaction().start(pool.database_name, user, readonly=rpc.readonly) as transaction: try: c_args, c_kwargs, transaction.context, transaction.timestamp \ = rpc.convert(obj, *args, **kwargs) # AKE: add session to transaction context transaction.context.update({ 'session': session, 'token': token, }) transaction.context['_request'] = request.context meth = getattr(obj, method) # AKE: perf analyzer hooks try: wrapped_meth = profile(meth) except Exception: perf_logger.exception('profile failed') else: meth = wrapped_meth if (rpc.instantiate is None or not is_instance_method(obj, method)): result = rpc.result(meth(*c_args, **c_kwargs)) else: assert rpc.instantiate == 0 inst = c_args.pop(0) if hasattr(inst, method): result = rpc.result(meth(inst, *c_args, **c_kwargs)) else: result = [ rpc.result(meth(i, *c_args, **c_kwargs)) for i in inst ] except backend.DatabaseOperationalError: if count and not rpc.readonly: transaction.rollback() continue logger.error(log_message, *log_args, exc_info=True) # JCA: log slow RPC if slow_threshold >= 0: slow_args += (str(time.time() - slow_start), ) log_exception(slow_logger.error, slow_msg, *slow_args) raise except (ConcurrencyException, UserError, UserWarning, LoginException): logger.debug(log_message, *log_args, exc_info=True) # JCA: log slow RPC if slow_threshold >= 0: slow_args += (str(time.time() - slow_start), ) log_exception(slow_logger.debug, slow_msg, *slow_args) raise except Exception: logger.error(log_message, *log_args, exc_info=True) # JCA: log slow RPC if slow_threshold >= 0: slow_args += (str(time.time() - slow_start), ) log_exception(slow_logger.error, slow_msg, *slow_args) raise # Need to commit to unlock SQLite database transaction.commit() while transaction.tasks: task_id = transaction.tasks.pop() run_task(pool, task_id) if session: context = {'_request': request.context} security.reset(pool.database_name, session, context=context) # JCA: Allow to format json result if format_json_result and logger.isEnabledFor(logging.DEBUG): try: for line in json.dumps(result, indent=2, sort_keys=True, cls=DEBUGEncoder).split('\n'): logger.debug('Result: %s' % line) except Exception: logger.debug('Could not format parameters in log', exc_info=True) else: logger.debug('Result: %s', result) # JCA: log slow RPC if slow_threshold >= 0: slow_diff = time.time() - slow_start slow_args += (str(slow_diff), ) if slow_diff > slow_threshold: slow_logger.info(slow_msg, *slow_args) else: slow_logger.debug(slow_msg, *slow_args) # AKE: perf analyzer hooks try: PerfLog().on_leave(result) except Exception: perf_logger.exception('on_leave failed') response = app.make_response(request, result) if rpc.readonly and rpc.cache: response.headers.extend(rpc.cache.headers()) return response
def __post_setup__(cls): super(ModelView, cls).__post_setup__() methods = { '_done': set(), 'depends': collections.defaultdict(set), 'depend_methods': collections.defaultdict(set), 'change': collections.defaultdict(set), } cls.__change_buttons = methods['change'] def set_methods(name): if name in methods['_done']: return methods['_done'].add(name) for parent_cls in cls.__mro__: parent_meth = getattr(parent_cls, name, None) if not parent_meth: continue for attr in ['depends', 'depend_methods', 'change']: if isinstance(parent_meth, property): parent_value = getattr(parent_meth.fget, attr, set()) parent_value |= getattr(parent_meth.fset, attr, set()) else: parent_value = getattr(parent_meth, attr, set()) if parent_value: methods[attr][name] |= parent_value def setup_field(field_name, field, attribute): if attribute == 'selection_change_with': if isinstance(getattr(field, 'selection', None), str): function_name = field.selection else: return else: function_name = '%s_%s' % (attribute, field_name) function = getattr(cls, function_name, None) if not function: return set_methods(function_name) setattr(field, attribute, methods['depends'][function_name]) meth_names = list(methods['depend_methods'][function_name]) meth_done = set() while meth_names: meth_name = meth_names.pop() method = getattr(cls, meth_name) assert callable(method) or isinstance(method, property), \ "%s.%s not callable or property" % (cls, meth_name) set_methods(meth_name) setattr( field, attribute, getattr(field, attribute) | methods['depends'][meth_name]) meth_names += list(methods['depend_methods'][meth_name] - meth_done) meth_done.add(meth_name) if (attribute == 'on_change' and not getattr(function, 'on_change', None)): # Decorate on_change to always return self setattr(cls, function_name, on_change(function)) for name, field in cls._fields.items(): for attribute in [ 'on_change', 'on_change_with', 'autocomplete', 'selection_change_with', ]: setup_field(name, field, attribute) # Update __rpc__ for field_name, field in cls._fields.items(): field.set_rpc(cls) for button in cls._buttons: if not is_instance_method(cls, button): cls.__rpc__.setdefault(button, RPC(readonly=False, instantiate=0)) else: cls.__rpc__.setdefault( button, RPC(instantiate=0, result=on_change_result)) meth_names = set() meth_done = set() for parent_cls in cls.__mro__: parent_meth = getattr(parent_cls, button, None) if not parent_meth: continue cls.__change_buttons[button] |= getattr( parent_meth, 'change', set()) meth_names |= getattr(parent_meth, 'change_methods', set()) while meth_names: meth_name = meth_names.pop() method = getattr(cls, meth_name) assert callable(method) or isinstance(method, property), \ "%s.%s not callable or property" % (cls, meth_name) set_methods(meth_name) cls.__change_buttons[button] |= methods['depends'][meth_name] meth_names |= (methods['depend_methods'][meth_name] - meth_done) meth_done.add(meth_name) set_methods('on_change_notify') cls._on_change_notify_depends = methods['depends']['on_change_notify'] meth_names = list(methods['depend_methods']['on_change_notify']) meth_done = set() while meth_names: meth_name = meth_names.pop() method = getattr(cls, meth_name) assert callable(method) or isinstance(method, property), \ "%s.%s not callable or property" % (cls, meth_name) set_methods(meth_name) cls._on_change_notify_depends |= methods['depends'][meth_name] meth_names += list(methods['depend_methods'][meth_name] - meth_done) meth_done.add(meth_name)
def dispatch(host, port, protocol, database_name, user, session, object_type, object_name, method, *args, **kwargs): Database = backend.get('Database') DatabaseOperationalError = backend.get('DatabaseOperationalError') if object_type == 'common': if method == 'login': try: database = Database(database_name).connect() cursor = database.cursor() cursor.close() except Exception: return False res = security.login(database_name, user, session) with Transaction().start(database_name, 0): Cache.clean(database_name) Cache.resets(database_name) msg = res and 'successful login' or 'bad login or password' logger.info('%s \'%s\' from %s:%d using %s on database \'%s\'', msg, user, host, port, protocol, database_name) return res or False elif method == 'logout': name = security.logout(database_name, user, session) logger.info('logout \'%s\' from %s:%d ' 'using %s on database \'%s\'', name, host, port, protocol, database_name) return True elif method == 'version': return __version__ elif method == 'list_lang': return [ ('bg_BG', 'Български'), ('ca_ES', 'Català'), ('cs_CZ', 'Čeština'), ('de_DE', 'Deutsch'), ('en_US', 'English'), ('es_AR', 'Español (Argentina)'), ('es_EC', 'Español (Ecuador)'), ('es_ES', 'Español (España)'), ('es_CO', 'Español (Colombia)'), ('fr_FR', 'Français'), ('lt_LT', 'Lietuvių'), ('nl_NL', 'Nederlands'), ('ru_RU', 'Russian'), ('sl_SI', 'Slovenščina'), ] elif method == 'db_exist': try: database = Database(*args, **kwargs).connect() cursor = database.cursor() cursor.close(close=True) return True except Exception: return False elif method == 'list': if not config.getboolean('database', 'list'): raise Exception('AccessDenied') with Transaction().start(None, 0, close=True) as transaction: return transaction.database.list(transaction.cursor) elif method == 'create': return create(*args, **kwargs) elif method == 'restore': return restore(*args, **kwargs) elif method == 'drop': return drop(*args, **kwargs) elif method == 'dump': return dump(*args, **kwargs) return elif object_type == 'system': database = Database(database_name).connect() database_list = Pool.database_list() pool = Pool(database_name) if database_name not in database_list: pool.init() if method == 'listMethods': res = [] for type in ('model', 'wizard', 'report'): for object_name, obj in pool.iterobject(type=type): for method in obj.__rpc__: res.append(type + '.' + object_name + '.' + method) return res elif method == 'methodSignature': return 'signatures not supported' elif method == 'methodHelp': res = [] args_list = args[0].split('.') object_type = args_list[0] object_name = '.'.join(args_list[1:-1]) method = args_list[-1] obj = pool.get(object_name, type=object_type) return pydoc.getdoc(getattr(obj, method)) for count in range(config.getint('database', 'retry'), -1, -1): try: user = security.check(database_name, user, session) except DatabaseOperationalError: if count: continue raise break database_list = Pool.database_list() pool = Pool(database_name) if database_name not in database_list: with Transaction().start(database_name, user, readonly=True) as transaction: pool.init() obj = pool.get(object_name, type=object_type) if method in obj.__rpc__: rpc = obj.__rpc__[method] else: raise UserError('Calling method %s on %s %s is not allowed!' % (method, object_type, object_name)) log_message = '%s.%s.%s(*%s, **%s) from %s@%s:%d/%s' log_args = (object_type, object_name, method, args, kwargs, user, host, port, database_name) logger.info(log_message, *log_args) for count in range(config.getint('database', 'retry'), -1, -1): with Transaction().start(database_name, user, readonly=rpc.readonly) as transaction: Cache.clean(database_name) try: c_args, c_kwargs, transaction.context, transaction.timestamp \ = rpc.convert(obj, *args, **kwargs) meth = getattr(obj, method) if (rpc.instantiate is None or not is_instance_method(obj, method)): result = rpc.result(meth(*c_args, **c_kwargs)) else: assert rpc.instantiate == 0 inst = c_args.pop(0) if hasattr(inst, method): result = rpc.result(meth(inst, *c_args, **c_kwargs)) else: result = [rpc.result(meth(i, *c_args, **c_kwargs)) for i in inst] if not rpc.readonly: transaction.cursor.commit() except DatabaseOperationalError: transaction.cursor.rollback() if count and not rpc.readonly: continue raise except (NotLogged, ConcurrencyException, UserError, UserWarning): logger.debug(log_message, *log_args, exc_info=True) transaction.cursor.rollback() raise except Exception: logger.error(log_message, *log_args, exc_info=True) transaction.cursor.rollback() raise Cache.resets(database_name) with Transaction().start(database_name, 0) as transaction: pool = Pool(database_name) Session = pool.get('ir.session') try: Session.reset(session) except DatabaseOperationalError: logger.debug('Reset session failed', exc_info=True) # Silently fail when reseting session transaction.cursor.rollback() else: transaction.cursor.commit() logger.debug('Result: %s', result) return result
def __parse_fields(cls, element, type, fields_width=None, fields_optional=None, _fields_attrs=None): pool = Pool() Translation = pool.get('ir.translation') ModelData = pool.get('ir.model.data') ModelAccess = pool.get('ir.model.access') Button = pool.get('ir.model.button') User = pool.get('res.user') ActionWindow = pool.get('ir.action.act_window') if fields_width is None: fields_width = {} if fields_optional is None: fields_optional = {} if _fields_attrs is None: fields_attrs = {} else: fields_attrs = _fields_attrs def set_view_ids(element): view_ids = [] if element.get('view_ids'): for view_id in element.get('view_ids').split(','): try: view_ids.append(int(view_id)) except ValueError: view_ids.append(ModelData.get_id(*view_id.split('.'))) element.attrib['view_ids'] = ','.join(map(str, view_ids)) return view_ids def get_relation(field): if hasattr(field, 'model_name'): return field.model_name elif hasattr(field, 'get_target'): return field.get_target().__name__ def get_views(relation, widget, view_ids, mode): Relation = pool.get(relation) views = {} if widget in {'one2many', 'many2many'}: # Prefetch only the first view to prevent infinite loop if view_ids: for view_id in view_ids: view = Relation.fields_view_get(view_id=view_id) views[str(view_id)] = view break else: for view_type in mode: views[view_type] = (Relation.fields_view_get( view_type=view_type)) break return views for attr in ('name', 'icon', 'symbol'): if not element.get(attr): continue fields_attrs.setdefault(element.get(attr), {}) if element.tag == 'field' and type in ['tree', 'form']: for attr in ('name', 'icon'): fname = element.get(attr) if not fname: continue view_ids = set_view_ids(element) if type != 'form': continue field = cls._fields[fname] relation = get_relation(field) if not relation: continue mode = (element.attrib.pop('mode', None) or 'tree,form').split(',') widget = element.attrib.get('widget', field._type) views = get_views(relation, widget, view_ids, mode) element.attrib['mode'] = ','.join(mode) fields_attrs[fname].setdefault('views', {}).update(views) if type == 'tree': if element.get('name') in fields_width: element.set('width', str(fields_width[element.get('name')])) if element.get('optional'): if element.get('name') in fields_optional: optional = str( int(fields_optional[element.get('name')])) element.set('optional', optional) encoder = PYSONEncoder() if element.tag == 'button': button_name = element.attrib['name'] if button_name in cls._buttons: states = cls._buttons[button_name] else: states = {} groups = set(User.get_groups()) button_attr = Button.get_view_attributes(cls.__name__, button_name) for attr, value in button_attr.items(): if not element.get(attr): element.set(attr, value or '') button_groups = Button.get_groups(cls.__name__, button_name) if ((button_groups and not groups & button_groups) or (not button_groups and not ModelAccess.check( cls.__name__, 'write', raise_exception=False))): states = states.copy() states['readonly'] = True element.set('states', encoder.encode(states)) button_rules = Button.get_rules(cls.__name__, button_name) if button_rules: element.set('rule', '1') change = cls.__change_buttons[button_name] if change: change = list(change) # Add id to change if the button is not cached # Not having the id increase the efficiency of the cache if cls.__rpc__[button_name].cache: change.append('id') element.set('change', encoder.encode(change)) if not is_instance_method(cls, button_name): element.set('type', 'class') else: element.set('type', 'instance') for depend in states.get('depends', []): fields_attrs.setdefault(depend, {}) if element.tag == 'link': link_name = element.attrib['name'] action_id = ModelData.get_id(*link_name.split('.')) try: with Transaction().set_context(_check_access=True): action, = ActionWindow.search([('id', '=', action_id)]) except ValueError: action = None if (not action or not action.res_model or not ModelAccess.check( action.res_model, 'read', raise_exception=False)): element.tag = 'label' colspan = element.attrib.get('colspan') link_name = element.attrib['name'] element.attrib.clear() element.attrib['id'] = link_name if colspan is not None: element.attrib['colspan'] = colspan else: element.attrib['id'] = str(action.action.id) # translate view if Transaction().language != 'en': for attr in ('string', 'sum', 'confirm', 'help'): if element.get(attr): trans = Translation.get_source(cls.__name__, 'view', Transaction().language, element.get(attr)) if trans: element.set(attr, trans) if element.tag == 'tree' and element.get('sequence'): fields_attrs.setdefault(element.get('sequence'), {}) if element.tag == 'calendar': for attr in ['dtstart', 'dtend', 'color', 'background_color']: if element.get(attr): fields_attrs.setdefault(element.get(attr), {}) for field in element: fields_attrs = cls.__parse_fields(field, type, fields_width=fields_width, fields_optional=fields_optional, _fields_attrs=fields_attrs) return fields_attrs
def __view_look_dom(cls, element, type, fields_width=None, fields_attrs=None): pool = Pool() Translation = pool.get('ir.translation') ModelData = pool.get('ir.model.data') Button = pool.get('ir.model.button') User = pool.get('res.user') if fields_width is None: fields_width = {} if not fields_attrs: fields_attrs = {} else: fields_attrs = copy.deepcopy(fields_attrs) def set_view_ids(element): view_ids = [] if element.get('view_ids'): for view_id in element.get('view_ids').split(','): try: view_ids.append(int(view_id)) except ValueError: view_ids.append(ModelData.get_id(*view_id.split('.'))) element.attrib['view_ids'] = ','.join(map(str, view_ids)) return view_ids def get_relation(field): if hasattr(field, 'model_name'): return field.model_name elif hasattr(field, 'get_target'): return field.get_target().__name__ def get_views(relation, view_ids, mode): Relation = pool.get(relation) views = {} if field._type in ['one2many', 'many2many']: # Prefetch only the first view to prevent infinite loop if view_ids: for view_id in view_ids: view = Relation.fields_view_get(view_id=view_id) views[str(view_id)] = view break else: for view_type in mode: views[view_type] = ( Relation.fields_view_get(view_type=view_type)) break return views for attr in ('name', 'icon'): if not element.get(attr): continue fields_attrs.setdefault(element.get(attr), {}) if element.tag == 'field' and type in ['tree', 'form']: for attr in ('name', 'icon'): fname = element.get(attr) if not fname: continue view_ids = set_view_ids(element) if type != 'form': continue field = cls._fields[fname] relation = get_relation(field) if not relation: continue mode = ( element.attrib.pop('mode', None) or 'tree,form').split(',') views = get_views(relation, view_ids, mode) element.attrib['mode'] = ','.join(mode) fields_attrs[fname].setdefault('views', {}).update(views) if type == 'tree' and element.get('name') in fields_width: element.set('width', str(fields_width[element.get('name')])) encoder = PYSONEncoder() if element.tag == 'button': button_name = element.attrib['name'] if button_name in cls._buttons: states = cls._buttons[button_name] else: states = {} groups = set(User.get_groups()) button_groups = Button.get_groups(cls.__name__, button_name) if button_groups and not groups & button_groups: states = states.copy() states['readonly'] = True element.set('states', encoder.encode(states)) change = cls.__change_buttons[button_name] if change: element.set('change', encoder.encode(list(change))) if not is_instance_method(cls, button_name): element.set('type', 'class') else: element.set('type', 'instance') # translate view if Transaction().language != 'en_US': for attr in ('string', 'sum', 'confirm', 'help'): if element.get(attr): trans = Translation.get_source(cls.__name__, 'view', Transaction().language, element.get(attr)) if trans: element.set(attr, trans) # Set header string if element.tag in ('form', 'tree', 'graph'): element.set('string', cls.view_header_get( element.get('string') or '', view_type=element.tag)) if element.tag == 'tree' and element.get('sequence'): fields_attrs.setdefault(element.get('sequence'), {}) if element.tag == 'calendar': for attr in ('dtstart', 'dtend'): if element.get(attr): fields_attrs.setdefault(element.get(attr), {}) for field in element: fields_attrs = cls.__view_look_dom(field, type, fields_width=fields_width, fields_attrs=fields_attrs) return fields_attrs
def _dispatch(request, pool, *args, **kwargs): obj, method = get_object_method(request, pool) if method in obj.__rpc__: rpc = obj.__rpc__[method] else: abort(HTTPStatus.FORBIDDEN) user = request.user_id session = None if request.authorization.type == 'session': session = request.authorization.get('session') if rpc.fresh_session and session: context = {'_request': request.context} if not security.check_timeout( pool.database_name, user, session, context=context): abort(HTTPStatus.UNAUTHORIZED) log_message = '%s.%s(*%s, **%s) from %s@%s%s' username = request.authorization.username if isinstance(username, bytes): username = username.decode('utf-8') log_args = (obj, method, args, kwargs, username, request.remote_addr, request.path) logger.debug(log_message, *log_args) retry = config.getint('database', 'retry') for count in range(retry, -1, -1): if count != retry: time.sleep(0.02 * (retry - count)) with Transaction().start(pool.database_name, user, readonly=rpc.readonly) as transaction: try: c_args, c_kwargs, transaction.context, transaction.timestamp \ = rpc.convert(obj, *args, **kwargs) transaction.context['_request'] = request.context meth = getattr(obj, method) if (rpc.instantiate is None or not is_instance_method(obj, method)): result = rpc.result(meth(*c_args, **c_kwargs)) else: assert rpc.instantiate == 0 inst = c_args.pop(0) if hasattr(inst, method): result = rpc.result(meth(inst, *c_args, **c_kwargs)) else: result = [ rpc.result(meth(i, *c_args, **c_kwargs)) for i in inst ] except backend.DatabaseOperationalError: if count and not rpc.readonly: transaction.rollback() continue logger.error(log_message, *log_args, exc_info=True) raise except (ConcurrencyException, UserError, UserWarning, LoginException): logger.debug(log_message, *log_args, exc_info=True) raise except Exception: logger.error(log_message, *log_args, exc_info=True) raise # Need to commit to unlock SQLite database transaction.commit() while transaction.tasks: task_id = transaction.tasks.pop() run_task(pool, task_id) if session: context = {'_request': request.context} security.reset(pool.database_name, session, context=context) logger.debug('Result: %s', result) response = app.make_response(request, result) if rpc.readonly and rpc.cache: response.headers.extend(rpc.cache.headers()) return response
def _dispatch(request, pool, *args, **kwargs): DatabaseOperationalError = backend.get('DatabaseOperationalError') obj, method = get_object_method(request, pool) if method in obj.__rpc__: rpc = obj.__rpc__[method] else: raise UserError('Calling method %s on %s is not allowed' % (method, obj)) log_message = '%s.%s(*%s, **%s) from %s@%s/%s' log_args = (obj, method, args, kwargs, request.authorization.username, request.remote_addr, request.path) logger.info(log_message, *log_args) user = request.user_id session = None if request.authorization.type == 'session': session = request.authorization.get('session') for count in range(config.getint('database', 'retry'), -1, -1): with Transaction().start(pool.database_name, user, readonly=rpc.readonly, context={'session': session}) as transaction: Cache.clean(pool.database_name) try: PerfLog().on_enter(user, session, request.method, args, kwargs) except: perf_logger.exception('on_enter failed') try: c_args, c_kwargs, transaction.context, transaction.timestamp \ = rpc.convert(obj, *args, **kwargs) meth = getattr(obj, method) try: wrapped_meth = profile(meth) except: perf_logger.exception('profile failed') else: meth = wrapped_meth if (rpc.instantiate is None or not is_instance_method(obj, method)): result = rpc.result(meth(*c_args, **c_kwargs)) else: assert rpc.instantiate == 0 inst = c_args.pop(0) if hasattr(inst, method): result = rpc.result(meth(inst, *c_args, **c_kwargs)) else: result = [rpc.result(meth(i, *c_args, **c_kwargs)) for i in inst] except DatabaseOperationalError: if count and not rpc.readonly: transaction.rollback() continue logger.error(log_message, *log_args, exc_info=True) raise except (ConcurrencyException, UserError, UserWarning): logger.debug(log_message, *log_args, exc_info=True) raise except Exception: logger.error(log_message, *log_args, exc_info=True) raise # Need to commit to unlock SQLite database transaction.commit() Cache.resets(pool.database_name) if request.authorization.type == 'session': try: with Transaction().start(pool.database_name, 0) as transaction: Session = pool.get('ir.session') Session.reset(request.authorization.get('session')) except DatabaseOperationalError: logger.debug('Reset session failed', exc_info=True) logger.debug('Result: %s', result) try: PerfLog().on_leave(result) except: perf_logger.exception('on_leave failed') return result
def __view_look_dom(cls, element, type, fields_width=None, fields_attrs=None): pool = Pool() Translation = pool.get('ir.translation') ModelData = pool.get('ir.model.data') Button = pool.get('ir.model.button') User = pool.get('res.user') if fields_width is None: fields_width = {} if not fields_attrs: fields_attrs = {} else: fields_attrs = copy.deepcopy(fields_attrs) childs = True if element.tag in ('field', 'label', 'separator', 'group', 'suffix', 'prefix'): for attr in ('name', 'icon'): if element.get(attr): fields_attrs.setdefault(element.get(attr), {}) try: field = cls._fields[element.get(attr)] if hasattr(field, 'model_name'): relation = field.model_name else: relation = field.get_target().__name__ except Exception: relation = False if relation and element.tag == 'field': childs = False views = {} mode = (element.attrib.pop('mode', None) or 'tree,form').split(',') view_ids = [] if element.get('view_ids'): for view_id in element.get('view_ids').split(','): try: view_ids.append(int(view_id)) except ValueError: view_ids.append( ModelData.get_id(*view_id.split('.'))) Relation = pool.get(relation) if (not len(element) and type == 'form' and field._type in ('one2many', 'many2many')): # Prefetch only the first view to prevent infinite # loop if view_ids: for view_id in view_ids: view = Relation.fields_view_get( view_id=view_id) views[str(view_id)] = view break else: for view_type in mode: views[view_type] = \ Relation.fields_view_get( view_type=view_type) break element.attrib['mode'] = ','.join(mode) element.attrib['view_ids'] = ','.join( map(str, view_ids)) fields_attrs[element.get(attr)].setdefault( 'views', {}).update(views) if element.get('name') in fields_width: element.set('width', str(fields_width[element.get('name')])) encoder = PYSONEncoder() if element.tag == 'button': button_name = element.attrib['name'] if button_name in cls._buttons: states = cls._buttons[button_name] else: states = {} groups = set(User.get_groups()) button_groups = Button.get_groups(cls.__name__, button_name) if button_groups and not groups & button_groups: states = states.copy() states['readonly'] = True element.set('states', encoder.encode(states)) change = cls.__change_buttons[button_name] if change: element.set('change', encoder.encode(list(change))) if not is_instance_method(cls, button_name): element.set('type', 'class') else: element.set('type', 'instance') # translate view if Transaction().language != 'en_US': for attr in ('string', 'sum', 'confirm', 'help'): if element.get(attr): trans = Translation.get_source(cls.__name__, 'view', Transaction().language, element.get(attr)) if trans: element.set(attr, trans) # Set header string if element.tag in ('form', 'tree', 'graph'): element.set( 'string', cls.view_header_get(element.get('string') or '', view_type=element.tag)) if element.tag == 'tree' and element.get('sequence'): fields_attrs.setdefault(element.get('sequence'), {}) if element.tag == 'calendar': for attr in ('dtstart', 'dtend'): if element.get(attr): fields_attrs.setdefault(element.get(attr), {}) if childs: for field in element: fields_attrs = cls.__view_look_dom(field, type, fields_width=fields_width, fields_attrs=fields_attrs) return fields_attrs
def _dispatch(request, pool, *args, **kwargs): DatabaseOperationalError = backend.get('DatabaseOperationalError') obj, method = get_object_method(request, pool) if method in obj.__rpc__: rpc = obj.__rpc__[method] else: raise UserError('Calling method %s on %s is not allowed' % (method, obj)) # JCA : If log_threshold is != -1, we only log the times for calls that # exceed the configured value if log_threshold == -1: log_message = '%s.%s(*%s, **%s) from %s@%s/%s' username = request.authorization.username.decode('utf-8') log_args = (obj, method, args, kwargs, username, request.remote_addr, request.path) logger.info(log_message, *log_args) else: log_message = '%s.%s (%s s)' log_args = (obj, method) log_start = time.time() user = request.user_id session = None if request.authorization.type == 'session': session = request.authorization.get('session') for count in range(config.getint('database', 'retry'), -1, -1): with Transaction().start(pool.database_name, user, readonly=rpc.readonly, context={'session': session}) as transaction: try: PerfLog().on_enter(user, session, request.rpc_method, args, kwargs) except: perf_logger.exception('on_enter failed') try: c_args, c_kwargs, transaction.context, transaction.timestamp \ = rpc.convert(obj, *args, **kwargs) meth = getattr(obj, method) try: wrapped_meth = profile(meth) except: perf_logger.exception('profile failed') else: meth = wrapped_meth if (rpc.instantiate is None or not is_instance_method(obj, method)): result = rpc.result(meth(*c_args, **c_kwargs)) else: assert rpc.instantiate == 0 inst = c_args.pop(0) if hasattr(inst, method): result = rpc.result(meth(inst, *c_args, **c_kwargs)) else: result = [ rpc.result(meth(i, *c_args, **c_kwargs)) for i in inst ] except DatabaseOperationalError: if count and not rpc.readonly: transaction.rollback() continue if log_threshold != -1: log_end = time.time() log_args += (str(log_end - log_start), ) log_exception(logger.error, log_message, *log_args) raise except (ConcurrencyException, UserError, UserWarning, LoginException): if log_threshold != -1: log_end = time.time() log_args += (str(log_end - log_start), ) log_exception(logger.debug, log_message, *log_args) raise except Exception: if log_threshold != -1: log_end = time.time() log_args += (str(log_end - log_start), ) log_exception(logger.error, log_message, *log_args) raise # Need to commit to unlock SQLite database transaction.commit() if request.authorization.type == 'session': try: with Transaction().start(pool.database_name, 0) as transaction: Session = pool.get('ir.session') Session.reset(request.authorization.get('session')) except DatabaseOperationalError: log_exception(logger.debug, 'Reset session failed') if log_threshold == -1: logger.debug('Result: %s', result) else: log_end = time.time() log_args += (str(log_end - log_start), ) if log_end - log_start > log_threshold: logger.info(log_message, *log_args) else: logger.debug(log_message, *log_args) try: PerfLog().on_leave(result) except: perf_logger.exception('on_leave failed') return result