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)
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)
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)
def _dispatch(request, pool, *args, **kwargs): DatabaseOperationalError = backend.get('DatabaseOperationalError') obj, method = get_object_method(request, pool) if method in obj.__rpc__: rpc = obj.__rpc__[method] else: raise UserError('Calling method %s on %s is not allowed' % (method, obj)) log_message = '%s.%s(*%s, **%s) from %s@%s/%s' log_args = (obj, method, args, kwargs, request.authorization.username, request.remote_addr, request.path) logger.info(log_message, *log_args) user = request.user_id for count in range(config.getint('database', 'retry'), -1, -1): with Transaction().start(pool.database_name, user, readonly=rpc.readonly) as transaction: Cache.clean(pool.database_name) try: c_args, c_kwargs, transaction.context, transaction.timestamp \ = rpc.convert(obj, *args, **kwargs) meth = getattr(obj, method) if (rpc.instantiate is None or not is_instance_method(obj, method)): result = rpc.result(meth(*c_args, **c_kwargs)) else: assert rpc.instantiate == 0 inst = c_args.pop(0) if hasattr(inst, method): result = rpc.result(meth(inst, *c_args, **c_kwargs)) else: result = [rpc.result(meth(i, *c_args, **c_kwargs)) for i in inst] except DatabaseOperationalError: if count and not rpc.readonly: transaction.rollback() continue logger.error(log_message, *log_args, exc_info=True) raise except (ConcurrencyException, UserError, UserWarning): logger.debug(log_message, *log_args, exc_info=True) raise except Exception: logger.error(log_message, *log_args, exc_info=True) raise # Need to commit to unlock SQLite database transaction.commit() Cache.resets(pool.database_name) if request.authorization.type == 'session': try: with Transaction().start(pool.database_name, 0) as transaction: Session = pool.get('ir.session') Session.reset(request.authorization.get('session')) except DatabaseOperationalError: logger.debug('Reset session failed', exc_info=True) logger.debug('Result: %s', result) return result
def 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)
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
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)
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)
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)
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)
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
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
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()
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
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()
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)
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)
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)
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)
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)
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)
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
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)
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)
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)
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)
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()
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
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()
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
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
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)
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)
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
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())
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
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'
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())
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
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)
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)
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)
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)
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)
def dispatch(host, port, protocol, database_name, user, session, object_type, object_name, method, *args, **kwargs): Database = backend.get('Database') DatabaseOperationalError = backend.get('DatabaseOperationalError') if object_type == 'common': if method == 'login': try: database = Database(database_name).connect() cursor = database.cursor() cursor.close() except Exception: return False res = security.login(database_name, user, session) with Transaction().start(database_name, 0): Cache.clean(database_name) Cache.resets(database_name) msg = res and 'successful login' or 'bad login or password' logger.info('%s \'%s\' from %s:%d using %s on database \'%s\'', msg, user, host, port, protocol, database_name) return res or False elif method == 'logout': name = security.logout(database_name, user, session) logger.info('logout \'%s\' from %s:%d ' 'using %s on database \'%s\'', name, host, port, protocol, database_name) return True elif method == 'version': return __version__ elif method == 'list_lang': return [ ('bg_BG', 'Български'), ('ca_ES', 'Català'), ('cs_CZ', 'Čeština'), ('de_DE', 'Deutsch'), ('en_US', 'English'), ('es_AR', 'Español (Argentina)'), ('es_EC', 'Español (Ecuador)'), ('es_ES', 'Español (España)'), ('es_CO', 'Español (Colombia)'), ('es_MX', 'Español (México)'), ('fr_FR', 'Français'), ('hu_HU', 'Magyar'), ('it_IT', 'Italiano'), ('lt_LT', 'Lietuvių'), ('nl_NL', 'Nederlands'), ('pt_BR', 'Português (Brasil)'), ('ru_RU', 'Russian'), ('sl_SI', 'Slovenščina'), ] elif method == 'db_exist': try: database = Database(*args, **kwargs).connect() cursor = database.cursor() cursor.close(close=True) return True except Exception: return False elif method == 'list': if not config.getboolean('database', 'list'): raise Exception('AccessDenied') with Transaction().start(None, 0, close=True) as transaction: return transaction.database.list(transaction.cursor) elif method == 'create': return create(*args, **kwargs) elif method == 'restore': return restore(*args, **kwargs) elif method == 'drop': return drop(*args, **kwargs) elif method == 'dump': return dump(*args, **kwargs) return elif object_type == 'system': database = Database(database_name).connect() database_list = Pool.database_list() pool = Pool(database_name) if database_name not in database_list: pool.init() if method == 'listMethods': res = [] for type in ('model', 'wizard', 'report'): for object_name, obj in pool.iterobject(type=type): for method in obj.__rpc__: res.append(type + '.' + object_name + '.' + method) return res elif method == 'methodSignature': return 'signatures not supported' elif method == 'methodHelp': res = [] args_list = args[0].split('.') object_type = args_list[0] object_name = '.'.join(args_list[1:-1]) method = args_list[-1] obj = pool.get(object_name, type=object_type) return pydoc.getdoc(getattr(obj, method)) for count in range(config.getint('database', 'retry'), -1, -1): try: user = security.check(database_name, user, session) except DatabaseOperationalError: if count: continue raise break database_list = Pool.database_list() pool = Pool(database_name) if database_name not in database_list: with Transaction().start(database_name, user, readonly=True) as transaction: pool.init() obj = pool.get(object_name, type=object_type) if method in obj.__rpc__: rpc = obj.__rpc__[method] else: raise UserError('Calling method %s on %s %s is not allowed!' % (method, object_type, object_name)) log_message = '%s.%s.%s(*%s, **%s) from %s@%s:%d/%s' log_args = (object_type, object_name, method, args, kwargs, user, host, port, database_name) logger.info(log_message, *log_args) for count in range(config.getint('database', 'retry'), -1, -1): with Transaction().start(database_name, user, readonly=rpc.readonly) as transaction: Cache.clean(database_name) try: c_args, c_kwargs, transaction.context, transaction.timestamp \ = rpc.convert(obj, *args, **kwargs) meth = getattr(obj, method) if (rpc.instantiate is None or not is_instance_method(obj, method)): result = rpc.result(meth(*c_args, **c_kwargs)) else: assert rpc.instantiate == 0 inst = c_args.pop(0) if hasattr(inst, method): result = rpc.result(meth(inst, *c_args, **c_kwargs)) else: result = [rpc.result(meth(i, *c_args, **c_kwargs)) for i in inst] if not rpc.readonly: transaction.cursor.commit() except DatabaseOperationalError: transaction.cursor.rollback() if count and not rpc.readonly: continue raise except (NotLogged, ConcurrencyException, UserError, UserWarning): logger.debug(log_message, *log_args, exc_info=True) transaction.cursor.rollback() raise except Exception: logger.error(log_message, *log_args, exc_info=True) transaction.cursor.rollback() raise Cache.resets(database_name) with Transaction().start(database_name, 0) as transaction: pool = Pool(database_name) Session = pool.get('ir.session') try: Session.reset(session) except DatabaseOperationalError: logger.debug('Reset session failed', exc_info=True) # Silently fail when reseting session transaction.cursor.rollback() else: transaction.cursor.commit() logger.debug('Result: %s', result) return result
def 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
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