Ejemplo n.º 1
0
 def _raise_publish_error(self, *args, **kwargs):
     raise NotModifiedError()
Ejemplo n.º 2
0
    def publish(self, review_request=None, user=None, trivial=False,
                send_notification=True, validate_fields=True, timestamp=None):

        """Publish this draft.

        This is an internal method. Programmatic publishes should use
        :py:meth:`reviewboard.reviews.models.review_request.ReviewRequest.publish`
        instead.

        This updates and returns the draft's ChangeDescription, which
        contains the changed fields. This is used by the e-mail template
        to tell people what's new and interesting.

        The keys that may be saved in ``fields_changed`` in the
        ChangeDescription are:

        *  ``submitter``
        *  ``summary``
        *  ``description``
        *  ``testing_done``
        *  ``bugs_closed``
        *  ``depends_on``
        *  ``branch``
        *  ``target_groups``
        *  ``target_people``
        *  ``screenshots``
        *  ``screenshot_captions``
        *  ``diff``
        *  Any custom field IDs

        Each field in 'fields_changed' represents a changed field. This will
        save fields in the standard formats as defined by the
        'ChangeDescription' documentation, with the exception of the
        'screenshot_captions' and 'diff' fields.

        For the 'screenshot_captions' field, the value will be a dictionary
        of screenshot ID/dict pairs with the following fields:

        * ``old``: The old value of the field
        * ``new``: The new value of the field

        For the ``diff`` field, there is only ever an ``added`` field,
        containing the ID of the new diffset.

        Args:
            review_request (reviewboard.reviews.models.review_request.
                            ReviewRequest, optional):
                The review request associated with this diff. If not provided,
                it will be looked up.

            user (django.contrib.auth.models.User, optional):
                The user publishing the draft. If not provided, this defaults
                to the review request submitter.

            trivial (bool, optional):
                Whether or not this is a trivial publish.

                Trivial publishes do not result in e-mail notifications.

            send_notification (bool, optional):
                Whether or not this will emit the
                :py:data:`reviewboard.reviews.signals.review_request_published`
                signal.

                This parameter is intended for internal use **only**.

            validate_fields (bool, optional):
                Whether or not the fields should be validated.

                This should only be ``False`` in the case of programmatic
                publishes, e.g., from close as submitted hooks.

            timestamp (datetime.datetime, optional):
                The datetime that should be used for all timestamps for objects
                published
                (:py:class:`~reviewboard.diffviewer.models.diff_set.DiffSet`,
                :py:class:`~reviewboard.changedescs.models.ChangeDescription`)
                over the course of the method.

        Returns:
            reviewboard.changedescs.models.ChangeDescription:
            The change description that results from this publish (if any).

            If this is an initial publish, there will be no change description
            (and this function will return ``None``).
        """
        if timestamp is None:
            timestamp = timezone.now()

        if not review_request:
            review_request = self.review_request

        if not self.changedesc and review_request.public:
            self.changedesc = ChangeDescription()

        if not user:
            if self.changedesc:
                user = self.changedesc.get_user(self)
            else:
                user = review_request.submitter

        self.copy_fields_to_request(review_request)

        # If no changes were made, raise exception and do not save
        if self.changedesc and not self.changedesc.has_modified_fields():
            raise NotModifiedError()

        if validate_fields:
            if not (self.target_groups.exists() or
                    self.target_people.exists()):
                raise PublishError(
                    ugettext('There must be at least one reviewer before this '
                             'review request can be published.'))

            if not review_request.summary.strip():
                raise PublishError(
                    ugettext('The draft must have a summary.'))

            if not review_request.description.strip():
                raise PublishError(
                    ugettext('The draft must have a description.'))

        if self.diffset:
            self.diffset.history = review_request.diffset_history
            self.diffset.timestamp = timestamp
            self.diffset.save(update_fields=('history', 'timestamp'))

        if self.changedesc:
            self.changedesc.user = user
            self.changedesc.timestamp = timestamp
            self.changedesc.public = True
            self.changedesc.save()
            review_request.changedescs.add(self.changedesc)

        review_request.description_rich_text = self.description_rich_text
        review_request.testing_done_rich_text = self.testing_done_rich_text
        review_request.rich_text = self.rich_text
        review_request.save()

        if send_notification:
            review_request_published.send(sender=type(review_request),
                                          user=user,
                                          review_request=review_request,
                                          trivial=trivial,
                                          changedesc=self.changedesc)

        return self.changedesc
