Ejemplo n.º 1
0
    def get(self, request, *args, **kwargs):
        """
        Retrieves the list of top-level resources, and a list of
        :term:`URI templates` for accessing any resource in the tree.
        """
        etag = self.get_etag(request, None)

        if etag_if_none_match(request, etag):
            return HttpResponseNotModified()

        data = {
            'links':
            self.get_links(self.list_child_resources,
                           request=request,
                           *args,
                           **kwargs),
        }

        if self._include_uri_templates:
            data['uri_templates'] = self.get_uri_templates(
                request, *args, **kwargs)

        return 200, data, {
            'ETag': etag,
        }
Ejemplo n.º 2
0
def user_infobox(request, username,
                 template_name='accounts/user_infobox.html',
                 local_site_name=None):
    """Displays a user info popup.

    This is meant to be embedded in other pages, rather than being
    a standalone page.
    """
    user = get_object_or_404(User, username=username)

    if local_site_name:
        local_site = get_object_or_404(LocalSite, name=local_site_name)

        if not local_site.is_accessible_by(request.user):
            return _render_permission_denied(request)

    etag = ':'.join([user.first_name, user.last_name, user.email,
                     str(user.last_login), str(settings.AJAX_SERIAL)])

    if etag_if_none_match(request, etag):
        return HttpResponseNotModified()

    response = render_to_response(template_name, {
        'user': user,
    })
    set_etag(response, etag)

    return response
Ejemplo n.º 3
0
    def dispatch(self, request, *args, **kwargs):
        """Handle a HTTP request and dispatch to a handler.

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

            *args (tuple):
                Positional arguments passed to the handler.

            **kwargs (dict):
                Keyword arguments passed to the handler.

        Returns:
            django.http.HttpResponse:
            The resulting HTTP response from the handler.
        """
        handle_etag = request.method.upper() in ('GET', 'HEAD')

        if handle_etag:
            etag = self.get_etag_data(request, *args, **kwargs)

            if etag:
                etag = encode_etag(etag)

                if etag_if_none_match(request, etag):
                    return HttpResponseNotModified()

        response = super(ETagViewMixin, self).dispatch(request, *args,
                                                       **kwargs)

        if handle_etag and etag and 200 <= response.status_code < 300:
            set_etag(response, etag)

        return response
Ejemplo n.º 4
0
    def dispatch(self, request, *args, **kwargs):
        """Handle a HTTP request and dispatch to a handler.

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

            *args (tuple):
                Positional arguments passed to the handler.

            **kwargs (dict):
                Keyword arguments passed to the handler.

        Returns:
            django.http.HttpResponse:
            The resulting HTTP response from the handler.
        """
        handle_etag = request.method.upper() in ('GET', 'HEAD')

        if handle_etag:
            etag = self.get_etag_data(request, *args, **kwargs)

            if etag:
                etag = encode_etag(etag)

                if etag_if_none_match(request, etag):
                    return HttpResponseNotModified()

        response = super(ETagViewMixin, self).dispatch(request, *args,
                                                       **kwargs)

        if handle_etag and etag and 200 <= response.status_code < 300:
            set_etag(response, etag)

        return response
Ejemplo n.º 5
0
def user_infobox(request,
                 username,
                 template_name='accounts/user_infobox.html',
                 local_site_name=None):
    """Displays a user info popup.

    This is meant to be embedded in other pages, rather than being
    a standalone page.
    """
    user = get_object_or_404(User, username=username)

    if local_site_name:
        local_site = get_object_or_404(LocalSite, name=local_site_name)

        if not local_site.is_accessible_by(request.user):
            return _render_permission_denied(request)

    etag = ':'.join([
        user.first_name, user.last_name, user.email,
        str(user.last_login),
        str(settings.AJAX_SERIAL)
    ])

    if etag_if_none_match(request, etag):
        return HttpResponseNotModified()

    response = render_to_response(template_name, {
        'user': user,
    })
    set_etag(response, etag)

    return response
Ejemplo n.º 6
0
    def are_cache_headers_current(self, request, last_modified=None,
                                  etag=None):
        """Determines if cache headers from the client are current.

        This will compare the optionally-provided timestamp and ETag against
        any conditional cache headers sent by the client to determine if
        the headers are current. If they are, the caller can return
        HttpResponseNotModified instead of a payload.
        """
        return ((last_modified and
                 get_modified_since(request, last_modified)) or
                (etag and etag_if_none_match(request, etag)))
Ejemplo n.º 7
0
    def render_to_response(self, request):
        """Renders the diff to an HttpResponse."""
        etag = self.make_etag()

        if etag_if_none_match(request, etag):
            response = HttpResponseNotModified()
        else:
            response = HttpResponse(self.render_to_string(request))

        set_etag(response, etag)

        return response
Ejemplo n.º 8
0
    def are_cache_headers_current(self, request, last_modified=None,
                                  etag=None):
        """Determines if cache headers from the client are current.

        This will compare the optionally-provided timestamp and ETag against
        any conditional cache headers sent by the client to determine if
        the headers are current. If they are, the caller can return
        HttpResponseNotModified instead of a payload.
        """
        return ((last_modified and
                 get_modified_since(request, last_modified)) or
                (etag and etag_if_none_match(request, etag)))
Ejemplo n.º 9
0
    def get(self, request, api_format, *args, **kwargs):
        """Handles HTTP GETs to individual object resources.

        By default, this will check for access permissions and query for
        the object. It will then return a serialized form of the object.

        This may need to be overridden if needing more complex logic.
        """
        if (not self.model
                or (self.uri_object_key is None and not self.singleton)):
            return HttpResponseNotAllowed(self.allowed_methods)

        try:
            obj = self.get_object(request, *args, **kwargs)
        except self.model.DoesNotExist:
            return DOES_NOT_EXIST

        if not self.has_access_permissions(request, obj, *args, **kwargs):
            if request.user.is_authenticated():
                return PERMISSION_DENIED
            else:
                return NOT_LOGGED_IN

        last_modified_timestamp = self.get_last_modified(request, obj)

        if (last_modified_timestamp
                and get_modified_since(request, last_modified_timestamp)):
            return HttpResponseNotModified()

        etag = self.get_etag(request, obj)

        if etag and etag_if_none_match(request, etag):
            return HttpResponseNotModified()

        data = {
            self.item_result_key:
            self.serialize_object(obj, request=request, *args, **kwargs),
        }

        response = WebAPIResponse(request,
                                  status=200,
                                  obj=data,
                                  api_format=api_format,
                                  **self.build_response_args(request))

        if last_modified_timestamp:
            set_last_modified(response, last_modified_timestamp)

        if etag:
            set_etag(response, etag)

        return response
