Exemplo n.º 1
0
    def poll(self, dbname, channels, last, options=None, timeout=TIMEOUT):
        if options is None:
            options = {}
        # Dont hang ctrl-c for a poll request, we need to bypass private
        # attribute access because we dont know before starting the thread that
        # it will handle a longpolling request
        if not eagle.evented:
            current = threading.current_thread()
            current._Thread__daemonic = True # PY2
            current._daemonic = True         # PY3
            # rename the thread to avoid tests waiting for a longpolling
            current.setName("openerp.longpolling.request.%s" % current.ident)

        registry = eagle.registry(dbname)

        # immediatly returns if past notifications exist
        with registry.cursor() as cr:
            env = api.Environment(cr, SUPERUSER_ID, {})
            notifications = env['bus.bus'].poll(channels, last, options)

        # immediatly returns in peek mode
        if options.get('peek'):
            return dict(notifications=notifications, channels=channels)

        # or wait for future ones
        if not notifications:
            if not self.started:
                # Lazy start of events listener
                self.start()

            event = self.Event()
            for channel in channels:
                self.channels.setdefault(hashable(channel), set()).add(event)
            try:
                event.wait(timeout=timeout)
                with registry.cursor() as cr:
                    env = api.Environment(cr, SUPERUSER_ID, {})
                    notifications = env['bus.bus'].poll(channels, last, options, force_status=True)
            except Exception:
                # timeout
                pass
            finally:
                # gc pointers to event
                for channel in channels:
                    channel_events = self.channels.get(hashable(channel))
                    if channel_events and event in channel_events:
                        channel_events.remove(event)
        return notifications
Exemplo n.º 2
0
    def _handle_exception(cls, exception):
        is_frontend_request = bool(getattr(request, 'is_frontend', False))
        if not is_frontend_request:
            # Don't touch non frontend requests exception handling
            return super(IrHttp, cls)._handle_exception(exception)
        try:
            response = super(IrHttp, cls)._handle_exception(exception)

            if isinstance(response, Exception):
                exception = response
            else:
                # if parent excplicitely returns a plain response, then we don't touch it
                return response
        except Exception as e:
            if 'werkzeug' in config['dev_mode']:
                raise e
            exception = e

        code, values = cls._get_exception_code_values(exception)

        if code is None:
            # Hand-crafted HTTPException likely coming from abort(),
            # usually for a redirect response -> return it directly
            return exception

        if not request.uid:
            cls._auth_method_public()
        with registry(request.env.cr.dbname).cursor() as cr:
            env = api.Environment(cr, request.uid, request.env.context)
            if code == 500:
                _logger.error("500 Internal Server Error:\n\n%s",
                              values['traceback'])
                values = cls._get_values_500_error(env, values, exception)
            elif code == 403:
                _logger.warn("403 Forbidden:\n\n%s", values['traceback'])
            elif code == 400:
                _logger.warn("400 Bad Request:\n\n%s", values['traceback'])
            try:
                html = cls._get_error_html(env, code, values)
            except Exception:
                html = env['ir.ui.view'].render_template(
                    'http_routing.http_error', values)

        return werkzeug.wrappers.Response(
            html, status=code, content_type='text/html;charset=utf-8')
Exemplo n.º 3
0
    def run_scheduler(self, use_new_cursor=False, company_id=False):
        """ Call the scheduler in order to check the running procurements (super method), to check the minimum stock rules
        and the availability of moves. This function is intended to be run for all the companies at the same time, so
        we run functions as SUPERUSER to avoid intercompanies and access rights issues. """
        try:
            if use_new_cursor:
                cr = registry(self._cr.dbname).cursor()
                self = self.with_env(self.env(cr=cr))  # TDE FIXME

            self._run_scheduler_tasks(use_new_cursor=use_new_cursor,
                                      company_id=company_id)
        finally:
            if use_new_cursor:
                try:
                    self._cr.close()
                except Exception:
                    pass
        return {}
Exemplo n.º 4
0
    def oauth2callback(self, **kw):
        """ This route/function is called by Google when user Accept/Refuse the consent of Google """
        state = json.loads(kw['state'])
        dbname = state.get('d')
        service = state.get('s')
        url_return = state.get('f')

        with registry(dbname).cursor() as cr:
            if kw.get('code'):
                request.env(cr, request.session.uid)['google.%s' %
                                                     service].set_all_tokens(
                                                         kw['code'])
                return redirect(url_return)
            elif kw.get('error'):
                return redirect("%s%s%s" %
                                (url_return, "?error=", kw['error']))
            else:
                return redirect("%s%s" % (url_return, "?error=Unknown_error"))
Exemplo n.º 5
0
 def shell(self, dbname):
     local_vars = {
         'openerp': eagle,
         'eagle': eagle,
     }
     with eagle.api.Environment.manage():
         if dbname:
             registry = eagle.registry(dbname)
             with registry.cursor() as cr:
                 uid = eagle.SUPERUSER_ID
                 ctx = eagle.api.Environment(cr, uid, {})['res.users'].context_get()
                 env = eagle.api.Environment(cr, uid, ctx)
                 local_vars['env'] = env
                 local_vars['self'] = env.user
                 self.console(local_vars)
                 cr.rollback()
         else:
             self.console(local_vars)
Exemplo n.º 6
0
def dispatch(method, params):
    (db, uid, passwd ) = params[0], int(params[1]), params[2]

    # set uid tracker - cleaned up at the WSGI
    # dispatching phase in eagle.service.wsgi_server.application
    threading.current_thread().uid = uid

    params = params[3:]
    if method == 'obj_list':
        raise NameError("obj_list has been discontinued via RPC as of 6.0, please query ir.model directly!")
    if method not in ['execute', 'execute_kw']:
        raise NameError("Method not available %s" % method)
    security.check(db,uid,passwd)
    registry = eagle.registry(db).check_signaling()
    fn = globals()[method]
    with registry.manage_changes():
        res = fn(db, uid, *params)
    return res
