Beispiel #1
0
    def test_0020_pickling(self):
        '''
        Test if the lazy rendering object can be pickled and rendered
        with a totally different context (when no application, request
        or transaction bound objects are present).
        '''
        with Transaction().start(DB_NAME, USER, CONTEXT) as txn:
            self.setup_defaults()
            app = self.get_app()

            with app.test_request_context('/'):
                response = render_template('tests/test-changing-context.html',
                                           variable="a")
                self.assertEqual(response, 'a')
                pickled_response = pickle.dumps(response)

            txn.rollback()
            # Drop the cache as the transaction is rollbacked
            Cache.drop(DB_NAME)

        with Transaction().start(DB_NAME, USER, CONTEXT) as txn:
            self.setup_defaults()
            app = self.get_app()

            with app.test_request_context('/'):
                response = pickle.loads(pickled_response)
                self.assertEqual(response, 'a')

            txn.rollback()
            # Drop the cache as the transaction is rollbacked
            Cache.drop(DB_NAME)
Beispiel #2
0
    def test_0040_inheritance(self):
        '''Test if templates are read in the order of the tryton
        module dependency graph. To test this we install the test
        module now and then try to load a template which is different
        with the test module.
        '''
        trytond.tests.test_tryton.install_module('nereid_test')

        with Transaction().start(DB_NAME, USER, CONTEXT) as txn:  # noqa
            # Add nereid_test also to list of modules installed so
            # that it is also added to the templates path

            self.setup_defaults()
            app = self.get_app()

            self.assertEqual(len(app.jinja_loader.loaders), 3)

            with app.test_request_context('/'):
                self.assertEqual(
                    render_template('tests/from-module.html'),
                    'from-nereid-test-module'
                )

            txn.rollback()
            Cache.drop(DB_NAME)
Beispiel #3
0
    def test_0020_pickling(self):
        '''
        Test if the lazy rendering object can be pickled and rendered
        with a totally different context (when no application, request
        or transaction bound objects are present).
        '''
        with Transaction().start(DB_NAME, USER, CONTEXT) as txn:
            self.setup_defaults()
            app = self.get_app()

            with app.test_request_context('/'):
                response = render_template(
                    'tests/test-changing-context.html',
                    variable="a"
                )
                self.assertEqual(response, 'a')
                pickled_response = pickle.dumps(response)

            txn.rollback()
            # Drop the cache as the transaction is rollbacked
            Cache.drop(DB_NAME)

        with Transaction().start(DB_NAME, USER, CONTEXT) as txn:
            self.setup_defaults()
            app = self.get_app()

            with app.test_request_context('/'):
                response = pickle.loads(pickled_response)
                self.assertEqual(response, 'a')

            txn.rollback()
            # Drop the cache as the transaction is rollbacked
            Cache.drop(DB_NAME)
Beispiel #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
Beispiel #5
0
 def commit(self):
     from trytond.cache import Cache
     try:
         if self._datamanagers:
             for datamanager in self._datamanagers:
                 datamanager.tpc_begin(self)
             for datamanager in self._datamanagers:
                 datamanager.commit(self)
             for datamanager in self._datamanagers:
                 datamanager.tpc_vote(self)
         # ABD: Some datamanager may returns transactions which should
         # be committed just before the main transaction
         for sub_transaction in self._sub_transactions:
             # Does not handle TPC or recursive transaction commit
             # This just commits the sub transactions to avoid any crashes
             # which could occur otherwise.
             sub_transaction.connection.commit()
         self.started_at = self.monotonic_time()
         Cache.commit(self)
         self.connection.commit()
     except Exception:
         self.rollback()
         raise
     else:
         try:
             for datamanager in self._datamanagers:
                 datamanager.tpc_finish(self)
         except Exception:
             logger.critical(
                 'A datamanager raised an exception in'
                 ' tpc_finish, the data might be inconsistant',
                 exc_info=True)
Beispiel #6
0
    def get_userinfo(self, user, password, command=''):
        path = urlparse.urlparse(self.path).path
        dbname = urllib.unquote_plus(path.split('/', 2)[1])
        database = Database().connect()
        cursor = database.cursor()
        databases = database.list(cursor)
        cursor.close()
        if not dbname or dbname not in databases:
            return True
        if user:
            user = int(login(dbname, user, password, cache=False))
            if not user:
                return None
        else:
            url = urlparse.urlparse(self.path)
            query = urlparse.parse_qs(url.query)
            path = url.path[len(dbname) + 2:]
            if 'key' in query:
                key, = query['key']
                with Transaction().start(dbname, 0) as transaction:
                    database_list = Pool.database_list()
                    pool = Pool(dbname)
                    if not dbname in database_list:
                        pool.init()
                    Share = pool.get('webdav.share')
                    user = Share.get_login(key, command, path)
                    transaction.cursor.commit()
            if not user:
                return None

        Transaction().start(dbname, user)
        Cache.clean(dbname)
        return user
Beispiel #7
0
 def commit(self):
     try:
         if self._datamanagers:
             for datamanager in self._datamanagers:
                 datamanager.tpc_begin(self)
             for datamanager in self._datamanagers:
                 datamanager.commit(self)
             for datamanager in self._datamanagers:
                 datamanager.tpc_vote(self)
         self.connection.commit()
     except:
         self.rollback()
         raise
     else:
         try:
             for datamanager in self._datamanagers:
                 datamanager.tpc_finish(self)
         except:
             logger.critical(
                 'A datamanager raised an exception in'
                 ' tpc_finish, the data might be inconsistant',
                 exc_info=True)
     if not self._nocache:
         from trytond.cache import Cache
         Cache.resets(self.database.name)
Beispiel #8
0
 def wrapper(request, pool, *args, **kwargs):
     DatabaseOperationalError = backend.get('DatabaseOperationalError')
     readonly_ = readonly  # can not modify non local
     if readonly_ is None:
         if request.method in {'POST', 'PUT', 'DELETE', 'PATCH'}:
             readonly_ = False
         else:
             readonly_ = True
     for count in range(config.getint('database', 'retry'), -1, -1):
         with Transaction().start(
                 pool.database_name, 0, readonly=readonly_
                 ) as transaction:
             try:
                 Cache.clean(pool.database_name)
                 result = func(request, pool, *args, **kwargs)
                 return result
             except DatabaseOperationalError:
                 if count and not readonly_:
                     transaction.rollback()
                     continue
                 logger.error('%s', request, exc_info=True)
                 raise
             except Exception:
                 logger.error('%s', request, exc_info=True)
                 raise
             # Need to commit to unlock SQLite database
             transaction.commit()
             Cache.resets(pool.database_name)
Beispiel #9
0
 def commit(self):
     from trytond.cache import Cache
     try:
         if self._datamanagers:
             for datamanager in self._datamanagers:
                 datamanager.tpc_begin(self)
             for datamanager in self._datamanagers:
                 datamanager.commit(self)
             for datamanager in self._datamanagers:
                 datamanager.tpc_vote(self)
         self.started_at = self.monotonic_time()
         Cache.commit(self)
         self.connection.commit()
     except Exception:
         self.rollback()
         raise
     else:
         try:
             for datamanager in self._datamanagers:
                 datamanager.tpc_finish(self)
         except Exception:
             logger.critical(
                 'A datamanager raised an exception in'
                 ' tpc_finish, the data might be inconsistant',
                 exc_info=True)
