def get(self, request, *args, **kwargs): """ Retrieves the list of top-level resources, and a list of :term:`URI templates` for accessing any resource in the tree. """ etag = self.get_etag(request, None) if etag_if_none_match(request, etag): return HttpResponseNotModified() data = { 'links': self.get_links(self.list_child_resources, request=request, *args, **kwargs), } if self._include_uri_templates: data['uri_templates'] = self.get_uri_templates( request, *args, **kwargs) return 200, data, { 'ETag': etag, }
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 are_cache_headers_current(self, request, last_modified=None, etag=None): """Determines if cache headers from the client are current. This will compare the optionally-provided timestamp and ETag against any conditional cache headers sent by the client to determine if the headers are current. If they are, the caller can return HttpResponseNotModified instead of a payload. """ return ((last_modified and get_modified_since(request, last_modified)) or (etag and etag_if_none_match(request, etag)))
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, *args, **kwargs): """ Retrieves the list of top-level resources, and a list of :term:`URI templates` for accessing any resource in the tree. """ etag = self.get_etag(request, None) if etag_if_none_match(request, etag): return HttpResponseNotModified() data = { 'links': self.get_links(self.list_child_resources, request=request, *args, **kwargs), } if self._include_uri_templates: data['uri_templates'] = self.get_uri_templates(request, *args, **kwargs) return 200, data, { 'ETag': etag, }
def get(self, request, *args, **kwargs): """Handle GET requests for this view. This will create the renderer for the diff fragment and render it in order to get the PatchError information. It then returns a response with a zip file containing all the debug data. If no PatchError occurred, this will return a 404. Args: request (django.http.HttpRequest): The HTTP request. *args (tuple): Additional positional arguments for the view. **kwargs (dict): Additional keyword arguments for the view. Returns: django.http.HttpResponse: A response containing the data bundle. """ try: renderer_settings = self._get_renderer_settings(**kwargs) etag = self.make_etag(renderer_settings, **kwargs) if etag_if_none_match(request, etag): return HttpResponseNotModified() diff_info_or_response = self.process_diffset_info(**kwargs) if isinstance(diff_info_or_response, HttpResponse): return diff_info_or_response except Http404: return HttpResponseNotFound() except Exception as e: logging.exception( '%s.get: Error when processing diffset info for filediff ' 'ID=%s, interfilediff ID=%s, chunk_index=%s: %s', self.__class__.__name__, kwargs.get('filediff_id'), kwargs.get('interfilediff_id'), kwargs.get('chunk_index'), e, request=request) return HttpResponseServerError() kwargs.update(diff_info_or_response) try: context = self.get_context_data(**kwargs) renderer = self.create_renderer( context=context, renderer_settings=renderer_settings, *args, **kwargs) renderer.render_to_response(request) except PatchError as e: patch_error = e except Exception as e: logging.exception( '%s.get: Error when rendering diffset for filediff ID=%s, ' 'interfilediff ID=%s, chunk_index=%s: %s', self.__class__.__name__, kwargs.get('filediff_id'), kwargs.get('interfilediff_id'), kwargs.get('chunk_index'), e, request=request) return HttpResponseServerError() else: return HttpResponseNotFound() zip_data = StringIO() with ZipFile(zip_data, 'w') as zipfile: basename = os.path.basename(patch_error.filename) zipfile.writestr('%s.orig' % basename, patch_error.orig_file) zipfile.writestr('%s.diff' % basename, patch_error.diff) if patch_error.rejects: zipfile.writestr('%s.rej' % basename, patch_error.rejects) if patch_error.new_file: zipfile.writestr('%s.new' % basename, patch_error.new_file) rsp = HttpResponse(zip_data.getvalue(), content_type='application/zip') rsp['Content-Disposition'] = \ 'attachment; filename=%s.zip' % basename return rsp
def review_detail(request, review_request_id, local_site_name=None, template_name="reviews/review_detail.html"): """ Main view for review requests. This covers the review request information and all the reviews on it. """ # If there's a local_site passed in the URL, we want to look up the review # request based on the local_id instead of the pk. This allows each # local_site configured to have its own review request ID namespace # starting from 1. review_request, response = \ _find_review_request(request, review_request_id, local_site_name) if not review_request: return response reviews = review_request.get_public_reviews() review = review_request.get_pending_review(request.user) review_timestamp = 0 last_visited = 0 starred = False if request.user.is_authenticated(): # If the review request is public and pending review and if the user # is logged in, mark that they've visited this review request. if review_request.public and review_request.status == "P": visited, visited_is_new = ReviewRequestVisit.objects.get_or_create( user=request.user, review_request=review_request) last_visited = visited.timestamp visited.timestamp = datetime.now() visited.save() starred = review_request in \ request.user.get_profile().starred_review_requests.all() # Unlike review above, this covers replies as well. try: last_draft_review = Review.objects.filter( review_request=review_request, user=request.user, public=False).latest() review_timestamp = last_draft_review.timestamp except Review.DoesNotExist: pass draft = review_request.get_draft(request.user) # Find out if we can bail early. Generate an ETag for this. last_activity_time, updated_object = review_request.get_last_activity() if draft: draft_timestamp = draft.last_updated else: draft_timestamp = "" etag = "%s:%s:%s:%s:%s:%s" % (request.user, last_activity_time, draft_timestamp, review_timestamp, int(starred), settings.AJAX_SERIAL) if etag_if_none_match(request, etag): return HttpResponseNotModified() changedescs = review_request.changedescs.filter(public=True) try: latest_changedesc = changedescs.latest('timestamp') latest_timestamp = latest_changedesc.timestamp except ChangeDescription.DoesNotExist: latest_timestamp = None entries = [] for temp_review in reviews: temp_review.ordered_comments = \ temp_review.comments.order_by('filediff', 'first_line') state = '' # Mark as collapsed if the review is older than the latest change if latest_timestamp and temp_review.timestamp < latest_timestamp: state = 'collapsed' try: latest_reply = temp_review.public_replies().latest( 'timestamp').timestamp except Review.DoesNotExist: latest_reply = None # Mark as expanded if there is a reply newer than last_visited if latest_reply and last_visited and last_visited < latest_reply: state = '' entries.append({ 'review': temp_review, 'timestamp': temp_review.timestamp, 'class': state, }) for changedesc in changedescs: fields_changed = [] for name, info in changedesc.fields_changed.items(): multiline = False if 'added' in info or 'removed' in info: change_type = 'add_remove' # We don't hard-code URLs in the bug info, since the # tracker may move, but we can do it here. if (name == "bugs_closed" and review_request.repository.bug_tracker): bug_url = review_request.repository.bug_tracker for field in info: for i, buginfo in enumerate(info[field]): try: full_bug_url = bug_url % buginfo[0] info[field][i] = (buginfo[0], full_bug_url) except TypeError: logging.warning( "Invalid bugtracker url format") elif 'old' in info or 'new' in info: change_type = 'changed' multiline = (name == "description" or name == "testing_done") # Branch text is allowed to have entities, so mark it safe. if name == "branch": if 'old' in info: info['old'][0] = mark_safe(info['old'][0]) if 'new' in info: info['new'][0] = mark_safe(info['new'][0]) elif name == "screenshot_captions": change_type = 'screenshot_captions' else: # No clue what this is. Bail. continue fields_changed.append({ 'title': fields_changed_name_map.get(name, name), 'multiline': multiline, 'info': info, 'type': change_type, }) # Expand the latest review change state = '' # Mark as collapsed if the change is older than a newer change if latest_timestamp and changedesc.timestamp < latest_timestamp: state = 'collapsed' entries.append({ 'changeinfo': fields_changed, 'changedesc': changedesc, 'timestamp': changedesc.timestamp, 'class': state, }) entries.sort(key=lambda item: item['timestamp']) response = render_to_response( template_name, RequestContext( request, _make_review_request_context( review_request, { 'draft': draft, 'review_request_details': draft or review_request, 'entries': entries, 'last_activity_time': last_activity_time, 'review': review, 'request': request, 'PRE_CREATION': PRE_CREATION, }))) set_etag(response, etag) return response
def get(self, request, *args, **kwargs): """Returns the last update made to the review request. This shows the type of update that was made, the user who made the update, and when the update was made. Clients can use this to inform the user that the review request was updated, or automatically update it in the background. This does not take into account changes to a draft review request, as that's generally not update information that the owner of the draft is interested in. Only public updates are represented. """ try: review_request = \ resources.review_request.get_object(request, *args, **kwargs) except ObjectDoesNotExist: return DOES_NOT_EXIST if not resources.review_request.has_access_permissions(request, review_request): return self.get_no_access_error(request) info = review_request.get_last_activity_info() timestamp = info['timestamp'] updated_object = info['updated_object'] changedesc = info['changedesc'] etag = encode_etag('%s:%s' % (timestamp, updated_object.pk)) if etag_if_none_match(request, etag): return HttpResponseNotModified() summary = None update_type = None user = None if isinstance(updated_object, ReviewRequest): if updated_object.status == ReviewRequest.SUBMITTED: summary = _('Review request submitted') elif updated_object.status == ReviewRequest.DISCARDED: summary = _('Review request discarded') else: summary = _('Review request updated') update_type = 'review-request' elif isinstance(updated_object, DiffSet): summary = _('Diff updated') update_type = 'diff' elif isinstance(updated_object, Review): if updated_object.is_reply(): summary = _('New reply') update_type = 'reply' else: summary = _('New review') update_type = 'review' user = updated_object.user else: # Should never be able to happen. The object will always at least # be a ReviewRequest. assert False if changedesc: user = changedesc.get_user(review_request) elif user is None: # There is no changedesc which means this review request hasn't # been changed since it was first published, so this change must # be due to the original submitter. user = review_request.submitter return 200, { self.item_result_key: { 'timestamp': timestamp, 'user': user, 'summary': summary, 'type': update_type, } }, { 'ETag': etag, }
def get(self, request, *args, **kwargs): """Handle GET requests for this view. This will create the renderer for the diff fragment, render it, and return it. If there's an error when rendering the diff fragment, an error page will be rendered and returned instead. Args: request (django.http.HttpRequest): The HTTP request. *args (tuple): Additional positional arguments for the view. **kwargs (dict): Additional keyword arguments for the view. Returns: django.http.HttpResponse: A response containing the rendered fragment. """ filediff_id = kwargs.get('filediff_id') interfilediff_id = kwargs.get('interfilediff_id') chunk_index = kwargs.get('chunk_index') try: renderer_settings = self._get_renderer_settings(**kwargs) etag = self.make_etag(renderer_settings, **kwargs) if etag_if_none_match(request, etag): return HttpResponseNotModified() diff_info_or_response = self.process_diffset_info(**kwargs) if isinstance(diff_info_or_response, HttpResponse): return diff_info_or_response except Http404: raise except Exception as e: logging.exception( '%s.get: Error when processing diffset info ' 'for filediff ID=%s, interfilediff ID=%s, ' 'chunk_index=%s: %s', self.__class__.__name__, filediff_id, interfilediff_id, chunk_index, e, request=request) return exception_traceback(self.request, e, self.error_template_name) kwargs.update(diff_info_or_response) try: context = self.get_context_data(**kwargs) renderer = self.create_renderer( context=context, renderer_settings=renderer_settings, *args, **kwargs) response = renderer.render_to_response(request) except PatchError as e: logging.warning( '%s.get: PatchError when rendering diffset for filediff ' 'ID=%s, interfilediff ID=%s, chunk_index=%s: %s', self.__class__.__name__, filediff_id, interfilediff_id, chunk_index, e, request=request) try: url_kwargs = { key: kwargs[key] for key in ('chunk_index', 'interfilediff_id', 'review_request_id', 'filediff_id', 'revision', 'interdiff_revision') if key in kwargs and kwargs[key] is not None } bundle_url = local_site_reverse('patch-error-bundle', kwargs=url_kwargs, request=request) except NoReverseMatch: # We'll sometimes see errors about this failing to resolve when # web crawlers start accessing fragment URLs without the proper # attributes. Ignore them. bundle_url = '' if e.rejects: lexer = get_lexer_by_name('diff') formatter = HtmlFormatter() rejects = highlight(e.rejects, lexer, formatter) else: rejects = None return HttpResponseServerError( render_to_string( self.patch_error_template_name, RequestContext( request, { 'bundle_url': bundle_url, 'file': diff_info_or_response['diff_file'], 'filename': os.path.basename(e.filename), 'patch_output': e.error_output, 'rejects': mark_safe(rejects), }))) except FileNotFoundError as e: return HttpResponseServerError( render_to_string( self.error_template_name, RequestContext(request, { 'error': e, 'file': diff_info_or_response['diff_file'], }))) except Exception as e: logging.exception( '%s.get: Error when rendering diffset for ' 'filediff ID=%s, interfilediff ID=%s, ' 'chunkindex=%s: %s', self.__class__.__name__, filediff_id, interfilediff_id, chunk_index, e, request=request) return exception_traceback(self.request, e, self.error_template_name, extra_context={ 'file': diff_info_or_response['diff_file'], }) if response.status_code == 200: set_etag(response, etag) return response
def get(self, request, *args, **kwargs): """Returns the last update made to the review request. This shows the type of update that was made, the user who made the update, and when the update was made. Clients can use this to inform the user that the review request was updated, or automatically update it in the background. This does not take into account changes to a draft review request, as that's generally not update information that the owner of the draft is interested in. Only public updates are represented. """ try: review_request = \ resources.review_request.get_object(request, *args, **kwargs) except ObjectDoesNotExist: return DOES_NOT_EXIST if not resources.review_request.has_access_permissions( request, review_request): return self.get_no_access_error(request) info = review_request.get_last_activity_info() timestamp = info['timestamp'] updated_object = info['updated_object'] changedesc = info['changedesc'] etag = encode_etag('%s:%s' % (timestamp, updated_object.pk)) if etag_if_none_match(request, etag): return HttpResponseNotModified() summary = None update_type = None if isinstance(updated_object, ReviewRequest): if updated_object.status == ReviewRequest.SUBMITTED: summary = _('Review request submitted') elif updated_object.status == ReviewRequest.DISCARDED: summary = _('Review request discarded') else: summary = _('Review request updated') update_type = 'review-request' elif isinstance(updated_object, DiffSet): summary = _('Diff updated') update_type = 'diff' elif isinstance(updated_object, Review): if updated_object.is_reply(): summary = _('New reply') update_type = 'reply' else: summary = _('New review') update_type = 'review' else: # Should never be able to happen. The object will always at least # be a ReviewRequest. assert False if changedesc: user = changedesc.get_user(review_request) else: # There is no changedesc which means this review request hasn't # been changed since it was first published, so this change must # be due to the original submitter. user = review_request.submitter return 200, { self.item_result_key: { 'timestamp': timestamp, 'user': user, 'summary': summary, 'type': update_type, } }, { 'ETag': etag, }
def get(self, request, *args, **kwargs): """Returns the last update made to the review request. This shows the type of update that was made, the user who made the update, and when the update was made. Clients can use this to inform the user that the review request was updated, or automatically update it in the background. This does not take into account changes to a draft review request, as that's generally not update information that the owner of the draft is interested in. Only public updates are represented. """ try: review_request = \ resources.review_request.get_object(request, *args, **kwargs) except ObjectDoesNotExist: return DOES_NOT_EXIST if not resources.review_request.has_access_permissions( request, review_request): return self.get_no_access_error(request) timestamp, updated_object = review_request.get_last_activity() etag = encode_etag('%s:%s' % (timestamp, updated_object.pk)) if etag_if_none_match(request, etag): return HttpResponseNotModified() user = None summary = None update_type = None if isinstance(updated_object, ReviewRequest): user = updated_object.submitter if updated_object.status == ReviewRequest.SUBMITTED: summary = _("Review request submitted") elif updated_object.status == ReviewRequest.DISCARDED: summary = _("Review request discarded") else: summary = _("Review request updated") update_type = "review-request" elif isinstance(updated_object, DiffSet): summary = _("Diff updated") update_type = "diff" elif isinstance(updated_object, Review): user = updated_object.user if updated_object.is_reply(): summary = _("New reply") update_type = "reply" else: summary = _("New review") update_type = "review" else: # Should never be able to happen. The object will always at least # be a ReviewRequest. assert False return 200, { self.item_result_key: { 'timestamp': timestamp, 'user': user, 'summary': summary, 'type': update_type, } }, { 'ETag': etag, }
def get(self, request, *args, **kwargs): """Returns the last update made to the review request. This shows the type of update that was made, the user who made the update, and when the update was made. Clients can use this to inform the user that the review request was updated, or automatically update it in the background. This does not take into account changes to a draft review request, as that's generally not update information that the owner of the draft is interested in. Only public updates are represented. """ try: review_request = \ resources.review_request.get_object(request, *args, **kwargs) except ObjectDoesNotExist: return DOES_NOT_EXIST if not resources.review_request.has_access_permissions(request, review_request): return self.get_no_access_error(request) timestamp, updated_object = review_request.get_last_activity() etag = encode_etag('%s:%s' % (timestamp, updated_object.pk)) if etag_if_none_match(request, etag): return HttpResponseNotModified() user = None summary = None update_type = None if isinstance(updated_object, ReviewRequest): user = updated_object.submitter if updated_object.status == ReviewRequest.SUBMITTED: summary = _("Review request submitted") elif updated_object.status == ReviewRequest.DISCARDED: summary = _("Review request discarded") else: summary = _("Review request updated") update_type = "review-request" elif isinstance(updated_object, DiffSet): summary = _("Diff updated") update_type = "diff" elif isinstance(updated_object, Review): user = updated_object.user if updated_object.is_reply(): summary = _("New reply") update_type = "reply" else: summary = _("New review") update_type = "review" else: # Should never be able to happen. The object will always at least # be a ReviewRequest. assert False return 200, { self.item_result_key: { 'timestamp': timestamp, 'user': user, 'summary': summary, 'type': update_type, } }, { 'ETag': etag, }
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 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) 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, 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 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() 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