Ejemplo n.º 3
0
    def publish(self,
                review_request=None,
                user=None,
                trivial=False,
                send_notification=True):
        """Publishes this draft.

        This updates and returns the draft's ChangeDescription, which
        contains the changed fields. This is used by the e-mail template
        to tell people what's new and interesting.

        The draft's associated ReviewRequest object will be used if one isn't
        passed in.

        The keys that may be saved in ``fields_changed`` in the
        ChangeDescription are:

        *  ``submitter``
        *  ``summary``
        *  ``description``
        *  ``testing_done``
        *  ``bugs_closed``
        *  ``depends_on``
        *  ``branch``
        *  ``target_groups``
        *  ``target_people``
        *  ``screenshots``
        *  ``screenshot_captions``
        *  ``diff``
        *  Any custom field IDs

        Each field in 'fields_changed' represents a changed field. This will
        save fields in the standard formats as defined by the
        'ChangeDescription' documentation, with the exception of the
        'screenshot_captions' and 'diff' fields.

        For the 'screenshot_captions' field, the value will be a dictionary
        of screenshot ID/dict pairs with the following fields:

        * ``old``: The old value of the field
        * ``new``: The new value of the field

        For the ``diff`` field, there is only ever an ``added`` field,
        containing the ID of the new diffset.

        The ``send_notification`` parameter is intended for internal use only,
        and is there to prevent duplicate notifications when being called by
        ReviewRequest.publish.
        """
        if not review_request:
            review_request = self.review_request

        if not self.changedesc and review_request.public:
            self.changedesc = ChangeDescription()

        if not user:
            if self.changedesc:
                user = self.changedesc.get_user(self)
            else:
                user = review_request.submitter

        self.copy_fields_to_request(review_request)

        if self.diffset:
            self.diffset.history = review_request.diffset_history
            self.diffset.save(update_fields=['history'])

        # If no changes were made, raise exception and do not save
        if self.changedesc and not self.changedesc.has_modified_fields():
            raise NotModifiedError()

        if self.changedesc:
            self.changedesc.user = user
            self.changedesc.timestamp = timezone.now()
            self.changedesc.public = True
            self.changedesc.save()
            review_request.changedescs.add(self.changedesc)

        review_request.description_rich_text = self.description_rich_text
        review_request.testing_done_rich_text = self.testing_done_rich_text
        review_request.rich_text = self.rich_text
        review_request.save()

        if send_notification:
            review_request_published.send(sender=review_request.__class__,
                                          user=user,
                                          review_request=review_request,
                                          trivial=trivial,
                                          changedesc=self.changedesc)

        return self.changedesc
