コード例 #1
0
    def serialize_object(self, obj, request=None, *args, **kwargs):
        """Serialize a diff comment.

        Args:
            obj (reviewboard.reviews.models.diff_comment.Comment):
                The diff comment to serialize.

            request (django.http.HttpRequest, optional):
                The HTTP request from the client.

            *args (tuple):
                Additional positional arguments.

            **kwargs (dict):
                Additional keyword arguments.

        Returns:
            dict:
            The serialized diff comment.
        """
        result = super(ReviewDiffCommentResource, self).serialize_object(
            obj, request=request, *args, **kwargs)

        if not dvcs_feature.is_enabled(request=request):
            result.pop('base_filediff_id', None)

        return result
コード例 #2
0
    def serialize_object(self, obj, request=None, *args, **kwargs):
        """Serialize a diff comment.

        Args:
            obj (reviewboard.reviews.models.diff_comment.Comment):
                The diff comment to serialize.

            request (django.http.HttpRequest, optional):
                The HTTP request from the client.

            *args (tuple):
                Additional positional arguments.

            **kwargs (dict):
                Additional keyword arguments.

        Returns:
            dict:
            The serialized diff comment.
        """
        result = super(ReviewDiffCommentResource, self).serialize_object(
            obj, request=request, *args, **kwargs)

        if not dvcs_feature.is_enabled(request=request):
            result.pop('base_filediff_id', None)

        return result
コード例 #3
0
ファイル: diff.py プロジェクト: ns-ancan/reviewboard
    def serialize_object(self, obj, request=None, *args, **kwargs):
        """Serialize a DiffSet.

        This method excludes fields from features that are not enabled.

        Args:
            obj (reviewboard.diffviewer.models.diffset.DiffSet):
                The DiffSet to serialize.

            request (django.http.HttpRequest, optional):
                The HTTP request from the client.

            *args (tuple):
                Additional positional arguments.

            **kwargs (dict):
                Additional keyword arguments.

        Returns:
            dict:
            The serialized DiffSet.
        """
        result = super(DiffResource, self).serialize_object(obj,
                                                            request=request,
                                                            *args,
                                                            **kwargs)

        if not dvcs_feature.is_enabled(request=request):
            # The field may not have been serialized (e.g., if `only-fields`
            # was set to a subset of fields that excludes
            # `created_with_history`).
            result.pop('commit_count', None)

        return result
コード例 #4
0
ファイル: diff.py プロジェクト: chipx86/reviewboard
    def serialize_object(self, obj, request=None, *args, **kwargs):
        """Serialize a DiffSet.

        This method excludes fields from features that are not enabled.

        Args:
            obj (reviewboard.diffviewer.models.diffset.DiffSet):
                The DiffSet to serialize.

            request (django.http.HttpRequest, optional):
                The HTTP request from the client.

            *args (tuple):
                Additional positional arguments.

            **kwargs (dict):
                Additional keyword arguments.

        Returns:
            dict:
            The serialized DiffSet.
        """
        result = super(DiffResource, self).serialize_object(
            obj, request=request, *args, **kwargs)

        if not dvcs_feature.is_enabled(request=request):
            # The field may not have been serialized (e.g., if `only-fields`
            # was set to a subset of fields that excludes
            # `created_with_history`).
            result.pop('commit_count', None)

        return result
コード例 #5
0
    def test_get_capability_dvcs_disabled(self):
        """Testing the GET / API for capabilities with the DVCS feature
        disabled
        """
        with override_feature_check(dvcs_feature.feature_id, False):
            self.assertFalse(dvcs_feature.is_enabled())
            rsp = self.api_get(get_root_url(),
                               expected_mimetype=root_item_mimetype)

        self.assertEqual(rsp['stat'], 'ok')
        self.assertIn('capabilities', rsp)

        caps = rsp['capabilities']
        self.assertIn('review_requests', caps)
        self.assertNotIn('supports_history', caps['review_requests'])