Ejemplo n.º 10
0
    def get(self, request, api_format, *args, **kwargs):
        """Handles HTTP GETs to individual object resources.

        By default, this will check for access permissions and query for
        the object. It will then return a serialized form of the object.

        This may need to be overridden if needing more complex logic.
        """
        if (not self.model or
            (self.uri_object_key is None and not self.singleton)):
            return HttpResponseNotAllowed(self.allowed_methods)

        try:
            obj = self.get_object(request, *args, **kwargs)
        except self.model.DoesNotExist:
            return DOES_NOT_EXIST

        if not self.has_access_permissions(request, obj, *args, **kwargs):
            if request.user.is_authenticated():
                return PERMISSION_DENIED
            else:
                return NOT_LOGGED_IN

        last_modified_timestamp = self.get_last_modified(request, obj)

        if (last_modified_timestamp and
            get_modified_since(request, last_modified_timestamp)):
            return HttpResponseNotModified()

        etag = self.get_etag(request, obj)

        if etag and etag_if_none_match(request, etag):
            return HttpResponseNotModified()

        data = {
            self.item_result_key: self.serialize_object(obj, request=request,
                                                        *args, **kwargs),
        }

        response = WebAPIResponse(request,
                                  status=200,
                                  obj=data,
                                  api_format=api_format,
                                  **self.build_response_args(request))

        if last_modified_timestamp:
            set_last_modified(response, last_modified_timestamp)

        if etag:
            set_etag(response, etag)

        return response
Ejemplo n.º 11
0
    def get(self, request, *args, **kwargs):
        """Handles GET requests for this view.

        This will create the renderer for the diff fragment, render it, and
        return it.

        If there's an error when rendering the diff fragment, an error page
        will be rendered and returned instead.
        """
        try:
            renderer_settings = self._get_renderer_settings(**kwargs)
            etag = self.make_etag(renderer_settings, **kwargs)

            if etag_if_none_match(request, etag):
                return HttpResponseNotModified()

            diff_info_or_response = self.process_diffset_info(**kwargs)

            if isinstance(diff_info_or_response, HttpResponse):
                return diff_info_or_response
        except Http404:
            raise
        except Exception as e:
            return exception_traceback(self.request, e,
                                       self.error_template_name)

        kwargs.update(diff_info_or_response)

        try:
            context = self.get_context_data(**kwargs)

            renderer = self.create_renderer(
                context=context,
                renderer_settings=renderer_settings,
                *args,
                **kwargs)
            response = renderer.render_to_response(request)
        except Exception as e:
            return exception_traceback(self.request,
                                       e,
                                       self.error_template_name,
                                       extra_context={
                                           'file':
                                           diff_info_or_response['diff_file'],
                                       })

        if response.status_code == 200:
            set_etag(response, etag)

        return response
Ejemplo n.º 12
0
    def get(self, request, *args, **kwargs):
        """Handles GET requests for this view.

        This will create the renderer for the diff fragment, render it, and
        return it.

        If there's an error when rendering the diff fragment, an error page
        will be rendered and returned instead.
        """
        try:
            renderer_settings = self._get_renderer_settings(**kwargs)
            etag = self.make_etag(renderer_settings, **kwargs)

            if etag_if_none_match(request, etag):
                return HttpResponseNotModified()

            diff_info_or_response = self.process_diffset_info(**kwargs)

            if isinstance(diff_info_or_response, HttpResponse):
                return diff_info_or_response
        except Http404:
            raise
        except Exception as e:
            return exception_traceback(self.request, e,
                                       self.error_template_name)

        kwargs.update(diff_info_or_response)

        try:
            context = self.get_context_data(**kwargs)

            renderer = self.create_renderer(
                context=context,
                renderer_settings=renderer_settings,
                *args, **kwargs)
            response = renderer.render_to_response(request)
        except Exception as e:
            return exception_traceback(
                self.request, e, self.error_template_name,
                extra_context={
                    'file': diff_info_or_response['diff_file'],
                })

        if response.status_code == 200:
            set_etag(response, etag)

        return response
Ejemplo n.º 13
0
    def get(self, request, *args, **kwargs):
        """
        Retrieves the list of top-level resources, and a list of
        :term:`URI templates` for accessing any resource in the tree.
        """
        etag = self.get_etag(request, None)

        if etag_if_none_match(request, etag):
            return HttpResponseNotModified()

        data = {
            'links': self.get_links(self.list_child_resources,
                                    request=request, *args, **kwargs),
        }

        if self._include_uri_templates:
            data['uri_templates'] = self.get_uri_templates(request, *args,
                                                           **kwargs)

        return 200, data, {
            'ETag': etag,
        }
Ejemplo n.º 14
0
    def get(self, request, *args, **kwargs):
        """Handle GET requests for this view.

        This will create the renderer for the diff fragment and render it in
        order to get the PatchError information. It then returns a response
        with a zip file containing all the debug data.

        If no PatchError occurred, this will return a 404.

        Args:
            request (django.http.HttpRequest):
                The HTTP request.

            *args (tuple):
                Additional positional arguments for the view.

            **kwargs (dict):
                Additional keyword arguments for the view.

        Returns:
            django.http.HttpResponse:
            A response containing the data bundle.
        """
        try:
            renderer_settings = self._get_renderer_settings(**kwargs)
            etag = self.make_etag(renderer_settings, **kwargs)

            if etag_if_none_match(request, etag):
                return HttpResponseNotModified()

            diff_info_or_response = self.process_diffset_info(**kwargs)

            if isinstance(diff_info_or_response, HttpResponse):
                return diff_info_or_response
        except Http404:
            return HttpResponseNotFound()
        except Exception as e:
            logging.exception(
                '%s.get: Error when processing diffset info for filediff '
                'ID=%s, interfilediff ID=%s, chunk_index=%s: %s',
                self.__class__.__name__,
                kwargs.get('filediff_id'),
                kwargs.get('interfilediff_id'),
                kwargs.get('chunk_index'),
                e,
                request=request)
            return HttpResponseServerError()

        kwargs.update(diff_info_or_response)

        try:
            context = self.get_context_data(**kwargs)

            renderer = self.create_renderer(
                context=context,
                renderer_settings=renderer_settings,
                *args, **kwargs)
            renderer.render_to_response(request)
        except PatchError as e:
            patch_error = e
        except Exception as e:
            logging.exception(
                '%s.get: Error when rendering diffset for filediff ID=%s, '
                'interfilediff ID=%s, chunk_index=%s: %s',
                self.__class__.__name__,
                kwargs.get('filediff_id'),
                kwargs.get('interfilediff_id'),
                kwargs.get('chunk_index'),
                e,
                request=request)
            return HttpResponseServerError()
        else:
            return HttpResponseNotFound()

        zip_data = StringIO()

        with ZipFile(zip_data, 'w') as zipfile:
            basename = os.path.basename(patch_error.filename)
            zipfile.writestr('%s.orig' % basename, patch_error.orig_file)
            zipfile.writestr('%s.diff' % basename, patch_error.diff)

            if patch_error.rejects:
                zipfile.writestr('%s.rej' % basename, patch_error.rejects)

            if patch_error.new_file:
                zipfile.writestr('%s.new' % basename, patch_error.new_file)

        rsp = HttpResponse(zip_data.getvalue(),
                           content_type='application/zip')
        rsp['Content-Disposition'] = \
            'attachment; filename=%s.zip' % basename

        return rsp