Exemplo n.º 7
0
    def _login(cls, db, login, password):
        try:
            return super(Users, cls)._login(db, login, password)
        except AccessDenied as e:
            with registry(db).cursor() as cr:
                cr.execute("SELECT id FROM res_users WHERE lower(login)=%s",
                           (login, ))
                res = cr.fetchone()
                if res:
                    raise e

                env = api.Environment(cr, SUPERUSER_ID, {})
                Ldap = env['res.company.ldap']
                for conf in Ldap._get_ldap_dicts():
                    entry = Ldap._authenticate(conf, login, password)
                    if entry:
                        return Ldap._get_or_create_user(conf, login, entry)
                raise e
Exemplo n.º 8
0
    def _refresh_google_token_json(
            self, refresh_token,
            service):  # exchange_AUTHORIZATION vs Token (service = calendar)
        get_param = self.env['ir.config_parameter'].sudo().get_param
        client_id = get_param('google_%s_client_id' % (service, ),
                              default=False)
        client_secret = get_param('google_%s_client_secret' % (service, ),
                                  default=False)

        if not client_id or not client_secret:
            raise UserError(
                _("The account for the Google service '%s' is not configured.")
                % service)

        headers = {"content-type": "application/x-www-form-urlencoded"}
        data = {
            'refresh_token': refresh_token,
            'client_id': client_id,
            'client_secret': client_secret,
            'grant_type': 'refresh_token',
        }

        try:
            dummy, response, dummy = self._do_request(GOOGLE_TOKEN_ENDPOINT,
                                                      params=data,
                                                      headers=headers,
                                                      type='POST',
                                                      preuri='')
            return response
        except requests.HTTPError as error:
            if error.response.status_code == 400:  # invalid grant
                with registry(request.session.db).cursor() as cur:
                    self.env(cur)['res.users'].browse(
                        self.env.uid).sudo().write(
                            {'google_%s_rtoken' % service: False})
            error_key = error.response.json().get("error", "nc")
            _logger.exception("Bad google request : %s !", error_key)
            error_msg = _(
                "Something went wrong during your token generation. Maybe your Authorization Code is invalid or already expired [%s]"
            ) % error_key
            raise self.env['res.config.settings'].get_config_warning(error_msg)
Exemplo n.º 9
0
    def log_xml(self, xml_string, func):
        self.ensure_one()

        if self.debug_logging:
            db_name = self._cr.dbname

            # Use a new cursor to avoid rollback that could be caused by an upper method
            try:
                db_registry = registry(db_name)
                with db_registry.cursor() as cr:
                    env = api.Environment(cr, SUPERUSER_ID, {})
                    IrLogging = env['ir.logging']
                    IrLogging.sudo().create({'name': 'delivery.carrier',
                              'type': 'server',
                              'dbname': db_name,
                              'level': 'DEBUG',
                              'message': xml_string,
                              'path': self.delivery_type,
                              'func': func,
                              'line': 1})
            except psycopg2.Error:
                pass
Exemplo n.º 10
0
    def _auth_method_calendar(cls):
        token = request.params['token']
        dbname = request.params['db']

        registry = eagle.registry(dbname)
        error_message = False
        with registry.cursor() as cr:
            env = Environment(cr, SUPERUSER_ID, {})

            attendee = env['calendar.attendee'].sudo().search(
                [('access_token', '=', token)], limit=1)
            if not attendee:
                error_message = """Invalid Invitation Token."""
            elif request.session.uid and request.session.login != 'anonymous':
                # if valid session but user is not match
                user = env['res.users'].sudo().browse(request.session.uid)
                if attendee.partner_id != user.partner_id:
                    error_message = """Invitation cannot be forwarded via email. This event/meeting belongs to %s and you are logged in as %s. Please ask organizer to add you.""" % (
                        attendee.email, user.email)
        if error_message:
            raise BadRequest(error_message)

        return True
Exemplo n.º 11
0
def email_send(email_from,
               email_to,
               subject,
               body,
               email_cc=None,
               email_bcc=None,
               reply_to=False,
               attachments=None,
               message_id=None,
               references=None,
               openobject_id=False,
               debug=False,
               subtype='plain',
               headers=None,
               smtp_server=None,
               smtp_port=None,
               ssl=False,
               smtp_user=None,
               smtp_password=None,
               cr=None,
               uid=None):
    """Low-level function for sending an email (deprecated).

    :deprecate: since OpenERP 6.1, please use ir.mail_server.send_email() instead.
    :param email_from: A string used to fill the `From` header, if falsy,
                       config['email_from'] is used instead.  Also used for
                       the `Reply-To` header if `reply_to` is not provided
    :param email_to: a sequence of addresses to send the mail to.
    """

    # If not cr, get cr from current thread database
    local_cr = None
    if not cr:
        db_name = getattr(threading.currentThread(), 'dbname', None)
        if db_name:
            local_cr = cr = eagle.registry(db_name).cursor()
        else:
            raise Exception(
                "No database cursor found, please pass one explicitly")

    # Send Email
    try:
        mail_server_pool = eagle.registry(cr.dbname)['ir.mail_server']
        res = False
        # Pack Message into MIME Object
        email_msg = mail_server_pool.build_email(email_from,
                                                 email_to,
                                                 subject,
                                                 body,
                                                 email_cc,
                                                 email_bcc,
                                                 reply_to,
                                                 attachments,
                                                 message_id,
                                                 references,
                                                 openobject_id,
                                                 subtype,
                                                 headers=headers)

        res = mail_server_pool.send_email(
            cr,
            uid or 1,
            email_msg,
            mail_server_id=None,
            smtp_server=smtp_server,
            smtp_port=smtp_port,
            smtp_user=smtp_user,
            smtp_password=smtp_password,
            smtp_encryption=('ssl' if ssl else None),
            smtp_debug=debug)
    except Exception:
        _logger.exception("tools.email_send failed to deliver email")
        return False
    finally:
        if local_cr:
            cr.close()
    return res