コード例 #6
0
    def create_comment(self,
                       request,
                       comments_m2m,
                       base_filediff_id=None,
                       **kwargs):
        """Create a review comment.

        Args:
            request (django.http.HttpRequest):
                The HTTP request from the client.

            comments_m2m (django.db.models.ManyToManyField):
                The review's comments relation, where the new comment will be
                added.

            base_filediff_id (int, optional):
                The ID of the base filediff for the :term:`cumulative diff` the
                comment is on.

            **kwargs (dict):
                Additional keyword arguments to pass on to the base class
                method.

        Returns:
            tuple or djblets.webapi.errors.WebAPIError:
            Either a successful payload containing the comment, or an error
            payload.
        """
        rsp = super(ReviewDiffCommentResource,
                    self).create_comment(comments_m2m=comments_m2m,
                                         save=False,
                                         **kwargs)

        if (isinstance(rsp, tuple) and isinstance(rsp[1], dict)
                and self.item_result_key in rsp[1]):
            comment = rsp[1][self.item_result_key]

            if (base_filediff_id is not None
                    and dvcs_feature.is_enabled(request=request)):
                comment.base_filediff_id = base_filediff_id

            comment.save()
            comments_m2m.add(comment)

        return rsp
コード例 #7
0
    def get_links(self,
                  child_resources=[],
                  obj=None,
                  request=None,
                  *args,
                  **kwargs):
        """Return the links for the resource.

        This method will filter out the draft diffcommit resource when the DVCS
        feature is disabled.

        Args:
            child_resources (list of djblets.webapi.resources.base.
                             WebAPIResource):
                The child resources for which links will be serialized.

            review_request_id (unicode):
                A string represenation of the ID of the review request for
                which links are being returned.

            request (django.http.HttpRequest):
                The HTTP request from the client.

            *args (tuple):
                Additional positional arguments.

            **kwargs (dict):
                Additional keyword arguments.

        Returns:
            dict:
            A dictionary of the links for the resource.
        """
        if (obj is not None and not dvcs_feature.is_enabled()
                and resources.draft_diffcommit in child_resources):
            child_resources = list(child_resources)
            child_resources.remove(resources.draft_diffcommit)

        return super(ReviewRequestDraftResource,
                     self).get_links(child_resources,
                                     obj=obj,
                                     request=request,
                                     *args,
                                     **kwargs)
コード例 #8
0
    def create_comment(self, request, comments_m2m, base_filediff_id=None,
                       **kwargs):
        """Create a review comment.

        Args:
            request (django.http.HttpRequest):
                The HTTP request from the client.

            comments_m2m (django.db.models.ManyToManyField):
                The review's comments relation, where the new comment will be
                added.

            base_filediff_id (int, optional):
                The ID of the base filediff for the :term:`cumulative diff` the
                comment is on.

            **kwargs (dict):
                Additional keyword arguments to pass on to the base class
                method.

        Returns:
            tuple or djblets.webapi.errors.WebAPIError:
            Either a successful payload containing the comment, or an error
            payload.
        """
        rsp = super(ReviewDiffCommentResource, self).create_comment(
            comments_m2m=comments_m2m,
            save=False,
            **kwargs)

        if (isinstance(rsp, tuple) and
            isinstance(rsp[1], dict) and
            self.item_result_key in rsp[1]):
            comment = rsp[1][self.item_result_key]

            if (base_filediff_id is not None and
                dvcs_feature.is_enabled(request=request)):
                comment.base_filediff_id = base_filediff_id

            comment.save()
            comments_m2m.add(comment)

        return rsp