Ejemplo n.º 15
0
def review_detail(request,
                  review_request_id,
                  local_site_name=None,
                  template_name="reviews/review_detail.html"):
    """
    Main view for review requests. This covers the review request information
    and all the reviews on it.
    """
    # If there's a local_site passed in the URL, we want to look up the review
    # request based on the local_id instead of the pk. This allows each
    # local_site configured to have its own review request ID namespace
    # starting from 1.
    review_request, response = \
        _find_review_request(request, review_request_id, local_site_name)

    if not review_request:
        return response

    reviews = review_request.get_public_reviews()
    review = review_request.get_pending_review(request.user)
    review_timestamp = 0
    last_visited = 0
    starred = False

    if request.user.is_authenticated():
        # If the review request is public and pending review and if the user
        # is logged in, mark that they've visited this review request.
        if review_request.public and review_request.status == "P":
            visited, visited_is_new = ReviewRequestVisit.objects.get_or_create(
                user=request.user, review_request=review_request)
            last_visited = visited.timestamp
            visited.timestamp = datetime.now()
            visited.save()

        starred = review_request in \
                  request.user.get_profile().starred_review_requests.all()

        # Unlike review above, this covers replies as well.
        try:
            last_draft_review = Review.objects.filter(
                review_request=review_request, user=request.user,
                public=False).latest()
            review_timestamp = last_draft_review.timestamp
        except Review.DoesNotExist:
            pass

    draft = review_request.get_draft(request.user)

    # Find out if we can bail early. Generate an ETag for this.
    last_activity_time, updated_object = review_request.get_last_activity()

    if draft:
        draft_timestamp = draft.last_updated
    else:
        draft_timestamp = ""

    etag = "%s:%s:%s:%s:%s:%s" % (request.user, last_activity_time,
                                  draft_timestamp, review_timestamp,
                                  int(starred), settings.AJAX_SERIAL)

    if etag_if_none_match(request, etag):
        return HttpResponseNotModified()

    changedescs = review_request.changedescs.filter(public=True)

    try:
        latest_changedesc = changedescs.latest('timestamp')
        latest_timestamp = latest_changedesc.timestamp
    except ChangeDescription.DoesNotExist:
        latest_timestamp = None

    entries = []

    for temp_review in reviews:
        temp_review.ordered_comments = \
            temp_review.comments.order_by('filediff', 'first_line')

        state = ''

        # Mark as collapsed if the review is older than the latest change
        if latest_timestamp and temp_review.timestamp < latest_timestamp:
            state = 'collapsed'

        try:
            latest_reply = temp_review.public_replies().latest(
                'timestamp').timestamp
        except Review.DoesNotExist:
            latest_reply = None

        # Mark as expanded if there is a reply newer than last_visited
        if latest_reply and last_visited and last_visited < latest_reply:
            state = ''

        entries.append({
            'review': temp_review,
            'timestamp': temp_review.timestamp,
            'class': state,
        })

    for changedesc in changedescs:
        fields_changed = []

        for name, info in changedesc.fields_changed.items():
            multiline = False

            if 'added' in info or 'removed' in info:
                change_type = 'add_remove'

                # We don't hard-code URLs in the bug info, since the
                # tracker may move, but we can do it here.
                if (name == "bugs_closed"
                        and review_request.repository.bug_tracker):
                    bug_url = review_request.repository.bug_tracker
                    for field in info:
                        for i, buginfo in enumerate(info[field]):
                            try:
                                full_bug_url = bug_url % buginfo[0]
                                info[field][i] = (buginfo[0], full_bug_url)
                            except TypeError:
                                logging.warning(
                                    "Invalid bugtracker url format")

            elif 'old' in info or 'new' in info:
                change_type = 'changed'
                multiline = (name == "description" or name == "testing_done")

                # Branch text is allowed to have entities, so mark it safe.
                if name == "branch":
                    if 'old' in info:
                        info['old'][0] = mark_safe(info['old'][0])

                    if 'new' in info:
                        info['new'][0] = mark_safe(info['new'][0])
            elif name == "screenshot_captions":
                change_type = 'screenshot_captions'
            else:
                # No clue what this is. Bail.
                continue

            fields_changed.append({
                'title':
                fields_changed_name_map.get(name, name),
                'multiline':
                multiline,
                'info':
                info,
                'type':
                change_type,
            })

        # Expand the latest review change
        state = ''

        # Mark as collapsed if the change is older than a newer change
        if latest_timestamp and changedesc.timestamp < latest_timestamp:
            state = 'collapsed'

        entries.append({
            'changeinfo': fields_changed,
            'changedesc': changedesc,
            'timestamp': changedesc.timestamp,
            'class': state,
        })

    entries.sort(key=lambda item: item['timestamp'])

    response = render_to_response(
        template_name,
        RequestContext(
            request,
            _make_review_request_context(
                review_request, {
                    'draft': draft,
                    'review_request_details': draft or review_request,
                    'entries': entries,
                    'last_activity_time': last_activity_time,
                    'review': review,
                    'request': request,
                    'PRE_CREATION': PRE_CREATION,
                })))
    set_etag(response, etag)

    return response
    def get(self, request, *args, **kwargs):
        """Returns the last update made to the review request.

        This shows the type of update that was made, the user who made the
        update, and when the update was made. Clients can use this to inform
        the user that the review request was updated, or automatically update
        it in the background.

        This does not take into account changes to a draft review request, as
        that's generally not update information that the owner of the draft is
        interested in. Only public updates are represented.
        """
        try:
            review_request = \
                resources.review_request.get_object(request, *args, **kwargs)
        except ObjectDoesNotExist:
            return DOES_NOT_EXIST

        if not resources.review_request.has_access_permissions(request,
                                                               review_request):
            return self.get_no_access_error(request)

        info = review_request.get_last_activity_info()
        timestamp = info['timestamp']
        updated_object = info['updated_object']
        changedesc = info['changedesc']

        etag = encode_etag('%s:%s' % (timestamp, updated_object.pk))

        if etag_if_none_match(request, etag):
            return HttpResponseNotModified()

        summary = None
        update_type = None
        user = None

        if isinstance(updated_object, ReviewRequest):
            if updated_object.status == ReviewRequest.SUBMITTED:
                summary = _('Review request submitted')
            elif updated_object.status == ReviewRequest.DISCARDED:
                summary = _('Review request discarded')
            else:
                summary = _('Review request updated')

            update_type = 'review-request'
        elif isinstance(updated_object, DiffSet):
            summary = _('Diff updated')
            update_type = 'diff'
        elif isinstance(updated_object, Review):
            if updated_object.is_reply():
                summary = _('New reply')
                update_type = 'reply'
            else:
                summary = _('New review')
                update_type = 'review'

            user = updated_object.user
        else:
            # Should never be able to happen. The object will always at least
            # be a ReviewRequest.
            assert False

        if changedesc:
            user = changedesc.get_user(review_request)
        elif user is None:
            # There is no changedesc which means this review request hasn't
            # been changed since it was first published, so this change must
            # be due to the original submitter.
            user = review_request.submitter

        return 200, {
            self.item_result_key: {
                'timestamp': timestamp,
                'user': user,
                'summary': summary,
                'type': update_type,
            }
        }, {
            'ETag': etag,
        }