Exemplo n.º 12
0
    def wrapper(___dbname, *args, **kwargs):
        """ Wraps around OSV functions and normalises a few exceptions
        """
        dbname = ___dbname  # NOTE: this forbid to use "___dbname" as arguments in http routes

        def tr(src, ttype):
            # We try to do the same as the _(), but without the frame
            # inspection, since we aready are wrapping an osv function
            # trans_obj = self.get('ir.translation') cannot work yet :(
            ctx = {}
            if not kwargs:
                if args and isinstance(args[-1], dict):
                    ctx = args[-1]
            elif isinstance(kwargs, dict):
                if 'context' in kwargs:
                    ctx = kwargs['context']
                elif 'kwargs' in kwargs and kwargs['kwargs'].get('context'):
                    # http entry points such as call_kw()
                    ctx = kwargs['kwargs'].get('context')
                else:
                    try:
                        from eagle.http import request
                        ctx = request.env.context
                    except Exception:
                        pass

            lang = ctx and ctx.get('lang')
            if not (lang or hasattr(src, '__call__')):
                return src

            # We open a *new* cursor here, one reason is that failed SQL
            # queries (as in IntegrityError) will invalidate the current one.
            cr = False

            try:
                cr = eagle.sql_db.db_connect(dbname).cursor()
                res = translate(cr,
                                name=False,
                                source_type=ttype,
                                lang=lang,
                                source=src)
                if res:
                    return res
                else:
                    return src
            finally:
                if cr: cr.close()

        def _(src):
            return tr(src, 'code')

        tries = 0
        while True:
            try:
                if eagle.registry(dbname)._init and not eagle.tools.config[
                        'test_enable']:
                    raise eagle.exceptions.Warning(
                        'Currently, this database is not fully loaded and can not be used.'
                    )
                return f(dbname, *args, **kwargs)
            except (OperationalError, QWebException) as e:
                if isinstance(e, QWebException):
                    cause = e.qweb.get('cause')
                    if isinstance(cause, OperationalError):
                        e = cause
                    else:
                        raise
                # Automatically retry the typical transaction serialization errors
                if e.pgcode not in PG_CONCURRENCY_ERRORS_TO_RETRY:
                    raise
                if tries >= MAX_TRIES_ON_CONCURRENCY_FAILURE:
                    _logger.info("%s, maximum number of tries reached" %
                                 errorcodes.lookup(e.pgcode))
                    raise
                wait_time = random.uniform(0.0, 2**tries)
                tries += 1
                _logger.info("%s, retry %d/%d in %.04f sec..." %
                             (errorcodes.lookup(e.pgcode), tries,
                              MAX_TRIES_ON_CONCURRENCY_FAILURE, wait_time))
                time.sleep(wait_time)
            except IntegrityError as inst:
                registry = eagle.registry(dbname)
                for key in registry._sql_error.keys():
                    if key in inst.pgerror:
                        raise ValidationError(
                            tr(registry._sql_error[key], 'sql_constraint')
                            or inst.pgerror)
                if inst.pgcode in (errorcodes.NOT_NULL_VIOLATION,
                                   errorcodes.FOREIGN_KEY_VIOLATION,
                                   errorcodes.RESTRICT_VIOLATION):
                    msg = _('The operation cannot be completed:')
                    _logger.debug("IntegrityError", exc_info=True)
                    try:
                        # Get corresponding model and field
                        model = field = None
                        for name, rclass in registry.items():
                            if inst.diag.table_name == rclass._table:
                                model = rclass
                                field = model._fields.get(
                                    inst.diag.column_name)
                                break
                        if inst.pgcode == errorcodes.NOT_NULL_VIOLATION:
                            # This is raised when a field is set with `required=True`. 2 cases:
                            # - Create/update: a mandatory field is not set.
                            # - Delete: another model has a not nullable using the deleted record.
                            msg += '\n'
                            msg += _(
                                '- Create/update: a mandatory field is not set.\n'
                                '- Delete: another model requires the record being deleted. If possible, archive it instead.'
                            )
                            if model:
                                msg += '\n\n{} {} ({}), {} {} ({})'.format(
                                    _('Model:'),
                                    model._description,
                                    model._name,
                                    _('Field:'),
                                    field.string if field else _('Unknown'),
                                    field.name if field else _('Unknown'),
                                )
                        elif inst.pgcode == errorcodes.FOREIGN_KEY_VIOLATION:
                            # This is raised when a field is set with `ondelete='restrict'`, at
                            # unlink only.
                            msg += _(
                                ' another model requires the record being deleted. If possible, archive it instead.'
                            )
                            constraint = inst.diag.constraint_name
                            if model or constraint:
                                msg += '\n\n{} {} ({}), {} {}'.format(
                                    _('Model:'),
                                    model._description
                                    if model else _('Unknown'),
                                    model._name if model else _('Unknown'),
                                    _('Constraint:'),
                                    constraint if constraint else _('Unknown'),
                                )
                    except Exception:
                        pass
                    raise ValidationError(msg)
                else:
                    raise ValidationError(inst.args[0])
Exemplo n.º 13
0
def check(db, uid, passwd):
    res_users = eagle.registry(db)['res.users']
    if res_users and not passwd:
        return res_users.check_withou_password(db, uid, passwd)
    return res_users.check(db, uid, passwd)