コード例 #9
0
ファイル: diff.py プロジェクト: ns-ancan/reviewboard
    def get_links(self,
                  child_resources=[],
                  obj=None,
                  request=None,
                  *args,
                  **kwargs):
        """Return the links for the resource.

        If the DVCS feature is disabled, links to resources that require the
        feature will not be included.

        Args:
            child_resource (list of reviewboard.webapi.base.WebAPIResource):
                The list of child resources for which links are to be
                serialized.

            obj (reviewboard.diffviewer.models.diffset.DiffSet, optional):
                The object whose links are being serialized.

            request (django.http.HttpRequest, optional):
                The HTTP request from the client.

            *args (tuple):
                Additional positional arguments.

            **kwargs (dict):
                Additional keyword arguments.

        Returns:
            dict:
            A dictionary of serialized links for the resource.
        """
        if (obj is not None and not dvcs_feature.is_enabled(request=request)
                and resources.diffcommit in child_resources):
            child_resources = list(child_resources)
            child_resources.remove(resources.diffcommit)

        return super(DiffResource, self).get_links(child_resources,
                                                   obj=obj,
                                                   request=request,
                                                   *args,
                                                   **kwargs)
コード例 #10
0
    def get_links(self, child_resources=[], obj=None, request=None,
                  *args, **kwargs):
        """Return the links for the resource.

        This method will filter out the draft diffcommit resource when the DVCS
        feature is disabled.

        Args:
            child_resources (list of djblets.webapi.resources.base.
                             WebAPIResource):
                The child resources for which links will be serialized.

            review_request_id (unicode):
                A string represenation of the ID of the review request for
                which links are being returned.

            request (django.http.HttpRequest):
                The HTTP request from the client.

            *args (tuple):
                Additional positional arguments.

            **kwargs (dict):
                Additional keyword arguments.

        Returns:
            dict:
            A dictionary of the links for the resource.
        """
        if (obj is not None and
            not dvcs_feature.is_enabled() and
            resources.draft_diffcommit in child_resources):
            child_resources = list(child_resources)
            child_resources.remove(resources.draft_diffcommit)

        return super(ReviewRequestDraftResource, self).get_links(
            child_resources, obj=obj, request=request, *args, **kwargs)
コード例 #11
0
ファイル: diff.py プロジェクト: chipx86/reviewboard
    def get_links(self, child_resources=[], obj=None, request=None,
                  *args, **kwargs):
        """Return the links for the resource.

        If the DVCS feature is disabled, links to resources that require the
        feature will not be included.

        Args:
            child_resource (list of reviewboard.webapi.base.WebAPIResource):
                The list of child resources for which links are to be
                serialized.

            obj (reviewboard.diffviewer.models.diffset.DiffSet, optional):
                The object whose links are being serialized.

            request (django.http.HttpRequest, optional):
                The HTTP request from the client.

            *args (tuple):
                Additional positional arguments.

            **kwargs (dict):
                Additional keyword arguments.

        Returns:
            dict:
            A dictionary of serialized links for the resource.
        """
        if (obj is not None and
            not dvcs_feature.is_enabled(request=request) and
            resources.diffcommit in child_resources):
            child_resources = list(child_resources)
            child_resources.remove(resources.diffcommit)

        return super(DiffResource, self).get_links(
            child_resources, obj=obj, request=request, *args, **kwargs)
