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
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
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
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
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
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
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
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 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
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 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
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)
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
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