Exemplo n.º 14
0
def registry():
    return eagle.registry(common.get_db_name())
Exemplo n.º 15
0
    def _procure_orderpoint_confirm(self,
                                    use_new_cursor=False,
                                    company_id=False):
        """ Create procurements based on orderpoints.
        :param bool use_new_cursor: if set, use a dedicated cursor and auto-commit after processing
            1000 orderpoints.
            This is appropriate for batch jobs only.
        """
        if company_id and self.env.company.id != company_id:
            # To ensure that the company_id is taken into account for
            # all the processes triggered by this method
            # i.e. If a PO is generated by the run of the procurements the
            # sequence to use is the one for the specified company not the
            # one of the user's company
            self = self.with_context(company_id=company_id,
                                     force_company=company_id)
        OrderPoint = self.env['stock.warehouse.orderpoint']
        domain = self._get_orderpoint_domain(company_id=company_id)
        orderpoints_noprefetch = OrderPoint.with_context(
            prefetch_fields=False).search(
                domain,
                order=self._procurement_from_orderpoint_get_order()).ids
        while orderpoints_noprefetch:
            if use_new_cursor:
                cr = registry(self._cr.dbname).cursor()
                self = self.with_env(self.env(cr=cr))
            OrderPoint = self.env['stock.warehouse.orderpoint']

            orderpoints = OrderPoint.browse(orderpoints_noprefetch[:1000])
            orderpoints_noprefetch = orderpoints_noprefetch[1000:]

            # Calculate groups that can be executed together
            location_data = OrderedDict()

            def makedefault():
                return {
                    'products': self.env['product.product'],
                    'orderpoints': self.env['stock.warehouse.orderpoint'],
                    'groups': []
                }

            for orderpoint in orderpoints:
                key = self._procurement_from_orderpoint_get_grouping_key(
                    [orderpoint.id])
                if not location_data.get(key):
                    location_data[key] = makedefault()
                location_data[key]['products'] += orderpoint.product_id
                location_data[key]['orderpoints'] += orderpoint
                location_data[key][
                    'groups'] = self._procurement_from_orderpoint_get_groups(
                        [orderpoint.id])

            for location_id, location_data in location_data.items():
                location_orderpoints = location_data['orderpoints']
                product_context = dict(
                    self._context,
                    location=location_orderpoints[0].location_id.id)
                substract_quantity = location_orderpoints._quantity_in_progress(
                )

                for group in location_data['groups']:
                    if group.get('from_date'):
                        product_context['from_date'] = group[
                            'from_date'].strftime(
                                DEFAULT_SERVER_DATETIME_FORMAT)
                    if group['to_date']:
                        product_context['to_date'] = group['to_date'].strftime(
                            DEFAULT_SERVER_DATETIME_FORMAT)
                    product_quantity = location_data['products'].with_context(
                        product_context)._product_available()
                    for orderpoint in location_orderpoints:
                        try:
                            op_product_virtual = product_quantity[
                                orderpoint.product_id.id]['virtual_available']
                            if op_product_virtual is None:
                                continue
                            if float_compare(op_product_virtual,
                                             orderpoint.product_min_qty,
                                             precision_rounding=orderpoint.
                                             product_uom.rounding) <= 0:
                                qty = max(orderpoint.product_min_qty,
                                          orderpoint.product_max_qty
                                          ) - op_product_virtual
                                remainder = orderpoint.qty_multiple > 0 and qty % orderpoint.qty_multiple or 0.0

                                if float_compare(remainder,
                                                 0.0,
                                                 precision_rounding=orderpoint.
                                                 product_uom.rounding) > 0:
                                    qty += orderpoint.qty_multiple - remainder

                                if float_compare(qty,
                                                 0.0,
                                                 precision_rounding=orderpoint.
                                                 product_uom.rounding) < 0:
                                    continue

                                qty -= substract_quantity[orderpoint.id]
                                qty_rounded = float_round(
                                    qty,
                                    precision_rounding=orderpoint.product_uom.
                                    rounding)
                                if qty_rounded > 0:
                                    values = orderpoint._prepare_procurement_values(
                                        qty_rounded,
                                        **group['procurement_values'])
                                    try:
                                        with self._cr.savepoint():
                                            #TODO: make it batch
                                            self.env['procurement.group'].run([
                                                self.env['procurement.group'].
                                                Procurement(
                                                    orderpoint.product_id,
                                                    qty_rounded,
                                                    orderpoint.product_uom,
                                                    orderpoint.location_id,
                                                    orderpoint.name,
                                                    orderpoint.name,
                                                    orderpoint.company_id,
                                                    values)
                                            ])
                                    except UserError as error:
                                        self.env[
                                            'stock.rule']._log_next_activity(
                                                orderpoint.product_id,
                                                error.name)
                                    self._procurement_from_orderpoint_post_process(
                                        [orderpoint.id])
                                if use_new_cursor:
                                    cr.commit()

                        except OperationalError:
                            if use_new_cursor:
                                orderpoints_noprefetch += [orderpoint.id]
                                cr.rollback()
                                continue
                            else:
                                raise

            try:
                if use_new_cursor:
                    cr.commit()
            except OperationalError:
                if use_new_cursor:
                    cr.rollback()
                    continue
                else:
                    raise

            if use_new_cursor:
                cr.commit()
                cr.close()

        return {}
Exemplo n.º 16
0
def check(db, uid, passwd):
    res_users = eagle.registry(db)['res.users']
    return res_users.check(db, uid, passwd)