Beispiel #10
0
    def _load_modules():
        global res
        TableHandler = backend.get('TableHandler')
        cursor = Transaction().cursor

        # Migration from 3.6: remove double module
        old_table = 'ir_module_module'
        new_table = 'ir_module'
        if TableHandler.table_exist(cursor, old_table):
            TableHandler.table_rename(cursor, old_table, new_table)
        if update:
            cursor.execute(
                *ir_module.select(ir_module.name,
                                  where=ir_module.state.in_(('installed',
                                                             'to install',
                                                             'to upgrade',
                                                             'to remove'))))
        else:
            cursor.execute(
                *ir_module.select(ir_module.name,
                                  where=ir_module.state.in_(('installed',
                                                             'to upgrade',
                                                             'to remove'))))
        module_list = [name for (name, ) in cursor.fetchall()]
        if update:
            module_list += update
        graph = create_graph(module_list)[0]

        try:
            load_module_graph(graph, pool, update, lang)
        except Exception:
            cursor.rollback()
            raise

        if update:
            cursor.execute(*ir_module.select(
                ir_module.name, where=(ir_module.state == 'to remove')))
            fetchall = cursor.fetchall()
            if fetchall:
                for (mod_name, ) in fetchall:
                    # TODO check if ressource not updated by the user
                    cursor.execute(*ir_model_data.select(
                        ir_model_data.model,
                        ir_model_data.db_id,
                        where=(ir_model_data.module == mod_name),
                        order_by=ir_model_data.id.desc))
                    for rmod, rid in cursor.fetchall():
                        Model = pool.get(rmod)
                        Model.delete([Model(rid)])
                    cursor.commit()
                cursor.execute(
                    *ir_module.update([ir_module.state], ['uninstalled'],
                                      where=(ir_module.state == 'to remove')))
                cursor.commit()
                res = False

            Module = pool.get('ir.module')
            Module.update_list()
        cursor.commit()
        Cache.resets(database_name)
Beispiel #11
0
    def __call__(self, *args):
        from trytond.cache import Cache
        from trytond.transaction import Transaction
        from trytond.rpc import RPC

        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:
            Cache.clean(self._config.database_name)
            args, kwargs, transaction.context, transaction.timestamp = \
                rpc.convert(self._object, *args)
            meth = getattr(self._object, self._name)
            if not hasattr(meth, 'im_self') or meth.im_self:
                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]
            if not rpc.readonly:
                transaction.commit()
            Cache.resets(self._config.database_name)
        return result
Beispiel #12
0
    def get_userinfo(self, user, password, command=''):
        path = urlparse.urlparse(self.path).path
        dbname = urllib.unquote_plus(path.split('/', 2)[1])
        database = backend.get('Database')().connect()
        cursor = database.cursor()
        databases = database.list(cursor)
        cursor.close()
        if not dbname or dbname not in databases:
            return True
        if user:
            user = int(login(dbname, user, password, cache=False))
            if not user:
                return None
        else:
            url = urlparse.urlparse(self.path)
            query = urlparse.parse_qs(url.query)
            path = url.path[len(dbname) + 2:]
            if 'key' in query:
                key, = query['key']
                with Transaction().start(dbname, 0) as transaction:
                    database_list = Pool.database_list()
                    pool = Pool(dbname)
                    if dbname not in database_list:
                        pool.init()
                    Share = pool.get('webdav.share')
                    user = Share.get_login(key, command, path)
                    transaction.cursor.commit()
            if not user:
                return None

        Transaction().start(dbname, user, context={
            '_check_access': True,
        })
        Cache.clean(dbname)
        return user
Beispiel #13
0
 def rollback(self):
     from trytond.cache import Cache
     for cache in self.cache.values():
         cache.clear()
     for datamanager in self._datamanagers:
         datamanager.tpc_abort(self)
     Cache.rollback(self)
     self.connection.rollback()
Beispiel #14
0
 def wrapper(*args, **kwargs):
     transaction = Transaction()
     with transaction.start(DB_NAME, user, context=context):
         result = func(*args, **kwargs)
         transaction.cursor.rollback()
         # Drop the cache as the transaction is rollbacked
         Cache.drop(DB_NAME)
         return result
Beispiel #15
0
 def wrapper(*args, **kwargs):
     transaction = Transaction()
     with transaction.start(DB_NAME, user, context=context):
         result = func(*args, **kwargs)
         transaction.rollback()
         # Drop the cache as the transaction is rollbacked
         Cache.drop(DB_NAME)
         return result
 def clear(self):
     dbname = Transaction().cursor.dbname
     self._lock.acquire()
     try:
         self._cache.setdefault(dbname, {})
         self._cache[dbname].clear()
         Cache.reset(dbname, self._name)
     finally:
         self._lock.release()
Beispiel #17
0
 def rollback(self):
     for cache in self.cache.itervalues():
         cache.clear()
     for datamanager in self._datamanagers:
         datamanager.tpc_abort(self)
     self.connection.rollback()
     if not self._nocache:
         from trytond.cache import Cache
         Cache.resets(self.database.name)
Beispiel #18
0
    def finish(self):
        WebDAVServer.DAVRequestHandler.finish(self)

        if not Transaction().connection:
            return
        dbname = Transaction().database.name
        Transaction().__exit__(None, None, None)
        if dbname:
            with Transaction().start(dbname, 0):
                Cache.resets(dbname)
Beispiel #19
0
def drop_db(name=DB_NAME):
    if db_exist(name):
        database = backend.Database(name)
        database.close()

        with Transaction().start(None, 0, close=True,
                                 autocommit=True) as transaction:
            database.drop(transaction.connection, name)
            Pool.stop(name)
            Cache.drop(name)
Beispiel #20
0
    def finish(self):
        WebDAVServer.DAVRequestHandler.finish(self)

        global CACHE
        CACHE = LocalDict()
        if not Transaction().cursor:
            return
        dbname = Transaction().cursor.database_name
        Transaction().stop()
        if dbname:
            Cache.resets(dbname)