Ejemplo n.º 17
0
    def get(self, request, *args, **kwargs):
        """Handle GET requests for this view.

        This will create the renderer for the diff fragment and render it in
        order to get the PatchError information. It then returns a response
        with a zip file containing all the debug data.

        If no PatchError occurred, this will return a 404.

        Args:
            request (django.http.HttpRequest):
                The HTTP request.

            *args (tuple):
                Additional positional arguments for the view.

            **kwargs (dict):
                Additional keyword arguments for the view.

        Returns:
            django.http.HttpResponse:
            A response containing the data bundle.
        """
        try:
            renderer_settings = self._get_renderer_settings(**kwargs)
            etag = self.make_etag(renderer_settings, **kwargs)

            if etag_if_none_match(request, etag):
                return HttpResponseNotModified()

            diff_info_or_response = self.process_diffset_info(**kwargs)

            if isinstance(diff_info_or_response, HttpResponse):
                return diff_info_or_response
        except Http404:
            return HttpResponseNotFound()
        except Exception as e:
            logging.exception(
                '%s.get: Error when processing diffset info for filediff '
                'ID=%s, interfilediff ID=%s, chunk_index=%s: %s',
                self.__class__.__name__,
                kwargs.get('filediff_id'),
                kwargs.get('interfilediff_id'),
                kwargs.get('chunk_index'),
                e,
                request=request)
            return HttpResponseServerError()

        kwargs.update(diff_info_or_response)

        try:
            context = self.get_context_data(**kwargs)

            renderer = self.create_renderer(
                context=context,
                renderer_settings=renderer_settings,
                *args,
                **kwargs)
            renderer.render_to_response(request)
        except PatchError as e:
            patch_error = e
        except Exception as e:
            logging.exception(
                '%s.get: Error when rendering diffset for filediff ID=%s, '
                'interfilediff ID=%s, chunk_index=%s: %s',
                self.__class__.__name__,
                kwargs.get('filediff_id'),
                kwargs.get('interfilediff_id'),
                kwargs.get('chunk_index'),
                e,
                request=request)
            return HttpResponseServerError()
        else:
            return HttpResponseNotFound()

        zip_data = StringIO()

        with ZipFile(zip_data, 'w') as zipfile:
            basename = os.path.basename(patch_error.filename)
            zipfile.writestr('%s.orig' % basename, patch_error.orig_file)
            zipfile.writestr('%s.diff' % basename, patch_error.diff)

            if patch_error.rejects:
                zipfile.writestr('%s.rej' % basename, patch_error.rejects)

            if patch_error.new_file:
                zipfile.writestr('%s.new' % basename, patch_error.new_file)

        rsp = HttpResponse(zip_data.getvalue(), content_type='application/zip')
        rsp['Content-Disposition'] = \
            'attachment; filename=%s.zip' % basename

        return rsp
Ejemplo n.º 18
0
    def get(self, request, *args, **kwargs):
        """Handle GET requests for this view.

        This will create the renderer for the diff fragment, render it, and
        return it.

        If there's an error when rendering the diff fragment, an error page
        will be rendered and returned instead.

        Args:
            request (django.http.HttpRequest):
                The HTTP request.

            *args (tuple):
                Additional positional arguments for the view.

            **kwargs (dict):
                Additional keyword arguments for the view.

        Returns:
            django.http.HttpResponse:
            A response containing the rendered fragment.
        """
        filediff_id = kwargs.get('filediff_id')
        interfilediff_id = kwargs.get('interfilediff_id')
        chunk_index = kwargs.get('chunk_index')

        try:
            renderer_settings = self._get_renderer_settings(**kwargs)
            etag = self.make_etag(renderer_settings, **kwargs)

            if etag_if_none_match(request, etag):
                return HttpResponseNotModified()

            diff_info_or_response = self.process_diffset_info(**kwargs)

            if isinstance(diff_info_or_response, HttpResponse):
                return diff_info_or_response
        except Http404:
            raise
        except Exception as e:
            logging.exception(
                '%s.get: Error when processing diffset info '
                'for filediff ID=%s, interfilediff ID=%s, '
                'chunk_index=%s: %s',
                self.__class__.__name__,
                filediff_id,
                interfilediff_id,
                chunk_index,
                e,
                request=request)

            return exception_traceback(self.request, e,
                                       self.error_template_name)

        kwargs.update(diff_info_or_response)

        try:
            context = self.get_context_data(**kwargs)

            renderer = self.create_renderer(
                context=context,
                renderer_settings=renderer_settings,
                *args,
                **kwargs)
            response = renderer.render_to_response(request)
        except PatchError as e:
            logging.warning(
                '%s.get: PatchError when rendering diffset for filediff '
                'ID=%s, interfilediff ID=%s, chunk_index=%s: %s',
                self.__class__.__name__,
                filediff_id,
                interfilediff_id,
                chunk_index,
                e,
                request=request)

            try:
                url_kwargs = {
                    key: kwargs[key]
                    for key in ('chunk_index', 'interfilediff_id',
                                'review_request_id', 'filediff_id', 'revision',
                                'interdiff_revision')
                    if key in kwargs and kwargs[key] is not None
                }

                bundle_url = local_site_reverse('patch-error-bundle',
                                                kwargs=url_kwargs,
                                                request=request)
            except NoReverseMatch:
                # We'll sometimes see errors about this failing to resolve when
                # web crawlers start accessing fragment URLs without the proper
                # attributes. Ignore them.
                bundle_url = ''

            if e.rejects:
                lexer = get_lexer_by_name('diff')
                formatter = HtmlFormatter()
                rejects = highlight(e.rejects, lexer, formatter)
            else:
                rejects = None

            return HttpResponseServerError(
                render_to_string(
                    self.patch_error_template_name,
                    RequestContext(
                        request, {
                            'bundle_url': bundle_url,
                            'file': diff_info_or_response['diff_file'],
                            'filename': os.path.basename(e.filename),
                            'patch_output': e.error_output,
                            'rejects': mark_safe(rejects),
                        })))
        except FileNotFoundError as e:
            return HttpResponseServerError(
                render_to_string(
                    self.error_template_name,
                    RequestContext(request, {
                        'error': e,
                        'file': diff_info_or_response['diff_file'],
                    })))
        except Exception as e:
            logging.exception(
                '%s.get: Error when rendering diffset for '
                'filediff ID=%s, interfilediff ID=%s, '
                'chunkindex=%s: %s',
                self.__class__.__name__,
                filediff_id,
                interfilediff_id,
                chunk_index,
                e,
                request=request)

            return exception_traceback(self.request,
                                       e,
                                       self.error_template_name,
                                       extra_context={
                                           'file':
                                           diff_info_or_response['diff_file'],
                                       })

        if response.status_code == 200:
            set_etag(response, etag)

        return response
    def get(self, request, *args, **kwargs):
        """Returns the last update made to the review request.

        This shows the type of update that was made, the user who made the
        update, and when the update was made. Clients can use this to inform
        the user that the review request was updated, or automatically update
        it in the background.

        This does not take into account changes to a draft review request, as
        that's generally not update information that the owner of the draft is
        interested in. Only public updates are represented.
        """
        try:
            review_request = \
                resources.review_request.get_object(request, *args, **kwargs)
        except ObjectDoesNotExist:
            return DOES_NOT_EXIST

        if not resources.review_request.has_access_permissions(
                request, review_request):
            return self.get_no_access_error(request)

        info = review_request.get_last_activity_info()
        timestamp = info['timestamp']
        updated_object = info['updated_object']
        changedesc = info['changedesc']

        etag = encode_etag('%s:%s' % (timestamp, updated_object.pk))

        if etag_if_none_match(request, etag):
            return HttpResponseNotModified()

        summary = None
        update_type = None

        if isinstance(updated_object, ReviewRequest):
            if updated_object.status == ReviewRequest.SUBMITTED:
                summary = _('Review request submitted')
            elif updated_object.status == ReviewRequest.DISCARDED:
                summary = _('Review request discarded')
            else:
                summary = _('Review request updated')

            update_type = 'review-request'
        elif isinstance(updated_object, DiffSet):
            summary = _('Diff updated')
            update_type = 'diff'
        elif isinstance(updated_object, Review):
            if updated_object.is_reply():
                summary = _('New reply')
                update_type = 'reply'
            else:
                summary = _('New review')
                update_type = 'review'
        else:
            # Should never be able to happen. The object will always at least
            # be a ReviewRequest.
            assert False

        if changedesc:
            user = changedesc.get_user(review_request)
        else:
            # There is no changedesc which means this review request hasn't
            # been changed since it was first published, so this change must
            # be due to the original submitter.
            user = review_request.submitter

        return 200, {
            self.item_result_key: {
                'timestamp': timestamp,
                'user': user,
                'summary': summary,
                'type': update_type,
            }
        }, {
            'ETag': etag,
        }
