Exemplo n.º 1
0
 def read_group(self,
                domain,
                fields,
                groupby,
                offset=0,
                limit=None,
                orderby=False,
                lazy=True):
     """Override read_group to add res_field=False in domain if not present."""
     if not fields:
         raise AccessError(
             _("Sorry, you must provide fields to read on attachments"))
     if any('(' in field for field in fields + groupby):
         raise AccessError(
             _("Sorry, the syntax 'name:agg(field)' is not available for attachments"
               ))
     if not any(item[0] in ('id', 'res_field') for item in domain):
         domain.insert(0, ('res_field', '=', False))
     groupby = [groupby] if isinstance(groupby, str) else groupby
     allowed_fields = self._read_group_allowed_fields()
     fields_set = set(field.split(':')[0] for field in fields + groupby)
     if not self.env.is_system() and (
             not fields or fields_set.difference(allowed_fields)):
         raise AccessError(
             _("Sorry, you are not allowed to access these fields on attachments."
               ))
     return super().read_group(domain,
                               fields,
                               groupby,
                               offset=offset,
                               limit=limit,
                               orderby=orderby,
                               lazy=lazy)
Exemplo n.º 2
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
Exemplo 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)
Exemplo 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)
Exemplo n.º 5
0
    def convert_answer_to_comment(self):
        """ Tools to convert an answer (forum.post) to a comment (mail.message).
        The original post is unlinked and a new comment is posted on the question
        using the post create_uid as the comment's author. """
        self.ensure_one()
        if not self.parent_id:
            return self.env['mail.message']

        # karma-based action check: use the post field that computed own/all value
        if not self.can_comment_convert:
            raise AccessError(_('%d karma required to convert an answer to a comment.') % self.karma_comment_convert)

        # post the message
        question = self.parent_id
        self_sudo = self.sudo()
        values = {
            'author_id': self_sudo.create_uid.partner_id.id,  # use sudo here because of access to res.users model
            'email_from': self_sudo.create_uid.email_formatted,  # use sudo here because of access to res.users model
            'body': tools.html_sanitize(self.content, sanitize_attributes=True, strip_style=True, strip_classes=True),
            'message_type': 'comment',
            'subtype': 'mail.mt_comment',
            'date': self.create_date,
        }
        # done with the author user to have create_uid correctly set
        new_message = question.with_user(self_sudo.create_uid.id).with_context(mail_create_nosubscribe=True).message_post(**values)

        # unlink the original answer, using SUPERUSER_ID to avoid karma issues
        self.sudo().unlink()

        return new_message
Exemplo n.º 6
0
    def migrate_to_lobject(self):
        """migrates all binary attachments to postgres large object storage"""
        if not self.env.user._is_admin():
            raise AccessError(
                _('Only administrators can execute this action.'))

        atts = self.search([
            '&',
            '&',
            ('id', '>', 0),  # bypass filtering of field-attached attachments
            ('type', '=', 'binary'),
            '|',
            ('store_fname', '=', False),
            ('store_fname', 'not like', LARGE_OBJECT_LOCATION + ':%')
        ])

        att_count = len(atts)
        if att_count:
            log.info(
                f'Migrating {att_count} database attachments to Large Objects...'
            )
            if self._storage() != LARGE_OBJECT_LOCATION:
                raise Exception(
                    f'Default storage is not set to Large Object ({LARGE_OBJECT_LOCATION})'
                )
            current_att = 1
            for att in atts:
                log.info(
                    f'Migrating attachment ID {att.id} ({current_att} of {att_count})...'
                )
                # re-save data to move to lobject storage
                att.write({'mimetype': att.mimetype, 'datas': att.datas})
                current_att += 1
Exemplo n.º 7
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
Exemplo n.º 8
0
 def get_mail_message_access(self, res_ids, operation, model_name=None):
     # XDO FIXME: to be correctly fixed with new get_mail_message_access and filter access rule
     if operation in ('write', 'unlink') and (not model_name or model_name == 'forum.post'):
         # Make sure only author or moderator can edit/delete messages
         for post in self.browse(res_ids):
             if not post.can_edit:
                 raise AccessError(_('%d karma required to edit a post.') % post.karma_edit)
     return super(Post, self).get_mail_message_access(res_ids, operation, model_name=model_name)