Beispiel #21
0
    def dispatch_request(self):
        """
        Does the request dispatching.  Matches the URL and returns the
        return value of the view or error handler.  This does not have to
        be a response object.
        """
        DatabaseOperationalError = backend.get('DatabaseOperationalError')

        req = _request_ctx_stack.top.request
        if req.routing_exception is not None:
            self.raise_routing_exception(req)

        rule = req.url_rule
        # if we provide automatic options for this URL and the
        # request came with the OPTIONS method, reply automatically
        if getattr(rule, 'provide_automatic_options', False) \
           and req.method == 'OPTIONS':
            return self.make_default_options_response()

        with Transaction().start(self.database_name, 0):
            Cache.clean(self.database_name)
            Cache.resets(self.database_name)

        with Transaction().start(self.database_name, 0, readonly=True):
            Website = Pool().get('nereid.website')
            website = Website.get_from_host(req.host)

            user, company = website.application_user.id, website.company.id

        for count in range(int(config.get('database', 'retry')), -1, -1):
            with Transaction().start(
                    self.database_name, user,
                    context={'company': company},
                    readonly=rule.is_readonly) as txn:
                try:
                    transaction_start.send(self)
                    rv = self._dispatch_request(req)
                    txn.cursor.commit()
                except DatabaseOperationalError:
                    # Strict transaction handling may cause this.
                    # Rollback and Retry the whole transaction if within
                    # max retries, or raise exception and quit.
                    txn.cursor.rollback()
                    if count:
                        continue
                    raise
                except Exception:
                    # Rollback and raise any other exception
                    txn.cursor.rollback()
                    raise
                else:
                    return rv
                finally:
                    transaction_stop.send(self)
Beispiel #22
0
    def _load_modules():
        global res
        TableHandler = backend.get('TableHandler')
        cursor = Transaction().cursor

        # Migration from 3.6: remove double module
        old_table = 'ir_module_module'
        new_table = 'ir_module'
        if TableHandler.table_exist(cursor, old_table):
            TableHandler.table_rename(cursor, old_table, new_table)
        if update:
            cursor.execute(*ir_module.select(ir_module.name,
                    where=ir_module.state.in_(('installed', 'to install',
                            'to upgrade', 'to remove'))))
        else:
            cursor.execute(*ir_module.select(ir_module.name,
                    where=ir_module.state.in_(('installed', 'to upgrade',
                            'to remove'))))
        module_list = [name for (name,) in cursor.fetchall()]
        if update:
            module_list += update
        graph = create_graph(module_list)[0]

        try:
            load_module_graph(graph, pool, update, lang)
        except Exception:
            cursor.rollback()
            raise

        if update:
            cursor.execute(*ir_module.select(ir_module.name,
                    where=(ir_module.state == 'to remove')))
            fetchall = cursor.fetchall()
            if fetchall:
                for (mod_name,) in fetchall:
                    # TODO check if ressource not updated by the user
                    cursor.execute(*ir_model_data.select(ir_model_data.model,
                            ir_model_data.db_id,
                            where=(ir_model_data.module == mod_name),
                            order_by=ir_model_data.id.desc))
                    for rmod, rid in cursor.fetchall():
                        Model = pool.get(rmod)
                        Model.delete([Model(rid)])
                    cursor.commit()
                cursor.execute(*ir_module.update([ir_module.state],
                        ['uninstalled'],
                        where=(ir_module.state == 'to remove')))
                cursor.commit()
                res = False

            Module = pool.get('ir.module')
            Module.update_list()
        cursor.commit()
        Cache.resets(database_name)
Beispiel #23
0
    def start(self,
              database_name,
              user,
              readonly=False,
              context=None,
              close=False,
              autocommit=False):
        '''
        Start transaction
        '''
        assert self.user is None
        assert self.database is None
        assert self.close is None
        assert self.context is None
        # Compute started_at before connect to ensure
        # it is strictly before all transactions started after
        # but it may be also before transactions started before
        self.started_at = self.monotonic_time()
        if not database_name:
            database = backend.Database().connect()
        else:
            database = backend.Database(database_name).connect()
        Flavor.set(backend.Database.flavor)
        self.connection = database.get_connection(readonly=readonly,
                                                  autocommit=autocommit)
        self.user = user
        self.database = database
        self.readonly = readonly
        self.close = close
        self.context = context or {}
        self.create_records = {}
        self.delete_records = {}
        self.delete = {}
        self.trigger_records = defaultdict(set)
        self.timestamp = {}
        self.counter = 0
        self._datamanagers = []
        self._sub_transactions = []
        self._sub_transactions_to_close = []
        if database_name:
            from trytond.cache import Cache
            try:
                Cache.sync(self)
            except BaseException:
                self.stop(False)
                raise

            from trytond import iwc
            try:
                iwc.start(database_name)
            except BaseException:
                self.stop(False)
                raise
        return self
Beispiel #24
0
    def finish(self):
        WebDAVServer.DAVRequestHandler.finish(self)

        global CACHE
        CACHE = LocalDict()
        if not Transaction().cursor:
            return
        dbname = Transaction().cursor.database_name
        Transaction().stop()
        if dbname:
            with Transaction().start(dbname, 0):
                Cache.resets(dbname)
Beispiel #25
0
def drop_db(name=DB_NAME):
    if db_exist(name):
        Database = backend.get('Database')
        database = Database(name)
        database.close()
        if name in Cache._listener:
            del Cache._listener[name]

        with Transaction().start(None, 0, close=True,
                                 autocommit=True) as transaction:
            Cache.drop(name)
            database.drop(transaction.connection, name)
            Pool.stop(name)
Beispiel #26
0
def func():
    with Transaction().start(dbname, user_id, context=CONTEXT) as transaction:
        # No password is needed, because we are working directly with the
        # API, bypassing any networking stuff.
        # don't forget to install the party's module before this test.
        party_obj = pool.get('party.party')
        new_party = party_obj.create([{'name': 'test_transactions'}])[0]
        new_party_id = new_party.id
        transaction.cursor.commit()

    print new_party_id
    # Reset the global cache for multi-instance
    Cache.resets(dbname)
Beispiel #27
0
def drop_db(name=DB_NAME):
    if db_exist(name):
        Database = backend.get('Database')
        database = Database(name)
        database.close()

        with Transaction().start(
                None, 0, close=True, autocommit=True, _nocache=True) \
                as transaction:
            database.kill_other_sessions(transaction.connection, name)
            database.drop(transaction.connection, name)
            Pool.stop(name)
            Cache.drop(name)
Beispiel #28
0
class Message(ModelSQL, ModelView):
    "Message"
    __name__ = "ir.message"

    _message_cache = Cache('ir.message', size_limit=10240, context=False)
    text = fields.Text("Text", required=True, translate=True)

    @classmethod
    def gettext(cls, *args, **variables):
        pool = Pool()
        ModelData = pool.get('ir.model.data')
        module, message_id, language = args

        key = (module, message_id, language)
        text = cls._message_cache.get(key)
        if text is None:
            message_id = ModelData.get_id(module, message_id)
            with Transaction().set_context(language=language):
                message = cls(message_id)

            text = message.text
            cls._message_cache.set(key, text)
        return text if not variables else text % variables

    @classmethod
    def write(cls, messages, values, *args):
        super(Message, cls).write(messages, values, *args)
        cls._message_cache.clear()

    @classmethod
    def delete(cls, messages):
        super(Message, cls).delete(messages)
        cls._message_cache.clear()
Beispiel #29
0
def login(request, database_name, user, password):
    Database = backend.get('Database')
    DatabaseOperationalError = backend.get('DatabaseOperationalError')
    try:
        Database(database_name).connect()
    except DatabaseOperationalError:
        logger.error('fail to connect to %s', database_name, exc_info=True)
        return False
    session = security.login(database_name, user, password)
    with Transaction().start(database_name, 0):
        Cache.clean(database_name)
        Cache.resets(database_name)
    msg = 'successful login' if session else 'bad login or password'
    logger.info('%s \'%s\' from %s using %s on database \'%s\'',
        msg, user, request.remote_addr, request.scheme, database_name)
    return session