Ejemplo n.º 20
0
    def get(self, request, *args, **kwargs):
        """Returns the last update made to the review request.

        This shows the type of update that was made, the user who made the
        update, and when the update was made. Clients can use this to inform
        the user that the review request was updated, or automatically update
        it in the background.

        This does not take into account changes to a draft review request, as
        that's generally not update information that the owner of the draft is
        interested in. Only public updates are represented.
        """
        try:
            review_request = \
                resources.review_request.get_object(request, *args, **kwargs)
        except ObjectDoesNotExist:
            return DOES_NOT_EXIST

        if not resources.review_request.has_access_permissions(
                request, review_request):
            return self.get_no_access_error(request)

        timestamp, updated_object = review_request.get_last_activity()

        etag = encode_etag('%s:%s' % (timestamp, updated_object.pk))

        if etag_if_none_match(request, etag):
            return HttpResponseNotModified()

        user = None
        summary = None
        update_type = None

        if isinstance(updated_object, ReviewRequest):
            user = updated_object.submitter

            if updated_object.status == ReviewRequest.SUBMITTED:
                summary = _("Review request submitted")
            elif updated_object.status == ReviewRequest.DISCARDED:
                summary = _("Review request discarded")
            else:
                summary = _("Review request updated")

            update_type = "review-request"
        elif isinstance(updated_object, DiffSet):
            summary = _("Diff updated")
            update_type = "diff"
        elif isinstance(updated_object, Review):
            user = updated_object.user

            if updated_object.is_reply():
                summary = _("New reply")
                update_type = "reply"
            else:
                summary = _("New review")
                update_type = "review"
        else:
            # Should never be able to happen. The object will always at least
            # be a ReviewRequest.
            assert False

        return 200, {
            self.item_result_key: {
                'timestamp': timestamp,
                'user': user,
                'summary': summary,
                'type': update_type,
            }
        }, {
            'ETag': etag,
        }
    def get(self, request, *args, **kwargs):
        """Returns the last update made to the review request.

        This shows the type of update that was made, the user who made the
        update, and when the update was made. Clients can use this to inform
        the user that the review request was updated, or automatically update
        it in the background.

        This does not take into account changes to a draft review request, as
        that's generally not update information that the owner of the draft is
        interested in. Only public updates are represented.
        """
        try:
            review_request = \
                resources.review_request.get_object(request, *args, **kwargs)
        except ObjectDoesNotExist:
            return DOES_NOT_EXIST

        if not resources.review_request.has_access_permissions(request,
                                                               review_request):
            return self.get_no_access_error(request)

        timestamp, updated_object = review_request.get_last_activity()

        etag = encode_etag('%s:%s' % (timestamp, updated_object.pk))

        if etag_if_none_match(request, etag):
            return HttpResponseNotModified()

        user = None
        summary = None
        update_type = None

        if isinstance(updated_object, ReviewRequest):
            user = updated_object.submitter

            if updated_object.status == ReviewRequest.SUBMITTED:
                summary = _("Review request submitted")
            elif updated_object.status == ReviewRequest.DISCARDED:
                summary = _("Review request discarded")
            else:
                summary = _("Review request updated")

            update_type = "review-request"
        elif isinstance(updated_object, DiffSet):
            summary = _("Diff updated")
            update_type = "diff"
        elif isinstance(updated_object, Review):
            user = updated_object.user

            if updated_object.is_reply():
                summary = _("New reply")
                update_type = "reply"
            else:
                summary = _("New review")
                update_type = "review"
        else:
            # Should never be able to happen. The object will always at least
            # be a ReviewRequest.
            assert False

        return 200, {
            self.item_result_key: {
                'timestamp': timestamp,
                'user': user,
                'summary': summary,
                'type': update_type,
            }
        }, {
            'ETag': etag,
        }
Ejemplo n.º 22
0
def view_diff_fragment(
        request, diffset_id, filediff_id, interdiffset_id=None,
        chunkindex=None,
        template_name='diffviewer/diff_file_fragment.html',
        error_template_name='diffviewer/diff_fragment_error.html'):

    def get_requested_diff_file(get_chunks=True):
        files = get_diff_files(diffset, filediff, interdiffset, highlighting,
                               get_chunks)

        if files:
            assert len(files) == 1
            file = files[0]

            if 'index' in request.GET:
                file['index'] = request.GET.get('index')

            return file

        return None

    diffset = get_object_or_404(DiffSet, pk=diffset_id)
    filediff = get_object_or_404(FileDiff, pk=filediff_id, diffset=diffset)
    interdiffset = get_object_or_none(DiffSet, pk=interdiffset_id)
    highlighting = get_enable_highlighting(request.user)

    if chunkindex:
        collapseall = False
    else:
        collapseall = get_collapse_diff(request)

    etag = ""

    if collapseall:
        etag += "collapseall-"

    if highlighting:
        etag += "highlighting-"

    etag += str(settings.AJAX_SERIAL)

    if etag_if_none_match(request, etag):
        return HttpResponseNotModified()

    try:
        file = get_requested_diff_file()

        if file:
            context = {
                'standalone': chunkindex is not None,
            }

            response = HttpResponse(
                build_diff_fragment(request, file, chunkindex,
                                    highlighting, collapseall,
                                    context, template_name))
            set_etag(response, etag)
            return response
        raise UserVisibleError(
            _(u"Internal error. Unable to locate file record for filediff %s") % \
            filediff.id)
    except Exception, e:
        extra_context = {}

        file = get_requested_diff_file(False)
        extra_context['file'] = file

        return exception_traceback(request, e, error_template_name,
                                   extra_context)