コード例 #12
0
    def update(self,
               request,
               finalize_commit_series=False,
               validation_info=None,
               extra_fields={},
               *args,
               **kwargs):
        """Update a diff.

        This is used for two purposes:

        1. For updating extra data on a draft diff.

           Extra data can be stored later lookup. See
           :ref:`webapi2.0-extra-data` for more information.

        2. For finalization of a draft diff on a review request created with
           commit history.
        """
        try:
            review_request = resources.review_request.get_object(
                request, *args, **kwargs)
            diffset = self.get_object(request, *args, **kwargs)
        except ObjectDoesNotExist:
            return DOES_NOT_EXIST

        if not review_request.is_mutable_by(request.user):
            return self.get_no_access_error(request)

        if extra_fields:
            try:
                self.import_extra_data(diffset, diffset.extra_data,
                                       extra_fields)
            except ImportExtraDataError as e:
                return e.error_payload

        if finalize_commit_series:
            if review_request.created_with_history:
                cumulative_diff = request.FILES.get('cumulative_diff')
                parent_diff = request.FILES.get('parent_diff')

                error_rsp = self._finalize_commit_series(
                    request, diffset, cumulative_diff, parent_diff,
                    validation_info)

                if error_rsp is not None:
                    return error_rsp

                # Only add default reviewers if this is the first time we've
                # published any diffsets.
                if review_request.can_add_default_reviewers():
                    diffset.review_request_draft.get().add_default_reviewers()
            elif dvcs_feature.is_enabled(request=request):
                return INVALID_ATTRIBUTE, {
                    'reason':
                    'This review request was not created with '
                    'commit history support.',
                }
            else:
                # Otherwise we silently ignore this option.
                finalize_commit_series = False

        if extra_fields or finalize_commit_series:
            diffset.save(update_fields=('extra_data', ))

        return 200, {
            self.item_result_key: diffset,
        }
コード例 #13
0
ファイル: diff.py プロジェクト: chipx86/reviewboard
    def create(self, request, extra_fields={}, local_site=None, *args,
               **kwargs):
        """Creates a new diff by parsing an uploaded diff file.

        This will implicitly create the new Review Request draft, which can
        be updated separately and then published.

        This accepts a unified diff file, validates it, and stores it along
        with the draft of a review request. The new diff will have a revision
        of 0.

        A parent diff can be uploaded along with the main diff. A parent diff
        is a diff based on an existing commit in the repository, which will
        be applied before the main diff. The parent diff will not be included
        in the diff viewer. It's useful when developing a change based on a
        branch that is not yet committed. In this case, a parent diff of the
        parent branch would be provided along with the diff of the new commit,
        and only the new commit will be shown.

        It is expected that the client will send the data as part of a
        :mimetype:`multipart/form-data` mimetype. The main diff's name and
        content would be stored in the ``path`` field. If a parent diff is
        provided, its name and content would be stored in the
        ``parent_diff_path`` field.

        An example of this would be::

            -- SoMe BoUnDaRy
            Content-Disposition: form-data; name=path; filename="foo.diff"

            <Unified Diff Content Here>
            -- SoMe BoUnDaRy --

        Extra data can be stored later lookup. See
        :ref:`webapi2.0-extra-data` for more information.
        """
        # Prevent a circular dependency, as ReviewRequestDraftResource
        # needs DraftDiffResource, which needs DiffResource.
        from reviewboard.webapi.resources.review_request_draft import \
            ReviewRequestDraftResource

        try:
            review_request = \
                resources.review_request.get_object(request, *args, **kwargs)
        except ReviewRequest.DoesNotExist:
            return DOES_NOT_EXIST

        if not review_request.is_mutable_by(request.user):
            return self.get_no_access_error(request)

        if review_request.repository is None:
            return INVALID_ATTRIBUTE, {
                'reason': 'This review request was created as attachments-'
                          'only, with no repository.',
            }
        elif review_request.created_with_history:
            assert dvcs_feature.is_enabled(request=request)

            if 'path' in request.FILES:
                return INVALID_FORM_DATA, {
                    'reason': (
                        'This review request was created with support for '
                        'multiple commits.\n'
                        '\n'
                        'Create an empty diff revision and upload commits to '
                        'that instead.'
                    ),
                }

            diffset = DiffSet.objects.create_empty(
                repository=review_request.repository,
                base_commit_id=request.POST.get('base_commit_id'))
            diffset.update_revision_from_history(
                review_request.diffset_history)
            diffset.save(update_fields=('revision',))
        else:
            form_data = request.POST.copy()
            form = UploadDiffForm(review_request,
                                  data=form_data,
                                  files=request.FILES,
                                  request=request)

            if not form.is_valid():
                return INVALID_FORM_DATA, {
                    'fields': self._get_form_errors(form),
                }

            try:
                diffset = form.create()
            except FileNotFoundError as e:
                return REPO_FILE_NOT_FOUND, {
                    'file': e.path,
                    'revision': six.text_type(e.revision)
                }
            except EmptyDiffError as e:
                return DIFF_EMPTY
            except DiffTooBigError as e:
                return DIFF_TOO_BIG, {
                    'reason': six.text_type(e),
                    'max_size': e.max_diff_size,
                }
            except Exception as e:
                # This could be very wrong, but at least they'll see the error.
                # We probably want a new error type for this.
                logging.error("Error uploading new diff: %s", e, exc_info=1,
                              request=request)

                return INVALID_FORM_DATA, {
                    'fields': {
                        'path': [six.text_type(e)]
                    }
                }

        discarded_diffset = None

        try:
            draft = review_request.draft.get()

            if draft.diffset and draft.diffset != diffset:
                discarded_diffset = draft.diffset
        except ReviewRequestDraft.DoesNotExist:
            try:
                draft = ReviewRequestDraftResource.prepare_draft(
                    request, review_request)
            except PermissionDenied:
                return self.get_no_access_error(request)

        draft.diffset = diffset

        # We only want to add default reviewers the first time.  Was bug 318.
        if review_request.can_add_default_reviewers():
            draft.add_default_reviewers()

        draft.save()

        if extra_fields:
            try:
                self.import_extra_data(diffset, diffset.extra_data,
                                       extra_fields)
            except ImportExtraDataError as e:
                return e.error_payload

            diffset.save(update_fields=['extra_data'])

        if discarded_diffset:
            discarded_diffset.delete()

        # E-mail gets sent when the draft is saved.

        return 201, {
            self.item_result_key: diffset,
        }