Beispiel #30
0
class DigitsMixin:
    __slots__ = ()

    _digits_cache = Cache('_digits_mixin..get_digits', context=False)

    @classmethod
    def __setup__(cls):
        super().__setup__()
        cls.__rpc__.update({
            'get_digits':
            RPC(instantiate=0, cache=dict(days=1)),
        })

    def get_digits(self):
        key = str(self)
        digits = self._digits_cache.get(key)
        if digits is not None:
            return digits
        digits = self._get_digits()
        self._digits_cache.set(key, digits)
        return digits

    def _get_digits(self):
        return (16, self.digits)

    @classmethod
    def write(cls, *args):
        super().write(*args)
        cls._digits_cache.clear()
Beispiel #31
0
def login(request, database_name, user, password):
    Database = backend.get('Database')
    DatabaseOperationalError = backend.get('DatabaseOperationalError')
    try:
        Database(database_name).connect()
    except DatabaseOperationalError:
        logger.error('fail to connect to %s', database_name, exc_info=True)
        return False
    session = security.login(database_name, user, password)
    with Transaction().start(database_name, 0):
        Cache.clean(database_name)
        Cache.resets(database_name)
    msg = 'successful login' if session else 'bad login or password'
    logger.info('%s \'%s\' from %s using %s on database \'%s\'',
        msg, user, request.remote_addr, request.scheme, database_name)
    return session
Beispiel #32
0
class SubdivisionType(DeactivableMixin, ModelSQL, ModelView):
    "Address Subdivision Type"
    __name__ = 'party.address.subdivision_type'
    country_code = fields.Char("Country Code", size=2, required=True)
    types = fields.MultiSelection('get_subdivision_types', "Subdivision Types")
    _get_types_cache = Cache('party.address.subdivision_type.get_types')

    @classmethod
    def __setup__(cls):
        super().__setup__()
        t = cls.__table__()
        cls._sql_constraints = [
            ('country_code_unique',
             Exclude(t, (t.country_code, Equal),
                     where=t.active == Literal(True)),
             'party.msg_address_subdivision_country_code_unique')
        ]
        cls._order.insert(0, ('country_code', 'ASC NULLS LAST'))

    @classmethod
    def get_subdivision_types(cls):
        pool = Pool()
        Subdivision = pool.get('country.subdivision')
        return Subdivision.fields_get(['type'])['type']['selection']

    @classmethod
    def create(cls, *args, **kwargs):
        records = super().create(*args, **kwargs)
        cls._get_types_cache.clear()
        return records

    @classmethod
    def write(cls, *args, **kwargs):
        super().write(*args, **kwargs)
        cls._get_types_cache.clear()

    @classmethod
    def delete(cls, *args, **kwargs):
        super().delete(*args, **kwargs)
        cls._get_types_cache.clear()

    @classmethod
    def get_types(cls, country):
        key = country.code if country else None
        types = cls._get_types_cache.get(key)
        if types is not None:
            return list(types)

        records = cls.search([
            ('country_code', '=', country.code if country else None),
        ])
        if records:
            record, = records
            types = record.types
        else:
            types = []

        cls._get_types_cache.set(key, types)
        return types
Beispiel #33
0
class CarrierSelection(sequence_ordered(), MatchMixin, ModelSQL, ModelView):
    'Carrier Selection'
    __name__ = 'carrier.selection'
    _get_carriers_cache = Cache('carrier.selection.get_carriers')

    active = fields.Boolean('Active')
    from_country = fields.Many2One('country.country',
                                   'From Country',
                                   ondelete='RESTRICT')
    to_country = fields.Many2One('country.country',
                                 'To Country',
                                 ondelete='RESTRICT')
    carrier = fields.Many2One('carrier',
                              'Carrier',
                              required=True,
                              ondelete='CASCADE')

    @staticmethod
    def default_active():
        return True

    @classmethod
    def create(cls, *args, **kwargs):
        selections = super(CarrierSelection, cls).create(*args, **kwargs)
        cls._get_carriers_cache.clear()
        return selections

    @classmethod
    def write(cls, *args, **kwargs):
        super(CarrierSelection, cls).write(*args, **kwargs)
        cls._get_carriers_cache.clear()

    @classmethod
    def delete(cls, *args, **kwargs):
        super(CarrierSelection, cls).delete(*args, **kwargs)
        cls._get_carriers_cache.clear()

    @classmethod
    def get_carriers(cls, pattern):
        pool = Pool()
        Carrier = pool.get('carrier')

        key = tuple(sorted(pattern.iteritems()))
        carriers = cls._get_carriers_cache.get(key)
        if carriers is not None:
            return Carrier.browse(carriers)

        carriers = []
        selections = cls.search([])
        if not selections:
            with Transaction().set_context(active_test=False):
                carriers = Carrier.search([])
        else:
            for selection in selections:
                if selection.match(pattern):
                    carriers.append(selection.carrier)

        cls._get_carriers_cache.set(key, map(int, carriers))
        return carriers
Beispiel #34
0
    def test_0040_headers(self):
        '''
        Change registrations headers and check
        '''
        trytond.tests.test_tryton.install_module('nereid_test')
        with Transaction().start(DB_NAME, USER, CONTEXT) as txn:
            self.setup_defaults()
            app = self.get_app()

            with app.test_client() as c:
                response = c.get('/test-lazy-renderer')
                self.assertEqual(response.headers['X-Test-Header'], 'TestValue')
                self.assertEqual(response.status_code, 201)

            txn.rollback()
            # Drop the cache as the transaction is rollbacked
            Cache.drop(DB_NAME)
Beispiel #35
0
    def __init__(self, database_name=None, user='******', database_type=None,
            language='en_US', password='', config_file=None):
        super(TrytondConfig, self).__init__()
        from trytond.config import CONFIG
        CONFIG.update_etc(config_file)
        CONFIG.set_timezone()
        if database_type is not None:
            CONFIG['db_type'] = database_type
        from trytond.pool import Pool
        from trytond import backend
        from trytond.protocols.dispatcher import create
        from trytond.cache import Cache
        from trytond.transaction import Transaction
        self.database_type = CONFIG['db_type']
        if database_name is None:
            if self.database_type == 'sqlite':
                database_name = ':memory:'
            else:
                database_name = 'test_%s' % int(time.time())
        self.database_name = database_name
        self._user = user
        self.config_file = config_file

        Pool.start()

        with Transaction().start(None, 0) as transaction:
            cursor = transaction.cursor
            databases = backend.get('Database').list(cursor)
        if database_name not in databases:
            create(database_name, CONFIG['admin_passwd'], language, password)

        database_list = Pool.database_list()
        self.pool = Pool(database_name)
        if database_name not in database_list:
            self.pool.init()

        with Transaction().start(self.database_name, 0) as transaction:
            Cache.clean(database_name)
            User = self.pool.get('res.user')
            transaction.context = self.context
            self.user = User.search([
                ('login', '=', user),
                ], limit=1)[0].id
            with transaction.set_user(self.user):
                self._context = User.get_preferences(context_only=True)
        Cache.resets(database_name)