Ejemplo n.º 23
0
def review_detail(request,
                  review_request_id,
                  local_site_name=None,
                  template_name="reviews/review_detail.html"):
    """
    Main view for review requests. This covers the review request information
    and all the reviews on it.
    """
    # If there's a local_site passed in the URL, we want to look up the review
    # request based on the local_id instead of the pk. This allows each
    # local_site configured to have its own review request ID namespace
    # starting from 1.
    review_request, response = \
        _find_review_request(request, review_request_id, local_site_name)

    if not review_request:
        return response

    reviews = review_request.get_public_reviews()
    review = review_request.get_pending_review(request.user)
    review_timestamp = 0
    last_visited = 0
    starred = False

    if request.user.is_authenticated():
        # If the review request is public and pending review and if the user
        # is logged in, mark that they've visited this review request.
        if review_request.public and review_request.status == "P":
            visited, visited_is_new = ReviewRequestVisit.objects.get_or_create(
                user=request.user, review_request=review_request)
            last_visited = visited.timestamp
            visited.timestamp = datetime.now()
            visited.save()

        starred = review_request in \
                  request.user.get_profile().starred_review_requests.all()

        # Unlike review above, this covers replies as well.
        try:
            last_draft_review = Review.objects.filter(
                review_request=review_request,
                user=request.user,
                public=False).latest()
            review_timestamp = last_draft_review.timestamp
        except Review.DoesNotExist:
            pass


    draft = review_request.get_draft(request.user)

    # Find out if we can bail early. Generate an ETag for this.
    last_activity_time, updated_object = review_request.get_last_activity()

    if draft:
        draft_timestamp = draft.last_updated
    else:
        draft_timestamp = ""

    etag = "%s:%s:%s:%s:%s:%s" % (request.user, last_activity_time,
                                  draft_timestamp, review_timestamp,
                                  int(starred),
                                  settings.AJAX_SERIAL)

    if etag_if_none_match(request, etag):
        return HttpResponseNotModified()

    changedescs = review_request.changedescs.filter(public=True)

    try:
        latest_changedesc = changedescs.latest('timestamp')
        latest_timestamp = latest_changedesc.timestamp
    except ChangeDescription.DoesNotExist:
        latest_timestamp = None

    entries = []

    for temp_review in reviews:
        temp_review.ordered_comments = \
            temp_review.comments.order_by('filediff', 'first_line')

        state = ''

        # Mark as collapsed if the review is older than the latest change
        if latest_timestamp and temp_review.timestamp < latest_timestamp:
            state = 'collapsed'

        try:
            latest_reply = temp_review.public_replies().latest('timestamp').timestamp
        except Review.DoesNotExist:
            latest_reply = None

        # Mark as expanded if there is a reply newer than last_visited
        if latest_reply and last_visited and last_visited < latest_reply:
          state = ''

        entries.append({
            'review': temp_review,
            'timestamp': temp_review.timestamp,
            'class': state,
        })

    for changedesc in changedescs:
        fields_changed = []

        for name, info in changedesc.fields_changed.items():
            multiline = False

            if 'added' in info or 'removed' in info:
                change_type = 'add_remove'

                # We don't hard-code URLs in the bug info, since the
                # tracker may move, but we can do it here.
                if (name == "bugs_closed" and
                    review_request.repository.bug_tracker):
                    bug_url = review_request.repository.bug_tracker
                    for field in info:
                        for i, buginfo in enumerate(info[field]):
                            try:
                                full_bug_url = bug_url % buginfo[0]
                                info[field][i] = (buginfo[0], full_bug_url)
                            except TypeError:
                                logging.warning("Invalid bugtracker url format")

            elif 'old' in info or 'new' in info:
                change_type = 'changed'
                multiline = (name == "description" or name == "testing_done")

                # Branch text is allowed to have entities, so mark it safe.
                if name == "branch":
                    if 'old' in info:
                        info['old'][0] = mark_safe(info['old'][0])

                    if 'new' in info:
                        info['new'][0] = mark_safe(info['new'][0])
            elif name == "screenshot_captions":
                change_type = 'screenshot_captions'
            else:
                # No clue what this is. Bail.
                continue

            fields_changed.append({
                'title': fields_changed_name_map.get(name, name),
                'multiline': multiline,
                'info': info,
                'type': change_type,
            })

        # Expand the latest review change
        state = ''

        # Mark as collapsed if the change is older than a newer change
        if latest_timestamp and changedesc.timestamp < latest_timestamp:
            state = 'collapsed'

        entries.append({
            'changeinfo': fields_changed,
            'changedesc': changedesc,
            'timestamp': changedesc.timestamp,
            'class': state,
        })

    entries.sort(key=lambda item: item['timestamp'])

    response = render_to_response(
        template_name,
        RequestContext(request, _make_review_request_context(review_request, {
            'draft': draft,
            'review_request_details': draft or review_request,
            'entries': entries,
            'last_activity_time': last_activity_time,
            'review': review,
            'request': request,
            'PRE_CREATION': PRE_CREATION,
        })))
    set_etag(response, etag)

    return response
Ejemplo n.º 24
0
    def get(self, request, *args, **kwargs):
        """Handle GET requests for this view.

        This will create the renderer for the diff fragment, render it, and
        return it.

        If there's an error when rendering the diff fragment, an error page
        will be rendered and returned instead.

        Args:
            request (django.http.HttpRequest):
                The HTTP request.

            *args (tuple):
                Additional positional arguments for the view.

            **kwargs (dict):
                Additional keyword arguments for the view.

        Returns:
            django.http.HttpResponse:
            A response containing the rendered fragment.
        """
        filediff_id = kwargs.get('filediff_id')
        interfilediff_id = kwargs.get('interfilediff_id')
        chunk_index = kwargs.get('chunk_index')

        try:
            renderer_settings = self._get_renderer_settings(**kwargs)
            etag = self.make_etag(renderer_settings, **kwargs)

            if etag_if_none_match(request, etag):
                return HttpResponseNotModified()

            diff_info_or_response = self.process_diffset_info(**kwargs)

            if isinstance(diff_info_or_response, HttpResponse):
                return diff_info_or_response
        except Http404:
            raise
        except Exception as e:
            logging.exception('%s.get: Error when processing diffset info '
                              'for filediff ID=%s, interfilediff ID=%s, '
                              'chunk_index=%s: %s',
                              self.__class__.__name__,
                              filediff_id,
                              interfilediff_id,
                              chunk_index,
                              e,
                              request=request)

            return exception_traceback(self.request, e,
                                       self.error_template_name)

        kwargs.update(diff_info_or_response)

        try:
            context = self.get_context_data(**kwargs)

            renderer = self.create_renderer(
                context=context,
                renderer_settings=renderer_settings,
                *args, **kwargs)
            response = renderer.render_to_response(request)
        except PatchError as e:
            logging.warning(
                '%s.get: PatchError when rendering diffset for filediff '
                'ID=%s, interfilediff ID=%s, chunk_index=%s: %s',
                self.__class__.__name__,
                filediff_id,
                interfilediff_id,
                chunk_index,
                e,
                request=request)

            url_kwargs = {
                key: kwargs[key]
                for key in ('chunk_index', 'interfilediff_id',
                            'review_request_id', 'filediff_id',
                            'revision', 'interdiff_revision')
                if key in kwargs and kwargs[key] is not None
            }
            bundle_url = local_site_reverse('patch-error-bundle',
                                            kwargs=url_kwargs,
                                            request=request)

            if e.rejects:
                lexer = get_lexer_by_name('diff')
                formatter = HtmlFormatter()
                rejects = highlight(e.rejects, lexer, formatter)
            else:
                rejects = None

            return HttpResponseServerError(render_to_string(
                self.patch_error_template_name,
                RequestContext(request, {
                    'bundle_url': bundle_url,
                    'file': diff_info_or_response['diff_file'],
                    'filename': os.path.basename(e.filename),
                    'patch_output': e.error_output,
                    'rejects': mark_safe(rejects),
                })))
        except Exception as e:
            if not isinstance(e, FileNotFoundError):
                logging.exception('%s.get: Error when rendering diffset for '
                                  'filediff ID=%s, interfilediff ID=%s, '
                                  'chunkindex=%s: %s',
                                  self.__class__.__name__,
                                  filediff_id,
                                  interfilediff_id,
                                  chunk_index,
                                  e,
                                  request=request)

            return exception_traceback(
                self.request, e, self.error_template_name,
                extra_context={
                    'file': diff_info_or_response['diff_file'],
                })

        if response.status_code == 200:
            set_etag(response, etag)

        return response