Ejemplo n.º 4
0
    def publish(self, review_request=None, user=None, send_notification=True):
        """Publishes this draft.

        This updates and returns the draft's ChangeDescription, which
        contains the changed fields. This is used by the e-mail template
        to tell people what's new and interesting.

        The draft's assocated ReviewRequest object will be used if one isn't
        passed in.

        The keys that may be saved in 'fields_changed' in the
        ChangeDescription are:

           *  'summary'
           *  'description'
           *  'testing_done'
           *  'bugs_closed'
           *  'depends_on'
           *  'branch'
           *  'target_groups'
           *  'target_people'
           *  'screenshots'
           *  'screenshot_captions'
           *  'diff'

        Each field in 'fields_changed' represents a changed field. This will
        save fields in the standard formats as defined by the
        'ChangeDescription' documentation, with the exception of the
        'screenshot_captions' and 'diff' fields.

        For the 'screenshot_captions' field, the value will be a dictionary
        of screenshot ID/dict pairs with the following fields:

           * 'old': The old value of the field
           * 'new': The new value of the field

        For the 'diff' field, there is only ever an 'added' field, containing
        the ID of the new diffset.

        The 'send_notification' parameter is intended for internal use only,
        and is there to prevent duplicate notifications when being called by
        ReviewRequest.publish.
        """
        if not review_request:
            review_request = self.review_request

        if not user:
            user = review_request.submitter

        if not self.changedesc and review_request.public:
            self.changedesc = ChangeDescription()

        def update_list(a, b, name, record_changes=True, name_field=None):
            aset = set([x.id for x in a.all()])
            bset = set([x.id for x in b.all()])

            if aset.symmetric_difference(bset):
                if record_changes and self.changedesc:
                    self.changedesc.record_field_change(
                        name, a.all(), b.all(), name_field)

                a.clear()
                for item in b.all():
                    a.add(item)

        for field_cls in get_review_request_fields():
            field = field_cls(review_request)

            if field.can_record_change_entry:
                old_value = field.load_value(review_request)
                new_value = field.load_value(self)

                if field.has_value_changed(old_value, new_value):
                    field.save_value(new_value)

                    if self.changedesc:
                        field.record_change_entry(self.changedesc, old_value,
                                                  new_value)

        # Screenshots are a bit special.  The list of associated screenshots
        # can change, but so can captions within each screenshot.
        screenshots = list(self.screenshots.all())
        caption_changes = {}

        for s in review_request.screenshots.all():
            if s in screenshots and s.caption != s.draft_caption:
                caption_changes[s.id] = {
                    'old': (s.caption, ),
                    'new': (s.draft_caption, ),
                }

                s.caption = s.draft_caption
                s.save(update_fields=['caption'])

        # Now scan through again and set the caption correctly for newly-added
        # screenshots by copying the draft_caption over. We don't need to
        # include this in the changedescs here because it's a new screenshot,
        # and update_list will record the newly-added item.
        for s in screenshots:
            if s.caption != s.draft_caption:
                s.caption = s.draft_caption
                s.save(update_fields=['caption'])

        if caption_changes and self.changedesc:
            self.changedesc.fields_changed['screenshot_captions'] = \
                caption_changes

        update_list(review_request.screenshots,
                    self.screenshots,
                    'screenshots',
                    name_field="caption")

        # There's no change notification required for this field.
        review_request.inactive_screenshots = self.inactive_screenshots.all()

        # Files are treated like screenshots. The list of files can
        # change, but so can captions within each file.
        files = list(self.file_attachments.all())
        caption_changes = {}

        for f in review_request.file_attachments.all():
            if f in files and f.caption != f.draft_caption:
                caption_changes[f.id] = {
                    'old': (f.caption, ),
                    'new': (f.draft_caption, ),
                }

                f.caption = f.draft_caption
                f.save(update_fields=['caption'])

        # Now scan through again and set the caption correctly for newly-added
        # files by copying the draft_caption over. We don't need to include
        # this in the changedescs here because it's a new screenshot, and
        # update_list will record the newly-added item.
        for f in files:
            if f.caption != f.draft_caption:
                f.caption = f.draft_caption
                f.save(update_fields=['caption'])

        if caption_changes and self.changedesc:
            self.changedesc.fields_changed['file_captions'] = caption_changes

        update_list(review_request.file_attachments,
                    self.file_attachments,
                    'files',
                    name_field="display_name")

        # There's no change notification required for this field.
        review_request.inactive_file_attachments = \
            self.inactive_file_attachments.all()

        if self.diffset:
            self.diffset.history = review_request.diffset_history
            self.diffset.save(update_fields=['history'])

        # If no changes were made, raise exception and do not save
        if self.changedesc and not self.changedesc.has_modified_fields():
            raise NotModifiedError()

        if self.changedesc:
            self.changedesc.timestamp = timezone.now()
            self.changedesc.rich_text = self.rich_text
            self.changedesc.public = True
            self.changedesc.save()
            review_request.changedescs.add(self.changedesc)

        review_request.rich_text = self.rich_text
        review_request.save()

        if send_notification:
            review_request_published.send(sender=review_request.__class__,
                                          user=user,
                                          review_request=review_request,
                                          changedesc=self.changedesc)

        return self.changedesc