Beispiel #36
0
class Employee(metaclass=PoolMeta):
    __name__ = 'company.employee'
    cost_price = fields.Function(
        fields.Numeric('Cost Price',
                       digits=price_digits,
                       help="Hourly cost price for this Employee."),
        'get_cost_price')
    cost_prices = fields.One2Many('company.employee_cost_price',
                                  'employee',
                                  'Cost Prices',
                                  help="List of hourly cost price over time.")
    _cost_prices_cache = Cache('company_employee.cost_prices')

    def get_cost_price(self, name):
        '''
        Return the cost price at the date given in the context or the
        current date
        '''
        ctx_date = Transaction().context.get('date', None)
        return self.compute_cost_price(ctx_date)

    def get_employee_costs(self):
        "Return a sorted list by date of start date and cost_price"
        pool = Pool()
        CostPrice = pool.get('company.employee_cost_price')
        # Get from cache employee costs or fetch them from the db
        employee_costs = self._cost_prices_cache.get(self.id)
        if employee_costs is None:
            cost_prices = CostPrice.search([
                ('employee', '=', self.id),
            ],
                                           order=[('date', 'ASC')])

            employee_costs = []
            for cost_price in cost_prices:
                employee_costs.append((cost_price.date, cost_price.cost_price))
            self._cost_prices_cache.set(self.id, employee_costs)
        return employee_costs

    def compute_cost_price(self, date=None):
        "Return the cost price at the given date"
        pool = Pool()
        Date = pool.get('ir.date')

        employee_costs = self.get_employee_costs()

        if date is None:
            with Transaction().set_context(company=self.company.id):
                date = Date.today()
        # compute the cost price for the given date
        cost = 0
        if employee_costs and date >= employee_costs[0][0]:
            for edate, ecost in employee_costs:
                if date >= edate:
                    cost = ecost
                else:
                    break
        return cost
Beispiel #37
0
    def wrapper(database, *args, **kwargs):
        DatabaseOperationalError = backend.get('DatabaseOperationalError')

        Cache.clean(database)

        # Intialise the pool. The init method is smart enough not to
        # reinitialise if it is already initialised.
        Pool(database).init()

        # get the context from the currently logged in user
        with Transaction().start(database, g.current_user, readonly=True):
            User = Pool().get('res.user')
            context = User.get_preferences(context_only=True)

        readonly = request.method == 'GET'

        for count in range(int(CONFIG['retry']), -1, -1):
            with Transaction().start(database,
                                     g.current_user,
                                     readonly=readonly,
                                     context=context) as transaction:
                cursor = transaction.cursor
                try:
                    result = function(*args, **kwargs)
                    if not readonly:
                        cursor.commit()
                except DatabaseOperationalError, exc:
                    cursor.rollback()
                    if count and not readonly:
                        continue
                    result = jsonify(error=unicode(exc)), 500
                except UserError, exc:
                    cursor.rollback()
                    result = jsonify(
                        error={
                            'type': 'UserError',
                            'message': exc.message,
                            'description': exc.description,
                            'code': exc.code,
                        }), 500
                    current_app.logger.error(traceback.format_exc())
                except Exception, exc:
                    cursor.rollback()
                    result = jsonify(error=unicode(exc)), 500
                    current_app.logger.error(traceback.format_exc())
Beispiel #38
0
class Selection(
        DeactivableMixin, sequence_ordered(), MatchMixin, ModelSQL, ModelView):
    'Carrier Selection'
    __name__ = 'carrier.selection'
    _get_carriers_cache = Cache(
        'carrier.selection.get_carriers', context=False)

    from_country = fields.Many2One('country.country', 'From Country',
        ondelete='RESTRICT',
        help="Apply only when shipping from this country.\n"
        "Leave empty for any countries.")
    to_country = fields.Many2One('country.country', 'To Country',
        ondelete='RESTRICT',
        help="Apply only when shipping to this country.\n"
        "Leave empty for any countries.")
    carrier = fields.Many2One('carrier', 'Carrier', required=True,
        ondelete='CASCADE', help="The selected carrier.")

    @classmethod
    def create(cls, *args, **kwargs):
        selections = super().create(*args, **kwargs)
        cls._get_carriers_cache.clear()
        return selections

    @classmethod
    def write(cls, *args, **kwargs):
        super().write(*args, **kwargs)
        cls._get_carriers_cache.clear()

    @classmethod
    def delete(cls, *args, **kwargs):
        super().delete(*args, **kwargs)
        cls._get_carriers_cache.clear()

    @classmethod
    def get_carriers(cls, pattern):
        pool = Pool()
        Carrier = pool.get('carrier')

        key = tuple(sorted(pattern.items()))
        carriers = cls._get_carriers_cache.get(key)
        if carriers is not None:
            return Carrier.browse(carriers)

        carriers = []
        selections = cls.search([])
        if not selections:
            with Transaction().set_context(active_test=False):
                carriers = Carrier.search([])
        else:
            for selection in selections:
                if (selection.match(pattern)
                        and selection.carrier not in carriers):
                    carriers.append(selection.carrier)

        cls._get_carriers_cache.set(key, list(map(int, carriers)))
        return carriers
Beispiel #39
0
    def test_0040_headers(self):
        '''
        Change registrations headers and check
        '''
        trytond.tests.test_tryton.install_module('nereid_test')
        with Transaction().start(DB_NAME, USER, CONTEXT) as txn:
            self.setup_defaults()
            app = self.get_app()

            with app.test_client() as c:
                response = c.get('/test-lazy-renderer')
                self.assertEqual(response.headers['X-Test-Header'],
                                 'TestValue')
                self.assertEqual(response.status_code, 201)

            txn.rollback()
            # Drop the cache as the transaction is rollbacked
            Cache.drop(DB_NAME)
Beispiel #40
0
 def transition_upgrade(self):
     pool = Pool()
     Module = pool.get('ir.module')
     Lang = pool.get('ir.lang')
     transaction = Transaction()
     with transaction.new_transaction():
         modules = Module.search([
             ('state', 'in', ['to upgrade', 'to remove', 'to activate']),
         ])
         update = [m.name for m in modules]
         langs = Lang.search([
             ('translatable', '=', True),
         ])
         lang = [x.code for x in langs]
     if update:
         pool.init(update=update, lang=lang)
         Cache.refresh_pool(transaction)
     return 'done'