Ejemplo n.º 25
0
def review_detail(request, review_request_id,
                  template_name="reviews/review_detail.html"):
    """
    Main view for review requests. This covers the review request information
    and all the reviews on it.
    """
    review_request = get_object_or_404(ReviewRequest, pk=review_request_id)

    reviews = review_request.get_public_reviews()
    review = review_request.get_pending_review(request.user)

    if request.user.is_authenticated():
        # If the review request is public and pending review and if the user
        # is logged in, mark that they've visited this review request.
        if review_request.public and review_request.status == "P":
            visited, visited_is_new = ReviewRequestVisit.objects.get_or_create(
                user=request.user, review_request=review_request)
            visited.timestamp = datetime.now()
            visited.save()


    # Unlike review above, this covers replies as well.
    review_timestamp = 0

    if request.user.is_authenticated():
        try:
            last_draft_review = Review.objects.filter(
                review_request=review_request,
                user=request.user,
                public=False).latest()
            review_timestamp = last_draft_review.timestamp
        except Review.DoesNotExist:
            pass

    # Find out if we can bail early. Generate an ETag for this.
    timestamps = [review_request.last_updated]
    draft = review_request.get_draft()

    if draft:
        timestamps.append(draft.last_updated)

    last_activity_time = get_latest_timestamp(timestamps)

    etag = "%s:%s:%s:%s" % (request.user, last_activity_time, review_timestamp,
                            settings.AJAX_SERIAL)

    if etag_if_none_match(request, etag):
        return HttpResponseNotModified()

    repository = review_request.repository
    changedescs = review_request.changedescs.filter(public=True)

    entries = []

    for temp_review in reviews:
        temp_review.ordered_comments = \
            temp_review.comments.order_by('filediff', 'first_line')

        entries.append({
            'review': temp_review,
            'timestamp': temp_review.timestamp,
        })

    for changedesc in changedescs:
        fields_changed = []

        for name, info in changedesc.fields_changed.items():
            multiline = False

            if 'added' in info or 'removed' in info:
                change_type = 'add_remove'

                # We don't hard-code URLs in the bug info, since the
                # tracker may move, but we can do it here.
                if (name == "bugs_closed" and
                    review_request.repository.bug_tracker):
                    bug_url = review_request.repository.bug_tracker
                    for field in info:
                        for i, buginfo in enumerate(info[field]):
                            try:
                                full_bug_url = bug_url % buginfo[0]
                                info[field][i] = (buginfo[0], full_bug_url)
                            except TypeError:
                                logging.warning("Invalid bugtracker url format")

            elif 'old' in info or 'new' in info:
                change_type = 'changed'
                multiline = (name == "description" or name == "testing_done")

                # Branch text is allowed to have entities, so mark it safe.
                if name == "branch":
                    if 'old' in info:
                        info['old'][0] = mark_safe(info['old'][0])

                    if 'new' in info:
                        info['new'][0] = mark_safe(info['new'][0])
            elif name == "screenshot_captions":
                change_type = 'screenshot_captions'
            else:
                # No clue what this is. Bail.
                continue

            fields_changed.append({
                'title': fields_changed_name_map.get(name, name),
                'multiline': multiline,
                'info': info,
                'type': change_type,
            })

        entries.append({
            'changeinfo': fields_changed,
            'changedesc': changedesc,
            'timestamp': changedesc.timestamp,
        })

    entries.sort(key=lambda item: item['timestamp'])

    response = render_to_response(template_name, RequestContext(request, {
        'draft': draft,
        'review_request': review_request,
        'review_request_details': draft or review_request,
        'entries': entries,
        'review': review,
        'request': request,
        'upload_diff_form': UploadDiffForm(repository),
        'upload_screenshot_form': UploadScreenshotForm(),
        'scmtool': repository.get_scmtool(),
        'PRE_CREATION': PRE_CREATION,
    }))
    set_etag(response, etag)

    return response
Ejemplo n.º 26
0
def review_detail(request, review_request_id, template_name="reviews/review_detail.html"):
    """
    Main view for review requests. This covers the review request information
    and all the reviews on it.
    """
    review_request = get_object_or_404(ReviewRequest, pk=review_request_id)

    reviews = review_request.get_public_reviews()
    review = review_request.get_pending_review(request.user)
    review_timestamp = 0
    starred = False

    if request.user.is_authenticated():
        # If the review request is public and pending review and if the user
        # is logged in, mark that they've visited this review request.
        if review_request.public and review_request.status == "P":
            visited, visited_is_new = ReviewRequestVisit.objects.get_or_create(
                user=request.user, review_request=review_request
            )
            visited.timestamp = datetime.now()
            visited.save()

        starred = review_request in request.user.get_profile().starred_review_requests.all()

        # Unlike review above, this covers replies as well.
        try:
            last_draft_review = Review.objects.filter(
                review_request=review_request, user=request.user, public=False
            ).latest()
            review_timestamp = last_draft_review.timestamp
        except Review.DoesNotExist:
            pass

    draft = review_request.get_draft(request.user)

    # Find out if we can bail early. Generate an ETag for this.
    last_activity_time, updated_object = review_request.get_last_activity()

    if draft:
        draft_timestamp = draft.last_updated
    else:
        draft_timestamp = ""

    etag = "%s:%s:%s:%s:%s:%s" % (
        request.user,
        last_activity_time,
        draft_timestamp,
        review_timestamp,
        int(starred),
        settings.AJAX_SERIAL,
    )

    if etag_if_none_match(request, etag):
        return HttpResponseNotModified()

    repository = review_request.repository
    changedescs = review_request.changedescs.filter(public=True)

    entries = []

    for temp_review in reviews:
        temp_review.ordered_comments = temp_review.comments.order_by("filediff", "first_line")

        entries.append({"review": temp_review, "timestamp": temp_review.timestamp})

    for changedesc in changedescs:
        fields_changed = []

        for name, info in changedesc.fields_changed.items():
            multiline = False

            if "added" in info or "removed" in info:
                change_type = "add_remove"

                # We don't hard-code URLs in the bug info, since the
                # tracker may move, but we can do it here.
                if name == "bugs_closed" and review_request.repository.bug_tracker:
                    bug_url = review_request.repository.bug_tracker
                    for field in info:
                        for i, buginfo in enumerate(info[field]):
                            try:
                                full_bug_url = bug_url % buginfo[0]
                                info[field][i] = (buginfo[0], full_bug_url)
                            except TypeError:
                                logging.warning("Invalid bugtracker url format")

            elif "old" in info or "new" in info:
                change_type = "changed"
                multiline = name == "description" or name == "testing_done"

                # Branch text is allowed to have entities, so mark it safe.
                if name == "branch":
                    if "old" in info:
                        info["old"][0] = mark_safe(info["old"][0])

                    if "new" in info:
                        info["new"][0] = mark_safe(info["new"][0])
            elif name == "screenshot_captions":
                change_type = "screenshot_captions"
            else:
                # No clue what this is. Bail.
                continue

            fields_changed.append(
                {
                    "title": fields_changed_name_map.get(name, name),
                    "multiline": multiline,
                    "info": info,
                    "type": change_type,
                }
            )

        entries.append({"changeinfo": fields_changed, "changedesc": changedesc, "timestamp": changedesc.timestamp})

    entries.sort(key=lambda item: item["timestamp"])

    response = render_to_response(
        template_name,
        RequestContext(
            request,
            {
                "draft": draft,
                "review_request": review_request,
                "review_request_details": draft or review_request,
                "entries": entries,
                "last_activity_time": last_activity_time,
                "review": review,
                "request": request,
                "upload_diff_form": UploadDiffForm(review_request),
                "upload_screenshot_form": UploadScreenshotForm(),
                "scmtool": repository.get_scmtool(),
                "PRE_CREATION": PRE_CREATION,
            },
        ),
    )
    set_etag(response, etag)

    return response