コード例 #14
0
    def create(self, request, filediff_id, interfilediff_id=None,
               base_filediff_id=None, *args, **kwargs):
        """Creates a new diff comment.

        This will create a new diff comment on this review. The review
        must be a draft review.

        Extra data can be stored later lookup. See
        :ref:`webapi2.0-extra-data` for more information.
        """
        try:
            review_request = \
                resources.review_request.get_object(request, *args, **kwargs)
            review = resources.review.get_object(request, *args, **kwargs)
        except ObjectDoesNotExist:
            return DOES_NOT_EXIST

        if not resources.review.has_modify_permissions(request, review):
            return self.get_no_access_error(request)

        filediff = None
        interfilediff = None
        invalid_fields = {}

        try:
            filediff = FileDiff.objects.get(
                pk=filediff_id,
                diffset__history__review_request=review_request)
        except ObjectDoesNotExist:
            invalid_fields['filediff_id'] = [
                'This is not a valid filediff ID.',
            ]

        if filediff is None or not dvcs_feature.is_enabled(request=request):
            base_filediff_id = None

        if base_filediff_id is not None:
            if not review_request.created_with_history:
                invalid_fields['base_filediff_id'] = [
                    'This field cannot be specified on review requests '
                    'created without history support.'
                ]
            elif interfilediff_id is not None:
                invalid_fields.update({
                    'base_filediff_id': [
                        'This field cannot be specified with '
                        'interfilediff_id.',
                    ],
                    'interfilediff_id': [
                        'This field cannot be specified with '
                        'base_filediff_id.',
                    ],
                })
            elif base_filediff_id == filediff_id:
                invalid_fields['base_filediff_id'] = [
                    'This cannot be the same as filediff_id.',
                ]

            elif base_filediff_id > filediff_id:
                invalid_fields['base_filediff_id'] = [
                    'This is not a valid base filediff ID.',
                ]
            else:
                base_filediff_exists = (
                    FileDiff.objects
                    .filter(diffset_id=filediff.diffset_id,
                            pk=base_filediff_id)
                    .exclude(commit_id=filediff.commit_id)
                    .exists()
                )

                if not base_filediff_exists:
                    invalid_fields['base_filediff_id'] = [
                        'This is not a valid base filediff ID.',
                    ]
                else:
                    ancestor_ids = (
                        ancestor.pk
                        for ancestor in filediff.get_ancestors(
                            minimal=False)
                    )

                    if base_filediff_id not in ancestor_ids:
                        invalid_fields['base_filediff_id'] = [
                            'This is not a valid base filediff ID.',
                        ]

        if filediff and interfilediff_id:
            if interfilediff_id == filediff.id:
                invalid_fields.setdefault('interfilediff_id', []).append(
                    'This cannot be the same as filediff_id.')
            else:
                try:
                    interfilediff = FileDiff.objects.get(
                        pk=interfilediff_id,
                        diffset__history=filediff.diffset.history)
                except ObjectDoesNotExist:
                    invalid_fields.setdefault('interfilediff_id', []).append(
                        'This is not a valid interfilediff ID.')

        if invalid_fields:
            return INVALID_FORM_DATA, {
                'fields': invalid_fields,
            }

        return self.create_comment(
            request=request,
            review=review,
            comments_m2m=review.comments,
            filediff=filediff,
            interfilediff=interfilediff,
            fields=('filediff', 'interfilediff', 'first_line', 'num_lines'),
            base_filediff_id=base_filediff_id,
            **kwargs)