Exemplo n.º 17
0
def migrate(cr, version):
    registry = eagle.registry(cr.dbname)
    from eagle.addons.account.models.chart_template import migrate_tags_on_taxes
    migrate_tags_on_taxes(cr, registry)
Exemplo n.º 18
0
def login(db, login, password):
    res_users = eagle.registry(db)['res.users']
    try:
        return res_users._login(db, login, password)
    except eagle.exceptions.AccessDenied:
        return False
Exemplo n.º 19
0
def load_module_graph(cr,
                      graph,
                      status=None,
                      perform_checks=True,
                      skip_modules=None,
                      report=None,
                      models_to_check=None):
    """Migrates+Updates or Installs all module nodes from ``graph``
       :param graph: graph of module nodes to load
       :param status: deprecated parameter, unused, left to avoid changing signature in 8.0
       :param perform_checks: whether module descriptors should be checked for validity (prints warnings
                              for same cases)
       :param skip_modules: optional list of module names (packages) which have previously been loaded and can be skipped
       :return: list of modules that were installed or updated
    """
    def load_test(idref, mode):
        cr.execute("SAVEPOINT load_test_data_file")
        try:
            load_data(cr, idref, mode, 'test', package, report)
            return True
        except Exception:
            _test_logger.exception(
                'module %s: an exception occurred in a test', package.name)
            return False
        finally:
            cr.execute("ROLLBACK TO SAVEPOINT load_test_data_file")
            # avoid keeping stale xml_id, etc. in cache
            eagle.registry(cr.dbname).clear_caches()

    if models_to_check is None:
        models_to_check = set()

    processed_modules = []
    loaded_modules = []
    registry = eagle.registry(cr.dbname)
    migrations = eagle.modules.migration.MigrationManager(cr, graph)
    module_count = len(graph)
    _logger.info('loading %d modules...', module_count)

    # register, instantiate and initialize models for each modules
    t0 = time.time()
    t0_sql = eagle.sql_db.sql_counter

    models_updated = set()

    for index, package in enumerate(graph, 1):
        module_name = package.name
        module_id = package.id

        if skip_modules and module_name in skip_modules:
            continue

        _logger.debug('loading module %s (%d/%d)', module_name, index,
                      module_count)

        needs_update = (hasattr(package, "init") or hasattr(package, "update")
                        or package.state in ("to install", "to upgrade"))
        if needs_update:
            if package.name != 'base':
                registry.setup_models(cr)
            migrations.migrate_module(package, 'pre')

        load_openerp_module(package.name)

        new_install = package.state == 'to install'
        if new_install:
            py_module = sys.modules['eagle.addons.%s' % (module_name, )]
            pre_init = package.info.get('pre_init_hook')
            if pre_init:
                getattr(py_module, pre_init)(cr)

        model_names = registry.load(cr, package)

        loaded_modules.append(package.name)
        if needs_update:
            models_updated |= set(model_names)
            models_to_check -= set(model_names)
            registry.setup_models(cr)
            registry.init_models(cr, model_names, {'module': package.name})
        elif package.state != 'to remove':
            # The current module has simply been loaded. The models extended by this module
            # and for which we updated the schema, must have their schema checked again.
            # This is because the extension may have changed the model,
            # e.g. adding required=True to an existing field, but the schema has not been
            # updated by this module because it's not marked as 'to upgrade/to install'.
            models_to_check |= set(model_names) & models_updated

        idref = {}

        mode = 'update'
        if hasattr(package, 'init') or package.state == 'to install':
            mode = 'init'

        if needs_update:
            env = api.Environment(cr, SUPERUSER_ID, {})
            # Can't put this line out of the loop: ir.module.module will be
            # registered by init_models() above.
            module = env['ir.module.module'].browse(module_id)

            if perform_checks:
                module._check()

            if package.state == 'to upgrade':
                # upgrading the module information
                module.write(module.get_values_from_terp(package.data))
            load_data(cr,
                      idref,
                      mode,
                      kind='data',
                      package=package,
                      report=report)
            demo_loaded = package.dbdemo = load_demo(cr, package, idref, mode,
                                                     report)
            cr.execute('update ir_module_module set demo=%s where id=%s',
                       (demo_loaded, module_id))
            module.invalidate_cache(['demo'])

            migrations.migrate_module(package, 'post')

            # Update translations for all installed languages
            overwrite = eagle.tools.config["overwrite_existing_translations"]
            module.with_context(overwrite=overwrite)._update_translations()

            if package.name is not None:
                registry._init_modules.add(package.name)

            if new_install:
                post_init = package.info.get('post_init_hook')
                if post_init:
                    getattr(py_module, post_init)(cr, registry)

            if mode == 'update':
                # validate the views that have not been checked yet
                env['ir.ui.view']._validate_module_views(module_name)

            # need to commit any modification the module's installation or
            # update made to the schema or data so the tests can run
            # (separately in their own transaction)
            cr.commit()
            if demo_loaded:
                # launch tests only in demo mode, allowing tests to use demo data.
                if tools.config.options['test_enable']:
                    # Yamel test
                    report.record_result(load_test(idref, mode))
                    # Python tests
                    env['ir.http']._clear_routing_map(
                    )  # force routing map to be rebuilt
                    report.record_result(
                        eagle.modules.module.run_unit_tests(
                            module_name, cr.dbname))
                    # tests may have reset the environment
                    env = api.Environment(cr, SUPERUSER_ID, {})
                    module = env['ir.module.module'].browse(module_id)

            processed_modules.append(package.name)

            ver = adapt_version(package.data['version'])
            # Set new modules and dependencies
            module.write({'state': 'installed', 'latest_version': ver})

            package.load_state = package.state
            package.load_version = package.installed_version
            package.state = 'installed'
            for kind in ('init', 'demo', 'update'):
                if hasattr(package, kind):
                    delattr(package, kind)

        if package.name is not None:
            registry._init_modules.add(package.name)

    _logger.log(25, "%s modules loaded in %.2fs, %s queries", len(graph),
                time.time() - t0, eagle.sql_db.sql_counter - t0_sql)

    return loaded_modules, processed_modules
