Ejemplo n.º 1
0
    def _make_access_error(self, operation, records):
        _logger.info('Access Denied by record rules for operation: %s on record ids: %r, uid: %s, model: %s', operation, records.ids[:6], self._uid, records._name)

        model = records._name
        description = self.env['ir.model']._get(model).name or model
        if not self.env.user.has_group('base.group_no_one'):
            return AccessError(_('The requested operation cannot be completed due to security restrictions. Please contact your system administrator.\n\n(Document type: "%(document_kind)s" (%(document_model)s), Operation: %(operation)s)') % {
                'document_kind': description,
                'document_model': model,
                'operation': operation,
            })

        # This extended AccessError is only displayed in debug mode.
        # Note that by default, public and portal users do not have
        # the group "base.group_no_one", even if debug mode is enabled,
        # so it is relatively safe here to include the list of rules and
        # record names.
        rules = self._get_failing(records, mode=operation).sudo()
        error = AccessError(_("""The requested operation ("%(operation)s" on "%(document_kind)s" (%(document_model)s)) was rejected because of the following rules:
%(rules_list)s
%(multi_company_warning)s
(Records: %(example_records)s, User: %(user_id)s)""") % {
            'operation': operation,
            'document_kind': description,
            'document_model': model,
            'rules_list': '\n'.join('- %s' % rule.name for rule in rules),
            'multi_company_warning': ('\n' + _('Note: this might be a multi-company issue.') + '\n') if any(
                'company_id' in (r.domain_force or []) for r in rules) else '',
            'example_records': ' - '.join(['%s (id=%s)' % (rec.display_name, rec.id) for rec in records[:6].sudo()]),
            'user_id': '%s (id=%s)' % (self.env.user.name, self.env.user.id),
        })
        # clean up the cache of records prefetched with display_name above
        for record in records[:6]:
            record._cache.clear()
        return error
Ejemplo n.º 2
0
    def company(self):
        """Return the current company (as an instance).

        If not specified in the context (`allowed_company_ids`),
        fallback on current user main company.

        :raise AccessError: invalid or unauthorized `allowed_company_ids` context key content.
        :return: current company (default=`self.user.company_id`)
        :rtype: res.company

        .. warning::

            No sanity checks applied in sudo mode !
            When in sudo mode, a user can access any company,
            even if not in his allowed companies.

            This allows to trigger inter-company modifications,
            even if the current user doesn't have access to
            the targeted company.
        """
        company_ids = self.context.get('allowed_company_ids', [])
        if company_ids:
            if not self.su:
                user_company_ids = self.user.company_ids.ids
                if any(cid not in user_company_ids for cid in company_ids):
                    raise AccessError(_("Access to unauthorized or invalid companies."))
            return self['res.company'].browse(company_ids[0])
        return self.user.company_id
Ejemplo n.º 3
0
 def _read(self, fields):
     # DLE P45: `test_31_prefetch`,
     # with self.assertRaises(AccessError):
     #     cat1.name
     if self.search_count([('id', 'in', self._ids),
                           ('name', '=', 'NOACCESS')]):
         raise AccessError('Sorry')
     return super(Category, self)._read(fields)
Ejemplo n.º 4
0
 def read(self, fields, load='_classic_read'):
     if self.check_access_rights('read', raise_exception=False):
         return super(HrEmployeePrivate, self).read(fields, load=load)
     private_fields = set(fields).difference(
         self.env['hr.employee.public']._fields.keys())
     if private_fields:
         raise AccessError(
             _('The fields "%s" you try to read is not available on the public employee profile.'
               ) % (','.join(private_fields)))
     return self.env['hr.employee.public'].browse(self.ids).read(fields,
                                                                 load=load)
Ejemplo n.º 5
0
 def _compute_kpi_hr_recruitment_new_colleagues_value(self):
     if not self.env.user.has_group('hr_recruitment.group_hr_recruitment_user'):
         raise AccessError(_("Do not have access, skip this data for user's digest email"))
     for record in self:
         start, end, company = record._get_kpi_compute_parameters()
         new_colleagues = self.env['hr.employee'].search_count([
             ('create_date', '>=', start),
             ('create_date', '<', end),
             ('company_id', '=', company.id)
         ])
         record.kpi_hr_recruitment_new_colleagues_value = new_colleagues
Ejemplo n.º 6
0
 def _compute_kpi_crm_lead_created_value(self):
     if not self.env.user.has_group('sales_team.group_sale_salesman'):
         raise AccessError(
             _("Do not have access, skip this data for user's digest email")
         )
     for record in self:
         start, end, company = record._get_kpi_compute_parameters()
         record.kpi_crm_lead_created_value = self.env[
             'crm.lead'].search_count([('create_date', '>=', start),
                                       ('create_date', '<', end),
                                       ('company_id', '=', company.id)])