コード例 #15
0
ファイル: diff.py プロジェクト: ns-ancan/reviewboard
    def create(self,
               request,
               extra_fields={},
               local_site=None,
               *args,
               **kwargs):
        """Creates a new diff by parsing an uploaded diff file.

        This will implicitly create the new Review Request draft, which can
        be updated separately and then published.

        This accepts a unified diff file, validates it, and stores it along
        with the draft of a review request. The new diff will have a revision
        of 0.

        A parent diff can be uploaded along with the main diff. A parent diff
        is a diff based on an existing commit in the repository, which will
        be applied before the main diff. The parent diff will not be included
        in the diff viewer. It's useful when developing a change based on a
        branch that is not yet committed. In this case, a parent diff of the
        parent branch would be provided along with the diff of the new commit,
        and only the new commit will be shown.

        It is expected that the client will send the data as part of a
        :mimetype:`multipart/form-data` mimetype. The main diff's name and
        content would be stored in the ``path`` field. If a parent diff is
        provided, its name and content would be stored in the
        ``parent_diff_path`` field.

        An example of this would be::

            -- SoMe BoUnDaRy
            Content-Disposition: form-data; name=path; filename="foo.diff"

            <Unified Diff Content Here>
            -- SoMe BoUnDaRy --

        Extra data can be stored later lookup. See
        :ref:`webapi2.0-extra-data` for more information.
        """
        # Prevent a circular dependency, as ReviewRequestDraftResource
        # needs DraftDiffResource, which needs DiffResource.
        from reviewboard.webapi.resources.review_request_draft import \
            ReviewRequestDraftResource

        try:
            review_request = \
                resources.review_request.get_object(request, *args, **kwargs)
        except ReviewRequest.DoesNotExist:
            return DOES_NOT_EXIST

        if not review_request.is_mutable_by(request.user):
            return self.get_no_access_error(request)

        if review_request.repository is None:
            return INVALID_ATTRIBUTE, {
                'reason':
                'This review request was created as attachments-'
                'only, with no repository.',
            }
        elif review_request.created_with_history:
            assert dvcs_feature.is_enabled(request=request)

            if 'path' in request.FILES:
                return INVALID_FORM_DATA, {
                    'reason':
                    ('This review request was created with support for '
                     'multiple commits.\n'
                     '\n'
                     'Create an empty diff revision and upload commits to '
                     'that instead.'),
                }

            diffset = DiffSet.objects.create_empty(
                repository=review_request.repository,
                base_commit_id=request.POST.get('base_commit_id'))
            diffset.update_revision_from_history(
                review_request.diffset_history)
            diffset.save(update_fields=('revision', ))
        else:
            form_data = request.POST.copy()
            form = UploadDiffForm(review_request,
                                  data=form_data,
                                  files=request.FILES,
                                  request=request)

            if not form.is_valid():
                return INVALID_FORM_DATA, {
                    'fields': self._get_form_errors(form),
                }

            try:
                diffset = form.create()
            except FileNotFoundError as e:
                return REPO_FILE_NOT_FOUND, {
                    'file': e.path,
                    'revision': six.text_type(e.revision)
                }
            except EmptyDiffError as e:
                return DIFF_EMPTY
            except DiffTooBigError as e:
                return DIFF_TOO_BIG, {
                    'reason': six.text_type(e),
                    'max_size': e.max_diff_size,
                }
            except Exception as e:
                # This could be very wrong, but at least they'll see the error.
                # We probably want a new error type for this.
                logger.error("Error uploading new diff: %s",
                             e,
                             exc_info=1,
                             request=request)

                return INVALID_FORM_DATA, {
                    'fields': {
                        'path': [six.text_type(e)]
                    }
                }

        discarded_diffset = None

        try:
            draft = review_request.draft.get()

            if draft.diffset and draft.diffset != diffset:
                discarded_diffset = draft.diffset
        except ReviewRequestDraft.DoesNotExist:
            try:
                draft = ReviewRequestDraftResource.prepare_draft(
                    request, review_request)
            except PermissionDenied:
                return self.get_no_access_error(request)

        draft.diffset = diffset

        # We only want to add default reviewers the first time.  Was bug 318.
        if review_request.can_add_default_reviewers():
            draft.add_default_reviewers()

        draft.save()

        if extra_fields:
            try:
                self.import_extra_data(diffset, diffset.extra_data,
                                       extra_fields)
            except ImportExtraDataError as e:
                return e.error_payload

            diffset.save(update_fields=['extra_data'])

        if discarded_diffset:
            discarded_diffset.delete()

        # E-mail gets sent when the draft is saved.

        return 201, {
            self.item_result_key: diffset,
        }
