Exemple #1
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
Exemple #2
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
Exemple #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
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
Exemple #5
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
Exemple #6
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
Exemple #7
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
Exemple #8
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
Exemple #9
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
Exemple #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 ObjectDoesNotExist:
            return DOES_NOT_EXIST

        if not self.has_access_permissions(request, obj, *args, **kwargs):
            return self.get_no_access_error(request, obj=obj, *args, **kwargs)

        last_modified_timestamp = self.get_last_modified(request, obj)
        etag = self.get_etag(request, obj, **kwargs)

        if self.are_cache_headers_current(request, last_modified_timestamp,
                                          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
Exemple #11
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 ObjectDoesNotExist:
            return DOES_NOT_EXIST

        if not self.has_access_permissions(request, obj, *args, **kwargs):
            return self.get_no_access_error(request, obj=obj, *args, **kwargs)

        last_modified_timestamp = self.get_last_modified(request, obj)
        etag = self.get_etag(request, obj, **kwargs)

        if self.are_cache_headers_current(request, last_modified_timestamp,
                                          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
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
Exemple #13
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
Exemple #14
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
Exemple #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
Exemple #16
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
Exemple #17
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)
Exemple #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)

            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
Exemple #19
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