Ejemplo n.º 7
0
 def _compute_project_task_opened_value(self):
     if not self.env.user.has_group('project.group_project_user'):
         raise AccessError(_("Do not have access, skip this data for user's digest email"))
     for record in self:
         start, end, company = record._get_kpi_compute_parameters()
         record.kpi_project_task_opened_value = self.env['project.task'].search_count([
             ('stage_id.fold', '=', False),
             ('create_date', '>=', start),
             ('create_date', '<', end),
             ('company_id', '=', company.id)
         ])
Ejemplo n.º 8
0
    def _parse_import_data_recursive(self, model, prefix, data, import_fields,
                                     options):
        # Get fields of type date/datetime
        all_fields = self.env[model].fields_get()
        for name, field in all_fields.items():
            name = prefix + name
            if field['type'] in ('date', 'datetime') and name in import_fields:
                index = import_fields.index(name)
                self._parse_date_from_data(data, index, name, field['type'],
                                           options)
            # Check if the field is in import_field and is a relational (followed by /)
            # Also verify that the field name exactly match the import_field at the correct level.
            elif any(name + '/' in import_field
                     and name == import_field.split('/')[prefix.count('/')]
                     for import_field in import_fields):
                # Recursive call with the relational as new model and add the field name to the prefix
                self._parse_import_data_recursive(field['relation'],
                                                  name + '/', data,
                                                  import_fields, options)
            elif field['type'] in ('float',
                                   'monetary') and name in import_fields:
                # Parse float, sometimes float values from file have currency symbol or () to denote a negative value
                # We should be able to manage both case
                index = import_fields.index(name)
                self._parse_float_from_data(data, index, name, options)
            elif field['type'] == 'binary' and field.get('attachment') and any(
                    f in name for f in IMAGE_FIELDS) and name in import_fields:
                index = import_fields.index(name)

                with requests.Session() as session:
                    session.stream = True

                    for num, line in enumerate(data):
                        if re.match(
                                config.get("import_image_regex",
                                           DEFAULT_IMAGE_REGEX), line[index]):
                            if not self.env.user._can_import_remote_urls():
                                raise AccessError(
                                    _("You can not import images via URL, check with your administrator or support for the reason."
                                      ))

                            line[index] = self._import_image_by_url(
                                line[index], session, name, num)
                        else:
                            try:
                                base64.b64decode(line[index], validate=True)
                            except binascii.Error:
                                raise ValueError(
                                    _("Found invalid image data, images should be imported as either URLs or base64-encoded data."
                                      ))

        return data
Ejemplo n.º 9
0
 def _compute_kpi_crm_opportunities_won_value(self):
     if not self.env.user.has_group('sales_team.group_sale_salesman'):
         raise AccessError(
             _("Do not have access, skip this data for user's digest email")
         )
     for record in self:
         start, end, company = record._get_kpi_compute_parameters()
         record.kpi_crm_opportunities_won_value = self.env[
             'crm.lead'].search_count([('type', '=', 'opportunity'),
                                       ('probability', '=', '100'),
                                       ('date_closed', '>=', start),
                                       ('date_closed', '<', end),
                                       ('company_id', '=', company.id)])
Ejemplo n.º 10
0
    def write(self, vals):
        """
        Synchronize user and its related employee
        and check access rights if employees are not allowed to update
        their own data (otherwise sudo is applied for self data).
        """
        hr_fields = {
            field
            for field_name, field in self._fields.items()
            if field.related_field and field.related_field.model_name ==
            'hr.employee' and field_name in vals
        }
        can_edit_self = self.env['ir.config_parameter'].sudo().get_param(
            'hr.hr_employee_self_edit') or self.env.user.has_group(
                'hr.group_hr_user')
        if hr_fields and not can_edit_self:
            # Raise meaningful error message
            raise AccessError(
                _("You are only allowed to update your preferences. Please contact a HR officer to update other informations."
                  ))

        result = super(User, self).write(vals)

        employee_values = {}
        for fname in [
                f for f in ['name', 'email', 'image_1920', 'tz'] if f in vals
        ]:
            employee_values[fname] = vals[fname]
        if employee_values:
            if 'email' in employee_values:
                employee_values['work_email'] = employee_values.pop('email')
            if 'image_1920' in vals:
                without_image = self.env['hr.employee'].sudo().search([
                    ('user_id', 'in', self.ids), ('image_1920', '=', False)
                ])
                with_image = self.env['hr.employee'].sudo().search([
                    ('user_id', 'in', self.ids), ('image_1920', '!=', False)
                ])
                without_image.write(employee_values)
                if not can_edit_self:
                    employee_values.pop('image_1920')
                with_image.write(employee_values)
            else:
                self.env['hr.employee'].sudo().search([
                    ('user_id', 'in', self.ids)
                ]).write(employee_values)
        return result