Exemplo n.º 20
0
def load_modules(db, force_demo=False, status=None, update_module=False):
    initialize_sys_path()

    force = []
    if force_demo:
        force.append('demo')

    models_to_check = set()

    with db.cursor() as cr:
        if not eagle.modules.db.is_initialized(cr):
            if not update_module:
                _logger.error(
                    "Database %s not initialized, you can force it with `-i base`",
                    cr.dbname)
                return
            _logger.info("init db")
            eagle.modules.db.initialize(cr)
            update_module = True  # process auto-installed modules
            tools.config["init"]["all"] = 1
            tools.config['update']['all'] = 1
            if not tools.config['without_demo']:
                tools.config["demo"]['all'] = 1

        # This is a brand new registry, just created in
        # eagle.modules.registry.Registry.new().
        registry = eagle.registry(cr.dbname)

        if 'base' in tools.config['update'] or 'all' in tools.config['update']:
            cr.execute(
                "update ir_module_module set state=%s where name=%s and state=%s",
                ('to upgrade', 'base', 'installed'))

        # STEP 1: LOAD BASE (must be done before module dependencies can be computed for later steps)
        graph = eagle.modules.graph.Graph()
        graph.add_module(cr, 'base', force)
        if not graph:
            _logger.critical(
                'module base cannot be loaded! (hint: verify addons-path)')
            raise ImportError(
                'Module `base` cannot be loaded! (hint: verify addons-path)')

        # processed_modules: for cleanup step after install
        # loaded_modules: to avoid double loading
        report = registry._assertion_report
        loaded_modules, processed_modules = load_module_graph(
            cr,
            graph,
            status,
            perform_checks=update_module,
            report=report,
            models_to_check=models_to_check)

        load_lang = tools.config.pop('load_language')
        if load_lang or update_module:
            # some base models are used below, so make sure they are set up
            registry.setup_models(cr)

        if load_lang:
            for lang in load_lang.split(','):
                tools.load_language(cr, lang)

        # STEP 2: Mark other modules to be loaded/updated
        if update_module:
            env = api.Environment(cr, SUPERUSER_ID, {})
            Module = env['ir.module.module']
            _logger.info('updating modules list')
            Module.update_list()

            _check_module_names(
                cr,
                itertools.chain(tools.config['init'], tools.config['update']))

            module_names = [k for k, v in tools.config['init'].items() if v]
            if module_names:
                modules = Module.search([('state', '=', 'uninstalled'),
                                         ('name', 'in', module_names)])
                if modules:
                    modules.button_install()

            module_names = [k for k, v in tools.config['update'].items() if v]
            if module_names:
                modules = Module.search([('state', '=', 'installed'),
                                         ('name', 'in', module_names)])
                if modules:
                    modules.button_upgrade()

            cr.execute("update ir_module_module set state=%s where name=%s",
                       ('installed', 'base'))
            Module.invalidate_cache(['state'])

        # STEP 3: Load marked modules (skipping base which was done in STEP 1)
        # IMPORTANT: this is done in two parts, first loading all installed or
        #            partially installed modules (i.e. installed/to upgrade), to
        #            offer a consistent system to the second part: installing
        #            newly selected modules.
        #            We include the modules 'to remove' in the first step, because
        #            they are part of the "currently installed" modules. They will
        #            be dropped in STEP 6 later, before restarting the loading
        #            process.
        # IMPORTANT 2: We have to loop here until all relevant modules have been
        #              processed, because in some rare cases the dependencies have
        #              changed, and modules that depend on an uninstalled module
        #              will not be processed on the first pass.
        #              It's especially useful for migrations.
        previously_processed = -1
        while previously_processed < len(processed_modules):
            previously_processed = len(processed_modules)
            processed_modules += load_marked_modules(
                cr, graph, ['installed', 'to upgrade', 'to remove'], force,
                status, report, loaded_modules, update_module, models_to_check)
            if update_module:
                processed_modules += load_marked_modules(
                    cr, graph, ['to install'], force, status, report,
                    loaded_modules, update_module, models_to_check)

        registry.loaded = True
        registry.setup_models(cr)

        # STEP 3.5: execute migration end-scripts
        migrations = eagle.modules.migration.MigrationManager(cr, graph)
        for package in graph:
            migrations.migrate_module(package, 'end')

        # STEP 4: Finish and cleanup installations
        if processed_modules:
            env = api.Environment(cr, SUPERUSER_ID, {})
            cr.execute(
                """select model,name from ir_model where id NOT IN (select distinct model_id from ir_model_access)"""
            )
            for (model, name) in cr.fetchall():
                if model in registry and not registry[
                        model]._abstract and not registry[model]._transient:
                    _logger.warning(
                        'The model %s has no access rules, consider adding one. E.g. access_%s,access_%s,model_%s,base.group_user,1,0,0,0',
                        model, model.replace('.',
                                             '_'), model.replace('.', '_'),
                        model.replace('.', '_'))

            # Temporary warning while we remove access rights on osv_memory objects, as they have
            # been replaced by owner-only access rights
            cr.execute(
                """select distinct mod.model, mod.name from ir_model_access acc, ir_model mod where acc.model_id = mod.id"""
            )
            for (model, name) in cr.fetchall():
                if model in registry and registry[model]._transient:
                    _logger.warning(
                        'The transient model %s (%s) should not have explicit access rules!',
                        model, name)

            cr.execute("SELECT model from ir_model")
            for (model, ) in cr.fetchall():
                if model in registry:
                    env[model]._check_removed_columns(log=True)
                elif _logger.isEnabledFor(
                        logging.INFO):  # more an info that a warning...
                    _logger.warning(
                        "Model %s is declared but cannot be loaded! (Perhaps a module was partially removed or renamed)",
                        model)

            # Cleanup orphan records
            env['ir.model.data']._process_end(processed_modules)

        for kind in ('init', 'demo', 'update'):
            tools.config[kind] = {}

        # STEP 5: Uninstall modules to remove
        if update_module:
            # Remove records referenced from ir_model_data for modules to be
            # removed (and removed the references from ir_model_data).
            cr.execute("SELECT name, id FROM ir_module_module WHERE state=%s",
                       ('to remove', ))
            modules_to_remove = dict(cr.fetchall())
            if modules_to_remove:
                env = api.Environment(cr, SUPERUSER_ID, {})
                pkgs = reversed(
                    [p for p in graph if p.name in modules_to_remove])
                for pkg in pkgs:
                    uninstall_hook = pkg.info.get('uninstall_hook')
                    if uninstall_hook:
                        py_module = sys.modules['eagle.addons.%s' %
                                                (pkg.name, )]
                        getattr(py_module, uninstall_hook)(cr, registry)

                Module = env['ir.module.module']
                Module.browse(modules_to_remove.values()).module_uninstall()
                # Recursive reload, should only happen once, because there should be no
                # modules to remove next time
                cr.commit()
                _logger.info(
                    'Reloading registry once more after uninstalling modules')
                api.Environment.reset()
                registry = eagle.modules.registry.Registry.new(
                    cr.dbname, force_demo, status, update_module)
                registry.check_tables_exist(cr)
                cr.commit()
                return registry

        # STEP 5.5: Verify extended fields on every model
        # This will fix the schema of all models in a situation such as:
        #   - module A is loaded and defines model M;
        #   - module B is installed/upgraded and extends model M;
        #   - module C is loaded and extends model M;
        #   - module B and C depend on A but not on each other;
        # The changes introduced by module C are not taken into account by the upgrade of B.
        if models_to_check:
            registry.init_models(cr, list(models_to_check),
                                 {'models_to_check': True})

        # STEP 6: verify custom views on every model
        if update_module:
            env = api.Environment(cr, SUPERUSER_ID, {})
            View = env['ir.ui.view']
            for model in registry:
                try:
                    View._validate_custom_views(model)
                except Exception as e:
                    _logger.warning('invalid custom view(s) for model %s: %s',
                                    model, tools.ustr(e))

        if report.failures:
            _logger.error('At least one test failed when loading the modules.')
        else:
            _logger.info('Modules loaded.')

        # STEP 8: call _register_hook on every model
        env = api.Environment(cr, SUPERUSER_ID, {})
        for model in env.values():
            model._register_hook()

        # STEP 9: save installed/updated modules for post-install tests
        registry.updated_modules += processed_modules