Beispiel #41
0
 def __setup__(cls):
     super(DictSchemaMixin, cls).__setup__()
     cls.__rpc__.update({
         'get_keys': RPC(instantiate=0),
     })
     # Do not instantiate more than one Cache
     if not hasattr(cls, '_relation_fields_cache'):
         cls._relation_fields_cache = Cache(cls.__name__ +
                                            '.get_relation_fields')
    def wrapper(database, *args, **kwargs):
        DatabaseOperationalError = backend.get('DatabaseOperationalError')

        Cache.clean(database)

        # Intialise the pool. The init method is smart enough not to
        # reinitialise if it is already initialised.
        Pool(database).init()

        # get the context from the currently logged in user
        with Transaction().start(database, g.current_user, readonly=True):
            User = Pool().get('res.user')
            context = User.get_preferences(context_only=True)

        readonly = request.method == 'GET'

        for count in range(int(CONFIG['retry']), -1, -1):
            with Transaction().start(
                    database, g.current_user,
                    readonly=readonly,
                    context=context) as transaction:
                cursor = transaction.cursor
                try:
                    result = function(*args, **kwargs)
                    if not readonly:
                        cursor.commit()
                except DatabaseOperationalError, exc:
                    cursor.rollback()
                    if count and not readonly:
                        continue
                    result = jsonify(error=unicode(exc)), 500
                except UserError, exc:
                    cursor.rollback()
                    result = jsonify(error={
                        'type': 'UserError',
                        'message': exc.message,
                        'description': exc.description,
                        'code': exc.code,
                    }), 500
                    current_app.logger.error(traceback.format_exc())
                except Exception, exc:
                    cursor.rollback()
                    result = jsonify(error=unicode(exc)), 500
                    current_app.logger.error(traceback.format_exc())
Beispiel #43
0
            def wrapper(*args, **kwargs):
                _db = Tdb._db
                _readonly = True
                if readonly is not None:
                    _readonly = readonly
                elif 'request' in kwargs:
                    _readonly = not (kwargs['request'].method
                                     in ('PUT', 'POST', 'DELETE', 'PATCH'))
                _user = user or 0
                _context = {}

                _retry = Tdb._retry or 0
                _is_open = (Transaction().cursor)

                if not _is_open:
                    with Transaction().start(_db, 0):
                        Cache.clean(_db)
                        _context.update(default_context())
                else:
                    # Transaction().new_cursor(readonly=_readonly)
                    pass
                _context.update(context or {})
                # _context.update({'company': Tdb._company})

                for count in range(_retry, -1, -1):
                    with NoTransaction() if _is_open else Transaction().start(
                            _db, _user, readonly=_readonly, context=_context):
                        cursor = Transaction().cursor
                        if withhold:
                            cursor.cursor.withhold = True
                        try:
                            result = func(*args, **kwargs)
                            if not _readonly:
                                cursor.commit()
                        except DatabaseOperationalError:
                            cursor.rollback()
                            if count and not _readonly:
                                continue
                            raise
                        except Exception:
                            cursor.rollback()
                            raise
                        Cache.resets(_db)
                        return result
Beispiel #44
0
def drop(request, database_name, password):
    Database = backend.get('Database')
    security.check_super(password)
    database = Database(database_name)
    database.close()
    # Sleep to let connections close
    time.sleep(1)

    with Transaction().start(None, 0, close=True, autocommit=True) \
            as transaction:
        try:
            database.drop(transaction.connection, database_name)
        except Exception:
            logger.error('DROP DB: %s failed', database_name, exc_info=True)
            raise
        else:
            logger.info('DROP DB: %s', database_name)
            Pool.stop(database_name)
            Cache.drop(database_name)
    return True
def transaction(request):
    """Yields transaction with installed module.
    """

    # Importing transaction directly causes cyclic dependency in 3.6
    from trytond.tests.test_tryton import USER, CONTEXT, DB_NAME, POOL
    from trytond.tools.singleton import Singleton  # noqa
    from trytond.transaction import Transaction
    from trytond.cache import Cache

    # Inject helper functions in instance on which test function was collected.
    request.instance.POOL = POOL
    request.instance.USER = USER
    request.instance.CONTEXT = CONTEXT
    request.instance.DB_NAME = DB_NAME

    transaction = Transaction()

    with transaction.start(DB_NAME, USER, context=CONTEXT) as txn:
        yield txn
        transaction.rollback()
        Cache.drop(DB_NAME)
Beispiel #46
0
    def __init__(self, database=None, user='******', config_file=None):
        super(TrytondConfig, self).__init__()
        if not database:
            database = os.environ.get('TRYTOND_DATABASE_URI')
        else:
            os.environ['TRYTOND_DATABASE_URI'] = database
        if not config_file:
            config_file = os.environ.get('TRYTOND_CONFIG')
        from trytond.config import config
        config.update_etc(config_file)
        from trytond.pool import Pool
        from trytond.cache import Cache
        from trytond.transaction import Transaction
        self.database = database
        database_name = None
        if database:
            uri = urlparse.urlparse(database)
            database_name = uri.path.strip('/')
        if not database_name:
            database_name = os.environ['DB_NAME']
        self.database_name = database_name
        self._user = user
        self.config_file = config_file

        Pool.start()
        self.pool = Pool(database_name)
        self.pool.init()

        with Transaction().start(self.database_name, 0) as transaction:
            Cache.clean(database_name)
            User = self.pool.get('res.user')
            transaction.context = self.context
            self.user = User.search([
                ('login', '=', user),
                ], limit=1)[0].id
            with transaction.set_user(self.user):
                self._context = User.get_preferences(context_only=True)
            Cache.resets(database_name)
Beispiel #47
0
def execute(app, database, user, payload_json):
    """
    Execute the task identified by the given payload in the given database
    as `user`.
    """
    if database not in Pool.database_list():
        # Initialise the database if this is the first time we see the
        # database being used.
        with Transaction().start(database, 0, readonly=True):
            Pool(database).init()

    with Transaction().start(database, 0):
        Cache.clean(database)

    with Transaction().start(database, user) as transaction:
        Async = Pool().get('async.async')
        DatabaseOperationalError = backend.get('DatabaseOperationalError')

        # De-serialize the payload in the transaction context so that
        # active records are constructed in the same transaction cache and
        # context.
        payload = Async.deserialize_payload(payload_json)

        try:
            with Transaction().set_context(payload['context']):
                results = Async.execute_payload(payload)
        except RetryWithDelay, exc:
            # A special error that would be raised by Tryton models to
            # retry the task after a certain delay. Useful when the task
            # got triggered before the record is ready and similar cases.
            transaction.cursor.rollback()
            raise app.retry(exc=exc, delay=exc.delay)
        except DatabaseOperationalError, exc:
            # Strict transaction handling may cause this.
            # Rollback and Retry the whole transaction if within
            # max retries, or raise exception and quit.
            transaction.cursor.rollback()
            raise app.retry(exc=exc)
        def threaded_send_email(email, smtp_server):
            """
            A new threaded email sender. This is required because there is
            no transaction in the new thread that is spawned and sendemail
            tries to create a new cursor from an existing transaction.

            So create the new transaction here, refresh the active record
            objects and call sendmail like the cron would have
            """
            with Transaction().start(DB_NAME, USER, context=CONTEXT):
                # email active record is from old transaction, so referesh it.
                email = EmailQueue(email.id)

                database = backend.get('database')

                try:
                    # Now send the email
                    email.send(smtp_server)
                except database.DatabaseOperationalError:
                    # This specific email could not be sent because of a
                    # transaction serialization error
                    searialization_error_q.put(email.id)
                finally:
                    Cache.drop(DB_NAME)
                            UserWarning)):
                    tb_s = ''.join(traceback.format_exception(*sys.exc_info()))
                    logger = logging.getLogger('dispatcher')
                    logger.error('Exception calling method %s on '
                        '%s %s from %s@%s:%d/%s:\n'
                        % (method, object_type, object_name, user, host, port,
                            database_name) + tb_s)
                transaction.cursor.rollback()
                raise
        if not (object_name == 'res.request' and method == 'request_get'):
            with Transaction().start(database_name, 0) as transaction:
                pool = Pool(database_name)
                session_obj = pool.get('ir.session')
                session_obj.reset(session)
                transaction.cursor.commit()
        Cache.resets(database_name)
        return res