Exemplo n.º 9
0
 def unlink(self):
     for post in self:
         if not post.can_unlink:
             raise AccessError(_('%d karma required to unlink a post.') % post.karma_unlink)
     # if unlinking an answer with accepted answer: remove provided karma
     for post in self:
         if post.is_correct:
             post.create_uid.sudo().add_karma(post.forum_id.karma_gen_answer_accepted * -1)
             self.env.user.sudo().add_karma(post.forum_id.karma_gen_answer_accepted * -1)
     return super(Post, self).unlink()
Exemplo n.º 10
0
    def convert_comment_to_answer(self, message_id, default=None):
        """ Tool to convert a comment (mail.message) into an answer (forum.post).
        The original comment is unlinked and a new answer from the comment's author
        is created. Nothing is done if the comment's author already answered the
        question. """
        comment = self.env['mail.message'].sudo().browse(message_id)
        post = self.browse(comment.res_id)
        if not comment.author_id or not comment.author_id.user_ids:  # only comment posted by users can be converted
            return False

        # karma-based action check: must check the message's author to know if own / all
        is_author = comment.author_id.id == self.env.user.partner_id.id
        karma_own = post.forum_id.karma_comment_convert_own
        karma_all = post.forum_id.karma_comment_convert_all
        karma_convert = is_author and karma_own or karma_all
        can_convert = self.env.user.karma >= karma_convert
        if not can_convert:
            if is_author and karma_own < karma_all:
                raise AccessError(_('%d karma required to convert your comment to an answer.') % karma_own)
            else:
                raise AccessError(_('%d karma required to convert a comment to an answer.') % karma_all)

        # check the message's author has not already an answer
        question = post.parent_id if post.parent_id else post
        post_create_uid = comment.author_id.user_ids[0]
        if any(answer.create_uid.id == post_create_uid.id for answer in question.child_ids):
            return False

        # create the new post
        post_values = {
            'forum_id': question.forum_id.id,
            'content': comment.body,
            'parent_id': question.id,
            'name': _('Re: %s') % (question.name or ''),
        }
        # done with the author user to have create_uid correctly set
        new_post = self.with_user(post_create_uid).create(post_values)

        # delete comment
        comment.unlink()

        return new_post
Exemplo n.º 11
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
Exemplo n.º 12
0
    def create(self, vals_list):
        records = super(WebsitePublishedMixin, self).create(vals_list)
        is_publish_modified = any([
            set(v.keys()) & {'is_published', 'website_published'}
            for v in vals_list
        ])
        if is_publish_modified and not all(record.can_publish
                                           for record in records):
            raise AccessError(self._get_can_publish_error_message())

        return records
Exemplo n.º 13
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)
         ])
Exemplo n.º 14
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)])
Exemplo n.º 15
0
    def create(self, vals):
        if 'content' in vals and vals.get('forum_id'):
            vals['content'] = self._update_content(vals['content'], vals['forum_id'])

        post = super(Post, self.with_context(mail_create_nolog=True)).create(vals)
        # deleted or closed questions
        if post.parent_id and (post.parent_id.state == 'close' or post.parent_id.active is False):
            raise UserError(_('Posting answer on a [Deleted] or [Closed] question is not possible.'))
        # karma-based access
        if not post.parent_id and not post.can_ask:
            raise AccessError(_('%d karma required to create a new question.') % post.forum_id.karma_ask)
        elif post.parent_id and not post.can_answer:
            raise AccessError(_('%d karma required to answer a question.') % post.forum_id.karma_answer)
        if not post.parent_id and not post.can_post:
            post.sudo().state = 'pending'

        # add karma for posting new questions
        if not post.parent_id and post.state == 'active':
            self.env.user.sudo().add_karma(post.forum_id.karma_gen_question_new)
        post.post_notification()
        return post
Exemplo n.º 16
0
 def _compute_kpi_pos_total_value(self):
     if not self.env.user.has_group('point_of_sale.group_pos_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_pos_total_value = sum(self.env['pos.order'].search([
             ('date_order', '>=', start), ('date_order', '<', end),
             ('state', 'not in', ['draft', 'cancel', 'invoiced']),
             ('company_id', '=', company.id)
         ]).mapped('amount_total'))
Exemplo n.º 17
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
Exemplo n.º 18
0
    def _update_content(self, content, forum_id):
        forum = self.env['forum.forum'].browse(forum_id)
        if content and self.env.user.karma < forum.karma_dofollow:
            for match in re.findall(r'<a\s.*href=".*?">', content):
                match = re.escape(match)  # replace parenthesis or special char in regex
                content = re.sub(match, match[:3] + 'rel="nofollow" ' + match[3:], content)

        if self.env.user.karma <= forum.karma_editor:
            filter_regexp = r'(<img.*?>)|(<a[^>]*?href[^>]*?>)|(<[a-z|A-Z]+[^>]*style\s*=\s*[\'"][^\'"]*\s*background[^:]*:[^url;]*url)'
            content_match = re.search(filter_regexp, content, re.I)
            if content_match:
                raise AccessError(_('%d karma required to post an image or link.') % forum.karma_editor)
        return content