Exemplo n.º 21
0
    def _process_jobs(cls, db_name):
        """ Try to process all cron jobs.

        This selects in database all the jobs that should be processed. It then
        tries to lock each of them and, if it succeeds, run the cron job (if it
        doesn't succeed, it means the job was already locked to be taken care
        of by another thread) and return.

        :raise BadVersion: if the version is different from the worker's
        :raise BadModuleState: if modules are to install/upgrade/remove
        """
        db = eagle.sql_db.db_connect(db_name)
        threading.current_thread().dbname = db_name
        try:
            with db.cursor() as cr:
                # Make sure the database has the same version as the code of
                # base and that no module must be installed/upgraded/removed
                cr.execute(
                    "SELECT latest_version FROM ir_module_module WHERE name=%s",
                    ['base'])
                (version, ) = cr.fetchone()
                cr.execute(
                    "SELECT COUNT(*) FROM ir_module_module WHERE state LIKE %s",
                    ['to %'])
                (changes, ) = cr.fetchone()
                if version is None:
                    raise BadModuleState()
                elif version != BASE_VERSION:
                    raise BadVersion()
                # Careful to compare timestamps with 'UTC' - everything is UTC as of v6.1.
                cr.execute("""SELECT * FROM ir_cron
                              WHERE numbercall != 0
                                  AND active AND nextcall <= (now() at time zone 'UTC')
                              ORDER BY priority""")
                jobs = cr.dictfetchall()

            if changes:
                if not jobs:
                    raise BadModuleState()
                # nextcall is never updated if the cron is not executed,
                # it is used as a sentinel value to check whether cron jobs
                # have been locked for a long time (stuck)
                parse = fields.Datetime.from_string
                oldest = min([parse(job['nextcall']) for job in jobs])
                if datetime.now() - oldest > MAX_FAIL_TIME:
                    eagle.modules.reset_modules_state(db_name)
                else:
                    raise BadModuleState()

            for job in jobs:
                lock_cr = db.cursor()
                try:
                    # Try to grab an exclusive lock on the job row from within the task transaction
                    # Restrict to the same conditions as for the search since the job may have already
                    # been run by an other thread when cron is running in multi thread
                    lock_cr.execute("""SELECT *
                                       FROM ir_cron
                                       WHERE numbercall != 0
                                          AND active
                                          AND nextcall <= (now() at time zone 'UTC')
                                          AND id=%s
                                       FOR UPDATE NOWAIT""", (job['id'], ),
                                    log_exceptions=False)

                    locked_job = lock_cr.fetchone()
                    if not locked_job:
                        _logger.debug(
                            "Job `%s` already executed by another process/thread. skipping it",
                            job['cron_name'])
                        continue
                    # Got the lock on the job row, run its code
                    _logger.info('Starting job `%s`.', job['cron_name'])
                    job_cr = db.cursor()
                    try:
                        registry = eagle.registry(db_name)
                        registry[cls._name]._process_job(job_cr, job, lock_cr)
                        _logger.info('Job `%s` done.', job['cron_name'])
                    except Exception:
                        _logger.exception(
                            'Unexpected exception while processing cron job %r',
                            job)
                    finally:
                        job_cr.close()

                except psycopg2.OperationalError as e:
                    if e.pgcode == '55P03':
                        # Class 55: Object not in prerequisite state; 55P03: lock_not_available
                        _logger.debug(
                            'Another process/thread is already busy executing job `%s`, skipping it.',
                            job['cron_name'])
                        continue
                    else:
                        # Unexpected OperationalError
                        raise
                finally:
                    # we're exiting due to an exception while acquiring the lock
                    lock_cr.close()

        finally:
            if hasattr(threading.current_thread(), 'dbname'):
                del threading.current_thread().dbname