コード例 #16
0
ファイル: draft_diff.py プロジェクト: chipx86/reviewboard
    def update(self, request, finalize_commit_series=False,
               validation_info=None, extra_fields={}, *args, **kwargs):
        """Update a diff.

        This is used for two purposes:

        1. For updating extra data on a draft diff.

           Extra data can be stored later lookup. See
           :ref:`webapi2.0-extra-data` for more information.

        2. For finalization of a draft diff on a review request created with
           commit history.
        """
        try:
            review_request = resources.review_request.get_object(
                request, *args, **kwargs)
            diffset = self.get_object(request, *args, **kwargs)
        except ObjectDoesNotExist:
            return DOES_NOT_EXIST

        if not review_request.is_mutable_by(request.user):
            return self.get_no_access_error(request)

        if extra_fields:
            try:
                self.import_extra_data(diffset, diffset.extra_data,
                                       extra_fields)
            except ImportExtraDataError as e:
                return e.error_payload

        if finalize_commit_series:
            if review_request.created_with_history:
                cumulative_diff = request.FILES.get('cumulative_diff')
                parent_diff = request.FILES.get('parent_diff')

                error_rsp = self._finalize_commit_series(request,
                                                         diffset,
                                                         cumulative_diff,
                                                         parent_diff,
                                                         validation_info)

                if error_rsp is not None:
                    return error_rsp

                # Only add default reviewers if this is the first time we've
                # published any diffsets.
                if review_request.can_add_default_reviewers():
                    diffset.review_request_draft.get().add_default_reviewers()
            elif dvcs_feature.is_enabled(request=request):
                return INVALID_ATTRIBUTE, {
                    'reason': 'This review request was not created with '
                              'commit history support.',
                }
            else:
                # Otherwise we silently ignore this option.
                finalize_commit_series = False

        if extra_fields or finalize_commit_series:
            diffset.save(update_fields=('extra_data',))

        return 200, {
            self.item_result_key: diffset,
        }
