Example #1
0
 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)
Example #2
0
    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)
Example #3
0
 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__,
                 })
Example #4
0
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
Example #5
0
    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))
Example #6
0
    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)
Example #7
0
    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())
Example #8
0
    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)
Example #9
0
    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)
Example #10
0
 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__,
                     })
Example #11
0
 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__,
             })
Example #12
0
    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]
Example #13
0
 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)
Example #14
0
    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'))
Example #15
0
    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'))
Example #16
0
    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))
Example #17
0
    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))
Example #18
0
    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())
Example #19
0
    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))
Example #20
0
 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__,
                 })
Example #21
0
    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)
Example #22
0
    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
Example #23
0
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
Example #24
0
    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
Example #25
0
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
Example #26
0
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
Example #27
0
    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)
Example #28
0
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
Example #29
0
    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
Example #30
0
    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
Example #31
0
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
Example #32
0
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
Example #33
0
    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
Example #34
0
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