Exemplo n.º 22
0
 def send_notifications():
     db_registry = registry(dbname)
     with api.Environment.manage(), db_registry.cursor() as cr:
         env = api.Environment(cr, SUPERUSER_ID, _context)
         env['mail.mail'].browse(email_ids).send()
Exemplo n.º 23
0
def migrate(cr, version):
    registry = eagle.registry(cr.dbname)
    from eagle.addons.account.models.chart_template import migrate_set_tags_and_taxes_updatable
    migrate_set_tags_and_taxes_updatable(cr, registry, 'l10n_de_skr03')
Exemplo n.º 24
0
    def _handle_exception(cls, exception):
        code = 500  # default code
        is_website_request = bool(
            getattr(request, 'is_frontend', False)
            and getattr(request, 'website', False))
        if not is_website_request:
            # Don't touch non website requests exception handling
            return super(Http, cls)._handle_exception(exception)
        else:
            try:
                response = super(Http, cls)._handle_exception(exception)

                if isinstance(response, Exception):
                    exception = response
                else:
                    # if parent excplicitely returns a plain response, then we don't touch it
                    return response
            except Exception as e:
                if 'werkzeug' in config['dev_mode']:
                    raise e
                exception = e

            values = dict(
                exception=exception,
                traceback=traceback.format_exc(),
            )

            if isinstance(exception, werkzeug.exceptions.HTTPException):
                if exception.code is None:
                    # Hand-crafted HTTPException likely coming from abort(),
                    # usually for a redirect response -> return it directly
                    return exception
                else:
                    code = exception.code

            if isinstance(exception, eagle.exceptions.AccessError):
                code = 403

            if isinstance(exception, QWebException):
                values.update(qweb_exception=exception)

                # retro compatibility to remove in 12.2
                exception.qweb = dict(message=exception.message,
                                      expression=exception.html)

                if type(exception.error) == eagle.exceptions.AccessError:
                    code = 403

            values.update(
                status_message=werkzeug.http.HTTP_STATUS_CODES[code],
                status_code=code,
            )

            view_id = code
            if request.website.is_publisher() and isinstance(
                    exception, werkzeug.exceptions.NotFound):
                view_id = 'page_404'
                values['path'] = request.httprequest.path[1:]

            if not request.uid:
                cls._auth_method_public()

            with registry(request.env.cr.dbname).cursor() as cr:
                env = api.Environment(cr, request.uid, request.env.context)
                if code == 500:
                    logger.error("500 Internal Server Error:\n\n%s",
                                 values['traceback'])
                    View = env["ir.ui.view"]
                    values['views'] = View
                    if 'qweb_exception' in values:
                        if 'load could not load template' in exception.args:
                            # When t-calling an inexisting template, we don't have reference to
                            # the view that did the t-call. We need to find it.
                            values['views'] = View.search(
                                [('type', '=', 'qweb'), '|',
                                 ('arch_db', 'ilike',
                                  't-call="%s"' % exception.name),
                                 ('arch_db', 'ilike',
                                  "t-call='%s'" % exception.name)],
                                order='write_date desc',
                                limit=1)
                        else:
                            try:
                                # exception.name might be int, string
                                exception_template = int(exception.name)
                            except:
                                exception_template = exception.name
                            view = View._view_obj(exception_template)
                            if exception.html in view.arch:
                                values['views'] = view
                            else:
                                # There might be 2 cases where the exception code can't be found
                                # in the view, either the error is in a child view or the code
                                # contains branding (<div t-att-data="request.browse('ok')"/>).
                                et = etree.fromstring(
                                    view.with_context(
                                        inherit_branding=False).read_combined(
                                            ['arch'])['arch'])
                                node = et.find(
                                    exception.path.replace(
                                        '/templates/t/', './'))
                                line = node is not None and etree.tostring(
                                    node, encoding='unicode')
                                if line:
                                    values['views'] = View._views_get(
                                        exception_template).filtered(
                                            lambda v: line in v.arch)
                        # Keep only views that we can reset
                        values['views'] = values['views'].filtered(
                            lambda view: view._get_original_view(
                            ).arch_fs or 'oe_structure' in view.key)
                        # Needed to show reset template on translated pages (`_prepare_qcontext` will set it for main lang)
                        values[
                            'editable'] = request.uid and request.website.is_publisher(
                            )
                elif code == 403:
                    logger.warn("403 Forbidden:\n\n%s", values['traceback'])
                try:
                    html = env['ir.ui.view'].render_template(
                        'website.%s' % view_id, values)
                except Exception:
                    html = env['ir.ui.view'].render_template(
                        'website.http_error', values)

            return werkzeug.wrappers.Response(
                html, status=code, content_type='text/html;charset=utf-8')