Ejemplo n.º 11
0
 def _compute_kpi_sale_total_value(self):
     if not self.env.user.has_group(
             'sales_team.group_sale_salesman_all_leads'):
         raise AccessError(
             _("Do not have access, skip this data for user's digest email")
         )
     for record in self:
         start, end, company = record._get_kpi_compute_parameters()
         all_channels_sales = self.env['sale.report'].read_group(
             [('date', '>=', start), ('date', '<', end),
              ('state', 'not in', ['draft', 'cancel', 'sent']),
              ('company_id', '=', company.id)], ['price_total'],
             ['price_total'])
         record.kpi_all_sale_total_value = sum([
             channel_sale['price_total']
             for channel_sale in all_channels_sales
         ])
Ejemplo n.º 12
0
    def execute(self):
        self.ensure_one()
        if not self.env.is_admin():
            raise AccessError(_("Only administrators can change the settings"))

        self = self.with_context(active_test=False)
        classified = self._get_classified_fields()

        self.set_values()

        # module fields: install/uninstall the selected modules
        to_install = []
        to_uninstall_modules = self.env['ir.module.module']
        lm = len('module_')
        for name, module in classified['module']:
            if int(self[name]):
                to_install.append((name[lm:], module))
            else:
                if module and module.state in ('installed', 'to upgrade'):
                    to_uninstall_modules += module

        if to_install or to_uninstall_modules:
            self.flush()

        if to_uninstall_modules:
            to_uninstall_modules.button_immediate_uninstall()

        self._install_modules(to_install)

        if to_install or to_uninstall_modules:
            # After the uninstall/install calls, the registry and environments
            # are no longer valid. So we reset the environment.
            self.env.reset()
            self = self.env()[self._name]

        # pylint: disable=next-method-called
        config = self.env['res.config'].next() or {}
        if config.get('type') not in ('ir.actions.act_window_close', ):
            return config

        # force client-side reload (update user menu and current view)
        return {
            'type': 'ir.actions.client',
            'tag': 'reload',
        }
Ejemplo n.º 13
0
 def _compute_kpi_account_total_revenue_value(self):
     if not self.env.user.has_group('account.group_account_invoice'):
         raise AccessError(
             _("Do not have access, skip this data for user's digest email")
         )
     for record in self:
         start, end, company = record._get_kpi_compute_parameters()
         self._cr.execute(
             '''
             SELECT SUM(line.debit)
             FROM account_move_line line
             JOIN account_move move ON move.id = line.move_id
             JOIN account_journal journal ON journal.id = move.journal_id
             WHERE line.company_id = %s AND line.date >= %s AND line.date < %s
             AND journal.type = 'sale'
         ''', [company.id, start, end])
         query_res = self._cr.fetchone()
         record.kpi_account_total_revenue_value = query_res and query_res[
             0] or 0.0
Ejemplo n.º 14
0
    def base_setup_data(self, **kw):
        if not request.env.user.has_group('base.group_erp_manager'):
            raise AccessError(_("Access Denied"))

        cr = request.cr
        cr.execute("""
            SELECT count(*)
              FROM res_users
             WHERE active=true AND
                   share=false
        """)
        active_count = cr.dictfetchall()[0].get('count')

        cr.execute("""
            SELECT count(u.*)
            FROM res_users u
            WHERE active=true AND
                  share=false AND
                  NOT exists(SELECT 1 FROM res_users_log WHERE create_uid=u.id)
        """)
        pending_count = cr.dictfetchall()[0].get('count')

        cr.execute("""
           SELECT id, login
             FROM res_users u
            WHERE active=true AND
                  share=false AND
                  NOT exists(SELECT 1 FROM res_users_log WHERE create_uid=u.id)
         ORDER BY id desc
            LIMIT 10
        """)
        pending_users = cr.fetchall()

        return {
            'active_users': active_count,
            'pending_count': pending_count,
            'pending_users': pending_users,
        }
Ejemplo n.º 15
0
    def companies(self):
        """Return a recordset of the enabled companies by the user.

        If not specified in the context(`allowed_company_ids`),
        fallback on current user companies.

        :raise AccessError: invalid or unauthorized `allowed_company_ids` context key content.
        :return: current companies (default=`self.user.company_ids`)
        :rtype: res.company

        .. warning::

            No sanity checks applied in sudo mode !
            When in sudo mode, a user can access any company,
            even if not in his allowed companies.

            This allows to trigger inter-company modifications,
            even if the current user doesn't have access to
            the targeted company.
        """
        company_ids = self.context.get('allowed_company_ids', [])
        if company_ids:
            if not self.su:
                user_company_ids = self.user.company_ids.ids
                if any(cid not in user_company_ids for cid in company_ids):
                    raise AccessError(_("Access to unauthorized or invalid companies."))
            return self['res.company'].browse(company_ids)
        # By setting the default companies to all user companies instead of the main one
        # we save a lot of potential trouble in all "out of context" calls, such as
        # /mail/redirect or /web/image, etc. And it is not unsafe because the user does
        # have access to these other companies. The risk of exposing foreign records
        # (wrt to the context) is low because all normal RPCs will have a proper
        # allowed_company_ids.
        # Examples:
        #   - when printing a report for several records from several companies
        #   - when accessing to a record from the notification email template
        #   - when loading an binary image on a template
        return self.user.company_ids