Ejemplo n.º 27
0
def review_detail(request, review_request_id, local_site_name=None, template_name="reviews/review_detail.html"):
    """
    Main view for review requests. This covers the review request information
    and all the reviews on it.
    """
    # If there's a local_site passed in the URL, we want to look up the review
    # request based on the local_id instead of the pk. This allows each
    # local_site configured to have its own review request ID namespace
    # starting from 1.
    review_request, response = _find_review_request(request, review_request_id, local_site_name)

    if not review_request:
        return response

    reviews = review_request.get_public_reviews()
    review = review_request.get_pending_review(request.user)
    review_timestamp = 0
    last_visited = 0
    starred = False

    if request.user.is_authenticated():
        # If the review request is public and pending review and if the user
        # is logged in, mark that they've visited this review request.
        if review_request.public and review_request.status == "P":
            visited, visited_is_new = ReviewRequestVisit.objects.get_or_create(
                user=request.user, review_request=review_request
            )
            last_visited = visited.timestamp
            visited.timestamp = datetime.now()
            visited.save()

        profile, profile_is_new = Profile.objects.get_or_create(user=request.user)
        starred = review_request in profile.starred_review_requests.all()

        # Unlike review above, this covers replies as well.
        try:
            last_draft_review = Review.objects.filter(
                review_request=review_request, user=request.user, public=False
            ).latest()
            review_timestamp = last_draft_review.timestamp
        except Review.DoesNotExist:
            pass

    draft = review_request.get_draft(request.user)

    # Find out if we can bail early. Generate an ETag for this.
    last_activity_time, updated_object = review_request.get_last_activity()

    if draft:
        draft_timestamp = draft.last_updated
    else:
        draft_timestamp = ""

    etag = "%s:%s:%s:%s:%s:%s" % (
        request.user,
        last_activity_time,
        draft_timestamp,
        review_timestamp,
        int(starred),
        settings.AJAX_SERIAL,
    )

    if etag_if_none_match(request, etag):
        return HttpResponseNotModified()

    changedescs = review_request.changedescs.filter(public=True)
    latest_changedesc = None

    try:
        latest_changedesc = changedescs.latest()
        latest_timestamp = latest_changedesc.timestamp
    except ChangeDescription.DoesNotExist:
        latest_timestamp = None

    entries = []

    for temp_review in reviews:
        temp_review.ordered_comments = temp_review.comments.order_by("filediff", "first_line")

        state = ""

        # Mark as collapsed if the review is older than the latest change
        if latest_timestamp and temp_review.timestamp < latest_timestamp:
            state = "collapsed"

        try:
            latest_reply = temp_review.public_replies().latest("timestamp").timestamp
        except Review.DoesNotExist:
            latest_reply = None

        # Mark as expanded if there is a reply newer than last_visited
        if latest_reply and last_visited and last_visited < latest_reply:
            state = ""

        entries.append({"review": temp_review, "timestamp": temp_review.timestamp, "class": state})

    for changedesc in changedescs:
        fields_changed = []

        for name, info in changedesc.fields_changed.items():
            multiline = False

            if "added" in info or "removed" in info:
                change_type = "add_remove"

                # We don't hard-code URLs in the bug info, since the
                # tracker may move, but we can do it here.
                if name == "bugs_closed" and review_request.repository.bug_tracker:
                    bug_url = review_request.repository.bug_tracker
                    for field in info:
                        for i, buginfo in enumerate(info[field]):
                            try:
                                full_bug_url = bug_url % buginfo[0]
                                info[field][i] = (buginfo[0], full_bug_url)
                            except TypeError:
                                logging.warning("Invalid bugtracker url format")

            elif "old" in info or "new" in info:
                change_type = "changed"
                multiline = name == "description" or name == "testing_done"

                # Branch text is allowed to have entities, so mark it safe.
                if name == "branch":
                    if "old" in info:
                        info["old"][0] = mark_safe(info["old"][0])

                    if "new" in info:
                        info["new"][0] = mark_safe(info["new"][0])

                # Make status human readable.
                if name == "status":
                    if "old" in info:
                        info["old"][0] = status_to_string(info["old"][0])

                    if "new" in info:
                        info["new"][0] = status_to_string(info["new"][0])

            elif name == "screenshot_captions":
                change_type = "screenshot_captions"
            elif name == "file_captions":
                change_type = "file_captions"
            else:
                # No clue what this is. Bail.
                continue

            fields_changed.append(
                {
                    "title": fields_changed_name_map.get(name, name),
                    "multiline": multiline,
                    "info": info,
                    "type": change_type,
                }
            )

        # Expand the latest review change
        state = ""

        # Mark as collapsed if the change is older than a newer change
        if latest_timestamp and changedesc.timestamp < latest_timestamp:
            state = "collapsed"

        entries.append(
            {"changeinfo": fields_changed, "changedesc": changedesc, "timestamp": changedesc.timestamp, "class": state}
        )

    entries.sort(key=lambda item: item["timestamp"])

    close_description = ""

    if latest_changedesc and "status" in latest_changedesc.fields_changed:
        status = latest_changedesc.fields_changed["status"]["new"][0]

        if status in (ReviewRequest.DISCARDED, ReviewRequest.SUBMITTED):
            close_description = latest_changedesc.text

    response = render_to_response(
        template_name,
        RequestContext(
            request,
            _make_review_request_context(
                review_request,
                {
                    "draft": draft,
                    "detail_hooks": ReviewRequestDetailHook.hooks,
                    "review_request_details": draft or review_request,
                    "entries": entries,
                    "last_activity_time": last_activity_time,
                    "review": review,
                    "request": request,
                    "latest_changedesc": latest_changedesc,
                    "close_description": close_description,
                    "PRE_CREATION": PRE_CREATION,
                },
            ),
        ),
    )
    set_etag(response, etag)

    return response