Exemplo n.º 19
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)])
Exemplo n.º 20
0
    def run(self):
        """ Runs the server action. For each server action, the
        run_action_<STATE> method is called. This allows easy overriding
        of the server actions.

        :param dict context: context should contain following keys

                             - active_id: id of the current object (single mode)
                             - active_model: current model that should equal the action's model

                             The following keys are optional:

                             - active_ids: ids of the current records (mass mode). If active_ids
                               and active_id are present, active_ids is given precedence.

        :return: an action_id to be executed, or False is finished correctly without
                 return action
        """
        res = False
        for action in self:
            action_groups = action.groups_id
            if action_groups and not (action_groups & self.env.user.groups_id):
                raise AccessError(
                    _("You don't have enough access rights to run this action."
                      ))

            eval_context = self._get_eval_context(action)
            if hasattr(self, 'run_action_%s_multi' % action.state):
                # call the multi method
                run_self = self.with_context(eval_context['env'].context)
                func = getattr(run_self, 'run_action_%s_multi' % action.state)
                res = func(action, eval_context=eval_context)

            elif hasattr(self, 'run_action_%s' % action.state):
                active_id = self._context.get('active_id')
                if not active_id and self._context.get('onchange_self'):
                    active_id = self._context['onchange_self']._origin.id
                    if not active_id:  # onchange on new record
                        func = getattr(self, 'run_action_%s' % action.state)
                        res = func(action, eval_context=eval_context)
                active_ids = self._context.get(
                    'active_ids', [active_id] if active_id else [])
                for active_id in active_ids:
                    # run context dedicated to a particular active_id
                    run_self = self.with_context(active_ids=[active_id],
                                                 active_id=active_id)
                    eval_context["env"].context = run_self._context
                    # call the single method related to the action: run_action_<STATE>
                    func = getattr(run_self, 'run_action_%s' % action.state)
                    res = func(action, eval_context=eval_context)
        return res or False
Exemplo n.º 21
0
 def validate(self):
     for post in self:
         if not post.can_moderate:
             raise AccessError(_('%d karma required to validate a post.') % post.forum_id.karma_moderate)
         # if state == pending, no karma previously added for the new question
         if post.state == 'pending':
             post.create_uid.sudo().add_karma(post.forum_id.karma_gen_question_new)
         post.write({
             'state': 'active',
             'active': True,
             'moderator_id': self.env.user.id,
         })
         post.post_notification()
     return True
Exemplo n.º 22
0
    def force_storage(self):
        """Force all attachments to be stored in the currently configured storage"""
        if not self.env.is_admin():
            raise AccessError(
                _('Only administrators can execute this action.'))

        # domain to retrieve the attachments to migrate
        domain = {
            'db': [('store_fname', '!=', False)],
            'file': [('db_datas', '!=', False)],
        }[self._storage()]

        for attach in self.search(domain):
            attach.write({'datas': attach.datas})
        return True
Exemplo n.º 23
0
 def _compute_kpi_website_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()
         confirmed_website_sales = self.env['sale.order'].search([
             ('date_order', '>=', start), ('date_order', '<', end),
             ('state', 'not in', ['draft', 'cancel', 'sent']),
             ('website_id', '!=', False), ('company_id', '=', company.id)
         ])
         record.kpi_website_sale_total_value = sum(
             confirmed_website_sales.mapped('amount_total'))
Exemplo n.º 24
0
 def check_access_rule(self, operation):
     """ Add Access rules of mail.message for non-employee user:
         - read:
             - raise if the type is comment and subtype NULL (internal note)
     """
     if self.user_has_groups('base.group_public'):
         self.env.cr.execute(
             'SELECT id FROM "%s" WHERE website_published IS NOT TRUE AND id = ANY (%%s)'
             % (self._table), (self.ids, ))
         if self.env.cr.fetchall():
             raise AccessError(
                 _('The requested operation cannot be completed due to security restrictions. Please contact your system administrator.\n\n(Document type: %s, Operation: %s)'
                   ) % (self._description, operation) +
                 ' - ({} {}, {} {})'.format(_('Records:'), self.ids[:6],
                                            _('User:'), self._uid))
     return super(MailMessage, self).check_access_rule(operation=operation)