Ejemplo n.º 16
0
    def _redirect_to_record(cls, model, res_id, access_token=None, **kwargs):
        # access_token and kwargs are used in the portal controller override for the Send by email or Share Link
        # to give access to the record to a recipient that has normally no access.
        uid = request.session.uid
        user = request.env['res.users'].sudo().browse(uid)
        cids = False

        # no model / res_id, meaning no possible record -> redirect to login
        if not model or not res_id or model not in request.env:
            return cls._redirect_to_messaging()

        # find the access action using sudo to have the details about the access link
        RecordModel = request.env[model]
        record_sudo = RecordModel.sudo().browse(res_id).exists()
        if not record_sudo:
            # record does not seem to exist -> redirect to login
            return cls._redirect_to_messaging()

        # the record has a window redirection: check access rights
        if uid is not None:
            if not RecordModel.with_user(uid).check_access_rights(
                    'read', raise_exception=False):
                return cls._redirect_to_messaging()
            try:
                # We need here to extend the "allowed_company_ids" to allow a redirection
                # to any record that the user can access, regardless of currently visible
                # records based on the "currently allowed companies".
                cids = request.httprequest.cookies.get('cids',
                                                       str(user.company_id.id))
                cids = [int(cid) for cid in cids.split(',')]
                try:
                    record_sudo.with_user(uid).with_context(
                        allowed_company_ids=cids).check_access_rule('read')
                except AccessError:
                    # In case the allowed_company_ids from the cookies (i.e. the last user configuration
                    # on his browser) is not sufficient to avoid an ir.rule access error, try to following
                    # heuristic:
                    # - Guess the supposed necessary company to access the record via the method
                    #   _get_mail_redirect_suggested_company
                    #   - If no company, then redirect to the messaging
                    #   - Merge the suggested company with the companies on the cookie
                    # - Make a new access test if it succeeds, redirect to the record. Otherwise,
                    #   redirect to the messaging.
                    suggested_company = record_sudo._get_mail_redirect_suggested_company(
                    )
                    if not suggested_company:
                        raise AccessError()
                    cids = cids + [suggested_company.id]
                    record_sudo.with_user(uid).with_context(
                        allowed_company_ids=cids).check_access_rule('read')
            except AccessError:
                return cls._redirect_to_messaging()
            else:
                record_action = record_sudo.get_access_action(access_uid=uid)
        else:
            record_action = record_sudo.get_access_action()
            if record_action[
                    'type'] == 'ir.actions.act_url' and record_action.get(
                        'target_type') != 'public':
                return cls._redirect_to_messaging()

        record_action.pop('target_type', None)
        # the record has an URL redirection: use it directly
        if record_action['type'] == 'ir.actions.act_url':
            return werkzeug.utils.redirect(record_action['url'])
        # other choice: act_window (no support of anything else currently)
        elif not record_action['type'] == 'ir.actions.act_window':
            return cls._redirect_to_messaging()

        url_params = {
            'model': model,
            'id': res_id,
            'active_id': res_id,
            'action': record_action.get('id'),
        }
        view_id = record_sudo.get_formview_id()
        if view_id:
            url_params['view_id'] = view_id

        if cids:
            url_params['cids'] = ','.join([str(cid) for cid in cids])
        url = '/web?#%s' % url_encode(url_params)
        return werkzeug.utils.redirect(url)
Ejemplo n.º 17
0
 def test_access_error_http(self, **kwargs):
     raise AccessError("This is an access http test")
Ejemplo n.º 18
0
 def check_user(self, uid=None):
     if uid is None:
         uid = request.uid
     is_admin = request.env['res.users'].browse(uid)._is_admin()
     if not is_admin:
         raise AccessError(_("Only administrators can upload a module"))
Ejemplo n.º 19
0
 def _check_user_impersonification(self, user_id=None):
     if (user_id and request.env.uid != user_id and
             not request.env.user.has_group('lunch.group_lunch_manager')):
         raise AccessError(
             _('You are trying to impersonate another user, but this can only be done by a lunch manager'
               ))
Ejemplo n.º 20
0
 def test_access_error_json(self, **kwargs):
     raise AccessError("This is an access rpc test")