def create(database_name, password, lang, admin_password):
    '''
    Create a database

    :param database_name: the database name
    :param password: the server password
    :param lang: the default language for the database
    :param admin_password: the admin password
    :return: True if succeed
    '''
    security.check_super(password)
    res = False
    def __init__(self, database_uri=None, user='******', language='en_US',
                 admin_password='',
                 super_pwd=None,
                 config_file=None):
        OrigConfigModule.Config.__init__(self)
        # FixMe: straighten this mess out

        if config_file is None:
            config_file = os.environ.get('TRYTOND_CONFIG')
        assert config_file and os.path.isfile(config_file), \
            "Set the environment variable TRYTOND_CONFIG to the path of TRYTOND CONFIG"

        if not database_uri:
            database_uri = os.environ.get('TRYTOND_DATABASE_URI')
        else:
            os.environ['TRYTOND_DATABASE_URI'] = database_uri
        assert os.path.isfile(config_file), \
            "set os.environ.get('TRYTOND_CONFIG') to be the Tryton config file"

        from trytond.config import config
        config.update_etc(config_file)

        from trytond.pool import Pool
        from trytond import backend
        from trytond.protocols.dispatcher import create
        from trytond.cache import Cache
        from trytond.transaction import Transaction
        self.database = database_uri
        database_name = None
        if database_uri:
            uri = urlparse.urlparse(database_uri)
            database_name = uri.path.strip('/')
        if not database_name:
            assert 'DB_NAME' in os.environ, \
                "Set os.environ['DB_NAME'] to be the database name"
            database_name = os.environ['DB_NAME']
        self.database_name = database_name
        self._user = user
        self.config_file = config_file

        Pool.start()
        if False:
           # new in 3.4
            self.pool = Pool(database_name)
            self.pool.init()
        else:
            # 3.2 code created the database if it did not exist
            with Transaction().start(None, 0) as transaction:
                cursor = transaction.cursor
                databases = backend.get('Database').list(cursor)
            if database_name not in databases:
                # trytond/protocols/dispatcher.py
                '''
                Create a database

                :param database_name: the database name
                :param password: the server password
                :param lang: the default language for the database
                :param admin_password: the admin password
                :return: True if succeed
                '''
                if not super_pwd:
                    sys.stderr.write(
                        "WARN: No super_pwd to create db %s\n" % (database_name,))
                    #! This is NOT the postgres server password
                    #! This calls security.check_super(password)
                    #! which is set in the conf file, [session]super_pwd
                    #! using crypt to generate it from from the command line
                    #! We default it to admin which may also be the
                    #! of the user 'admin': admin_password
                    super_pwd = 'admin'

                assert admin_password, "ERROR: No admin_password to create db " + database_name
                sys.stderr.write(
                    "create %s %s %s %s\n" % (database_name, super_pwd, language, admin_password,))
                create(database_name, super_pwd, language, admin_password)

            database_list = Pool.database_list()
            self.pool = Pool(database_name)
            if database_name not in database_list:
                self.pool.init()

        with Transaction().start(self.database_name, 0) as transaction:
            Cache.clean(database_name)
            User = self.pool.get('res.user')
            transaction.context = self.context
            self.user = User.search([
                ('login', '=', user),
                ], limit=1)[0].id
            with transaction.set_user(self.user):
                self._context = User.get_preferences(context_only=True)
            Cache.resets(database_name)
Beispiel #51
0
    def dispatch_request(self):
        """
        Does the request dispatching.  Matches the URL and returns the
        return value of the view or error handler.  This does not have to
        be a response object.
        """
        DatabaseOperationalError = backend.get('DatabaseOperationalError')

        req = _request_ctx_stack.top.request
        if req.routing_exception is not None:
            self.raise_routing_exception(req)

        rule = req.url_rule
        # if we provide automatic options for this URL and the
        # request came with the OPTIONS method, reply automatically
        if getattr(rule, 'provide_automatic_options', False) \
           and req.method == 'OPTIONS':
            return self.make_default_options_response()

        with Transaction().start(self.database_name, 0):
            Cache.clean(self.database_name)
            Cache.resets(self.database_name)

        with Transaction().start(self.database_name, 0, readonly=True):
            user = current_website.application_user.id
            website_context = current_website.get_context()
            website_context.update({
                'company': current_website.company.id,
            })
            language = current_locale.language.code

        # pop locale if specified in the view_args
        req.view_args.pop('locale', None)
        active_id = req.view_args.pop('active_id', None)

        for count in range(int(config.get('database', 'retry')), -1, -1):
            with Transaction().start(
                    self.database_name, user,
                    context=website_context,
                    readonly=rule.is_readonly) as txn:
                try:
                    transaction_start.send(self)
                    rv = self._dispatch_request(
                        req, language=language, active_id=active_id
                    )
                    txn.commit()
                    transaction_commit.send(self)
                except DatabaseOperationalError:
                    # Strict transaction handling may cause this.
                    # Rollback and Retry the whole transaction if within
                    # max retries, or raise exception and quit.
                    txn.rollback()
                    if count:
                        continue
                    raise
                except Exception:
                    # Rollback and raise any other exception
                    txn.rollback()
                    raise
                else:
                    return rv
                finally:
                    transaction_stop.send(self)
Beispiel #52
0
    def _load_modules():
        global res
        TableHandler = backend.get("TableHandler")
        transaction = Transaction()

        with transaction.connection.cursor() as cursor:
            # Migration from 3.6: remove double module
            old_table = "ir_module_module"
            new_table = "ir_module"
            if TableHandler.table_exist(old_table):
                TableHandler.table_rename(old_table, new_table)
            if update:
                migrate_modules(cursor)

                cursor.execute(
                    *ir_module.select(
                        ir_module.name,
                        where=ir_module.state.in_(("installed", "to install", "to upgrade", "to remove")),
                    )
                )
            else:
                cursor.execute(
                    *ir_module.select(
                        ir_module.name, where=ir_module.state.in_(("installed", "to upgrade", "to remove"))
                    )
                )
            module_list = [name for (name,) in cursor.fetchall()]
            if update:
                module_list += update
            graph = create_graph(module_list)[0]

            load_module_graph(graph, pool, update, lang)

            if update:
                cursor.execute(*ir_module.select(ir_module.name, where=(ir_module.state == "to remove")))
                fetchall = cursor.fetchall()
                if fetchall:
                    for (mod_name,) in fetchall:
                        # TODO check if ressource not updated by the user
                        cursor.execute(
                            *ir_model_data.select(
                                ir_model_data.model,
                                ir_model_data.db_id,
                                where=(ir_model_data.module == mod_name),
                                order_by=ir_model_data.id.desc,
                            )
                        )
                        for rmod, rid in cursor.fetchall():
                            Model = pool.get(rmod)
                            Model.delete([Model(rid)])
                        Transaction().connection.commit()
                    cursor.execute(
                        *ir_module.update([ir_module.state], ["uninstalled"], where=(ir_module.state == "to remove"))
                    )
                    Transaction().connection.commit()
                    res = False

                Module = pool.get("ir.module")
                Module.update_list()
        # Need to commit to unlock SQLite database
        transaction.commit()
        Cache.resets(database_name)