コード例 #17
0
    def create(self, request, filediff_id, interfilediff_id=None,
               base_filediff_id=None, *args, **kwargs):
        """Creates a new diff comment.

        This will create a new diff comment on this review. The review
        must be a draft review.

        Extra data can be stored later lookup. See
        :ref:`webapi2.0-extra-data` for more information.
        """
        try:
            review_request = \
                resources.review_request.get_object(request, *args, **kwargs)
            review = resources.review.get_object(request, *args, **kwargs)
        except ObjectDoesNotExist:
            return DOES_NOT_EXIST

        if not resources.review.has_modify_permissions(request, review):
            return self.get_no_access_error(request)

        filediff = None
        interfilediff = None
        invalid_fields = {}

        try:
            filediff = FileDiff.objects.get(
                pk=filediff_id,
                diffset__history__review_request=review_request)
        except ObjectDoesNotExist:
            invalid_fields['filediff_id'] = [
                'This is not a valid filediff ID.',
            ]

        if filediff is None or not dvcs_feature.is_enabled(request=request):
            base_filediff_id = None

        if base_filediff_id is not None:
            if not review_request.created_with_history:
                invalid_fields['base_filediff_id'] = [
                    'This field cannot be specified on review requests '
                    'created without history support.'
                ]
            elif interfilediff_id is not None:
                invalid_fields.update({
                    'base_filediff_id': [
                        'This field cannot be specified with '
                        'interfilediff_id.',
                    ],
                    'interfilediff_id': [
                        'This field cannot be specified with '
                        'base_filediff_id.',
                    ],
                })
            elif base_filediff_id == filediff_id:
                invalid_fields['base_filediff_id'] = [
                    'This cannot be the same as filediff_id.',
                ]

            elif base_filediff_id > filediff_id:
                invalid_fields['base_filediff_id'] = [
                    'This is not a valid base filediff ID.',
                ]
            else:
                base_filediff_exists = (
                    FileDiff.objects
                    .filter(diffset_id=filediff.diffset_id,
                            pk=base_filediff_id)
                    .exclude(commit_id=filediff.commit_id)
                    .exists()
                )

                if not base_filediff_exists:
                    invalid_fields['base_filediff_id'] = [
                        'This is not a valid base filediff ID.',
                    ]
                else:
                    ancestor_ids = (
                        ancestor.pk
                        for ancestor in filediff.get_ancestors(
                            minimal=False)
                    )

                    if base_filediff_id not in ancestor_ids:
                        invalid_fields['base_filediff_id'] = [
                            'This is not a valid base filediff ID.',
                        ]

        if filediff and interfilediff_id:
            if interfilediff_id == filediff.id:
                invalid_fields.setdefault('interfilediff_id', []).append(
                    'This cannot be the same as filediff_id.')
            else:
                try:
                    interfilediff = FileDiff.objects.get(
                        pk=interfilediff_id,
                        diffset__history=filediff.diffset.history)
                except ObjectDoesNotExist:
                    invalid_fields.setdefault('interfilediff_id', []).append(
                        'This is not a valid interfilediff ID.')

        if invalid_fields:
            return INVALID_FORM_DATA, {
                'fields': invalid_fields,
            }

        return self.create_comment(
            request=request,
            review=review,
            comments_m2m=review.comments,
            filediff=filediff,
            interfilediff=interfilediff,
            fields=('filediff', 'interfilediff', 'first_line', 'num_lines'),
            base_filediff_id=base_filediff_id,
            **kwargs)