Exemplo n.º 25
0
 def mark_as_offensive(self, reason_id):
     for post in self:
         if not post.can_moderate:
             raise AccessError(_('%d karma required to mark a post as offensive.') % post.forum_id.karma_moderate)
         # remove some karma
         _logger.info('Downvoting user <%s> for posting spam/offensive contents', post.create_uid)
         post.create_uid.sudo().add_karma(post.forum_id.karma_gen_answer_flagged)
         # TODO: potential bottleneck, could be done in batch
         post.write({
             'state': 'offensive',
             'moderator_id': self.env.user.id,
             'closed_date': fields.Datetime.now(),
             'closed_reason_id': reason_id,
             'active': False,
         })
     return True
Exemplo n.º 26
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
Exemplo n.º 27
0
 def message_post(self, *, parent_id=False, subtype=None, **kwargs):
     """ Temporary workaround to avoid spam. If someone replies on a channel
     through the 'Presentation Published' email, it should be considered as a
     note as we don't want all channel followers to be notified of this answer. """
     self.ensure_one()
     if kwargs.get('message_type') == 'comment' and not self.can_review:
         raise AccessError(_('Not enough karma to review'))
     if parent_id:
         parent_message = self.env['mail.message'].sudo().browse(parent_id)
         if parent_message.subtype_id and parent_message.subtype_id == self.env.ref(
                 'website_slides.mt_channel_slide_published'):
             if kwargs.get('subtype_id'):
                 kwargs['subtype_id'] = False
             subtype = 'mail.mt_note'
     return super(Channel, self).message_post(parent_id=parent_id,
                                              subtype=subtype,
                                              **kwargs)
Exemplo n.º 28
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
         ])
Exemplo n.º 29
0
    def write(self, vals):
        trusted_keys = ['active', 'is_correct', 'tag_ids']  # fields where security is checked manually
        if 'content' in vals:
            vals['content'] = self._update_content(vals['content'], self.forum_id.id)

        tag_ids = False
        if 'tag_ids' in vals:
            tag_ids = set(tag.get('id') for tag in self.resolve_2many_commands('tag_ids', vals['tag_ids']))

        for post in self:
            if 'state' in vals:
                if vals['state'] in ['active', 'close']:
                    if not post.can_close:
                        raise AccessError(_('%d karma required to close or reopen a post.') % post.karma_close)
                    trusted_keys += ['state', 'closed_uid', 'closed_date', 'closed_reason_id']
                elif vals['state'] == 'flagged':
                    if not post.can_flag:
                        raise AccessError(_('%d karma required to flag a post.') % post.forum_id.karma_flag)
                    trusted_keys += ['state', 'flag_user_id']
            if 'active' in vals:
                if not post.can_unlink:
                    raise AccessError(_('%d karma required to delete or reactivate a post.') % post.karma_unlink)
            if 'is_correct' in vals:
                if not post.can_accept:
                    raise AccessError(_('%d karma required to accept or refuse an answer.') % post.karma_accept)
                # update karma except for self-acceptance
                mult = 1 if vals['is_correct'] else -1
                if vals['is_correct'] != post.is_correct and post.create_uid.id != self._uid:
                    post.create_uid.sudo().add_karma(post.forum_id.karma_gen_answer_accepted * mult)
                    self.env.user.sudo().add_karma(post.forum_id.karma_gen_answer_accept * mult)
            if tag_ids:
                if set(post.tag_ids.ids) != tag_ids and self.env.user.karma < post.forum_id.karma_edit_retag:
                    raise AccessError(_('%d karma required to retag.') % post.forum_id.karma_edit_retag)
            if any(key not in trusted_keys for key in vals) and not post.can_edit:
                raise AccessError(_('%d karma required to edit a post.') % post.karma_edit)

        res = super(Post, self).write(vals)

        # if post content modify, notify followers
        if 'content' in vals or 'name' in vals:
            for post in self:
                if post.parent_id:
                    body, subtype = _('Answer Edited'), 'website_forum.mt_answer_edit'
                    obj_id = post.parent_id
                else:
                    body, subtype = _('Question Edited'), 'website_forum.mt_question_edit'
                    obj_id = post
                obj_id.message_post(body=body, subtype=subtype)
        if 'active' in vals:
            answers = self.env['forum.post'].with_context(active_test=False).search([('parent_id', 'in', self.ids)])
            if answers:
                answers.write({'active': vals['active']})
        return res
Exemplo n.º 30
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()

        result = self._install_modules(to_install)

        if result 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',
        }