Beispiel #53
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
Beispiel #54
0
def load_modules(database_name, pool, update=False, lang=None):
    res = True
    if not Transaction().cursor:
        contextmanager = Transaction().start(database_name, 0)
    else:
        contextmanager = contextlib.nested(Transaction().new_cursor(),
                Transaction().set_user(0),
                Transaction().reset_context())
    with contextmanager:
        cursor = Transaction().cursor
        if update:
            # Migration from 2.2: workflow module removed
            cursor.execute('DELETE FROM ir_module_module '
                'WHERE name = %s', ('workflow',))
            if 'all' in CONFIG['init']:
                cursor.execute("SELECT name FROM ir_module_module "
                    "WHERE name != \'test\'")
            else:
                cursor.execute("SELECT name FROM ir_module_module "
                    "WHERE state IN ('installed', 'to install', "
                    "'to upgrade', 'to remove')")
        else:
            cursor.execute("SELECT name FROM ir_module_module "
                "WHERE state IN ('installed', 'to upgrade', 'to remove')")
        module_list = [name for (name,) in cursor.fetchall()]
        if update:
            for module in CONFIG['init'].keys():
                if CONFIG['init'][module]:
                    module_list.append(module)
            for module in CONFIG['update'].keys():
                if CONFIG['update'][module]:
                    module_list.append(module)
        graph = create_graph(module_list)[0]

        try:
            load_module_graph(graph, pool, lang)
        except Exception:
            cursor.rollback()
            raise

        if update:
            cursor.execute("SELECT name FROM ir_module_module "
                "WHERE state IN ('to remove')")
            fetchall = cursor.fetchall()
            if fetchall:
                for (mod_name,) in fetchall:
                    #TODO check if ressource not updated by the user
                    cursor.execute('SELECT model, db_id FROM ir_model_data '
                        'WHERE module = %s '
                        'ORDER BY id DESC', (mod_name,))
                    for rmod, rid in cursor.fetchall():
                        Model = pool.get(rmod)
                        Model.delete([Model(rid)])
                    cursor.commit()
                cursor.execute("UPDATE ir_module_module SET state = %s "
                    "WHERE state IN ('to remove')", ('uninstalled',))
                cursor.commit()
                res = False

            Module = pool.get('ir.module.module')
            Module.update_list()
        cursor.commit()
    Cache.resets(database_name)
    return res
                    result = jsonify(error={
                        'type': 'UserError',
                        'message': exc.message,
                        'description': exc.description,
                        'code': exc.code,
                    }), 500
                    current_app.logger.error(traceback.format_exc())
                except Exception, exc:
                    cursor.rollback()
                    result = jsonify(error=unicode(exc)), 500
                    current_app.logger.error(traceback.format_exc())
                else:
                    if not (readonly or current_app.testing):
                        cursor.commit()

            Cache.resets(database)
            return result
    return wrapper


ar_to_dict = lambda ar: {'id': ar.id, 'rec_name': ar.rec_name}


@restful.route('/login', methods=['POST'])
def login(database):
    """
    POST: Login and return user id and session
    """
    result = security.login(
        database, request.form['login'], request.form['password']
    )
def dispatch(host, port, protocol, database_name, user, session, object_type,
        object_name, method, *args, **kargs):

    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)
            Cache.clean(database_name)
            logger = logging.getLogger('dispatcher')
            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))
            Cache.resets(database_name)
            return res or False
        elif method == 'logout':
            name = security.logout(database_name, user, session)
            logger = logging.getLogger('dispatcher')
            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 == 'timezone_get':
            return CONFIG['timezone']
        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_ES', 'Español (España)'),
                ('es_CO', 'Español (Colombia)'),
                ('fr_FR', 'Français'),
                ('nl_NL', 'Nederlands'),
                ('ru_RU', 'Russian'),
            ]
        elif method == 'db_exist':
            try:
                database = Database(*args, **kargs).connect()
                cursor = database.cursor()
                cursor.close(close=True)
                return True
            except Exception:
                return False
        elif method == 'list':
            if CONFIG['prevent_dblist']:
                raise Exception('AccessDenied')
            database = Database().connect()
            try:
                cursor = database.cursor()
                try:
                    res = database.list(cursor)
                finally:
                    cursor.close(close=True)
            except Exception:
                res = []
            return res
        elif method == 'create':
            return create(*args, **kargs)
        elif method == 'restore':
            return restore(*args, **kargs)
        elif method == 'drop':
            return drop(*args, **kargs)
        elif method == 'dump':
            return dump(*args, **kargs)
        return
    elif object_type == 'system':
        database = Database(database_name).connect()
        database_list = Pool.database_list()
        pool = Pool(database_name)
        if not database_name 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))

    user = security.check(database_name, user, session)

    Cache.clean(database_name)
    database_list = Pool.database_list()
    pool = Pool(database_name)
    if not database_name 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:
        readonly = not obj._rpc[method]
    elif method in getattr(obj, '_buttons', {}):
        readonly = False
    else:
        raise UserError('Calling method %s on %s %s is not allowed!'
            % (method, object_type, object_name))

    for count in range(int(CONFIG['retry']), -1, -1):
        with Transaction().start(database_name, user,
                readonly=readonly) as transaction:
            try:

                args_without_context = list(args)
                if 'context' in kargs:
                    context = kargs.pop('context')
                else:
                    context = args_without_context.pop()
                if '_timestamp' in context:
                    transaction.timestamp = context['_timestamp']
                    del context['_timestamp']
                transaction.context = context
                res = getattr(obj, method)(*args_without_context, **kargs)
                if not readonly:
                    transaction.cursor.commit()
            except DatabaseOperationalError, exception:
                transaction.cursor.rollback()
                if count and not readonly:
                    continue
                raise
            except Exception, exception:
                if CONFIG['verbose'] and not isinstance(exception, (
                            NotLogged, ConcurrencyException, UserError,
                            UserWarning)):
                    tb_s = ''.join(traceback.format_exception(*sys.exc_info()))
                    logger = logging.getLogger('dispatcher')
                    logger.error('Exception calling method %s on '
                        '%s %s from %s@%s:%d/%s:\n'
                        % (method, object_type, object_name, user, host, port,
                            database_name) + tb_s)
                transaction.cursor.rollback()
                raise
Beispiel #57
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