def get_draft(self, user=None): """ Returns the draft of the review request. If a user is specified, than the draft will be returned only if owned by the user. Otherwise, None will be returned. """ if not user: return get_object_or_none(self.draft) elif user.is_authenticated(): return get_object_or_none(self.draft, review_request__submitter=user) return None
def submitter(request, username, template_name='reviews/datagrid.html', local_site_name=None): """ A list of review requests owned by a particular user. """ local_site = get_object_or_none(LocalSite, name=local_site_name) if local_site_name and not local_site: raise Http404 # Make sure the user exists if local_site: if not local_site.users.filter(username=username).exists(): raise Http404 else: get_object_or_404(User, username=username) datagrid = ReviewRequestDataGrid(request, ReviewRequest.objects.from_user(username, status=None, with_counts=True, local_site=local_site), _("%s's review requests") % username, local_site=local_site) return datagrid.render_to_response(template_name)
def view_diff_fragment(request, diffset_id, filediff_id, interdiffset_id=None, chunkindex=None, collapseall=False, template_name='diffviewer/diff_file_fragment.html'): 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) try: files = get_diff_files(diffset, filediff, interdiffset, highlighting) if files: assert len(files) == 1 file = files[0] context = { 'standalone': True, } return HttpResponse(build_diff_fragment(request, file, chunkindex, highlighting, collapseall, context, template_name)) raise UserVisibleError( _(u"Internal error. Unable to locate file record for filediff %s") % \ filediff.id) except Exception, e: return exception_traceback(request, e, template_name, {'standalone': True})
def dashboard(request, template_name='reviews/dashboard.html', local_site_name=None): """ The dashboard view, showing review requests organized by a variety of lists, depending on the 'view' parameter. Valid 'view' parameters are: * 'outgoing' * 'to-me' * 'to-group' * 'starred' * 'watched-groups' * 'incoming' * 'mine' """ view = request.GET.get('view', None) local_site = get_object_or_none(LocalSite, name=local_site_name) if view == "watched-groups": # This is special. We want to return a list of groups, not # review requests. grid = WatchedGroupDataGrid(request, local_site=local_site) else: grid = DashboardDataGrid(request, local_site=local_site) user = request.user profile = user.get_profile() return grid.render_to_response(template_name)
def view_diff_fragment(request, diffset_id, filediff_id, interdiffset_id=None, chunkindex=None, collapseall=False, template_name='diffviewer/diff_file_fragment.html'): 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) try: files = get_diff_files(diffset, filediff, interdiffset, highlighting) if files: assert len(files) == 1 file = files[0] context = { 'standalone': True, } return HttpResponse( build_diff_fragment(request, file, chunkindex, highlighting, collapseall, context, template_name)) raise UserVisibleError( _(u"Internal error. Unable to locate file record for filediff %s") % \ filediff.id) except Exception, e: return exception_traceback(request, e, template_name, {'standalone': True})
def file_attachment_comments(context, file_attachment): """Returns a JSON array of current comments for a file attachment.""" comments = [] user = context.get('user', None) for comment in file_attachment.comments.all(): review = get_object_or_none(comment.review) if review and (review.public or review.user == user): comments.append({ 'comment_id': comment.id, 'text': comment.text, 'user': { 'username': review.user.username, 'name': review.user.get_full_name() or review.user.username, }, 'url': comment.get_review_url(), 'localdraft': review.user == user and not review.public, 'review_id': review.id, 'review_request_id': review.review_request.id, 'issue_opened': comment.issue_opened, 'issue_status': BaseComment .issue_status_to_string(comment .issue_status), }) return simplejson.dumps(comments)
def file_attachment_comments(context, file_attachment): """Returns a JSON array of current comments for a file attachment.""" comments = [] user = context.get('user', None) for comment in file_attachment.comments.all(): review = get_object_or_none(comment.review) if review and (review.public or review.user == user): comments.append({ 'comment_id': comment.id, 'text': escape(comment.text), 'user': { 'username': review.user.username, 'name': review.user.get_full_name() or review.user.username, }, 'url': comment.get_review_url(), 'localdraft': review.user == user and not review.public, 'review_id': review.id, 'review_request_id': review.review_request.id, 'issue_opened': comment.issue_opened, 'issue_status': BaseComment .issue_status_to_string(comment .issue_status), }) return simplejson.dumps(comments)
def render_star(user, obj): """ Does the actual work of rendering the star. The star tag is a wrapper around this. """ if user.is_anonymous(): return "" try: profile = user.get_profile() except Profile.DoesNotExist: return "" if isinstance(obj, ReviewRequest): obj_info = { 'type': 'reviewrequests', 'id': obj.id } starred = bool(get_object_or_none(profile.starred_review_requests, pk=obj.id)) elif isinstance(obj, Group): obj_info = { 'type': 'groups', 'id': obj.name } starred = bool(get_object_or_none(profile.starred_groups, pk=obj.id)) else: raise template.TemplateSyntaxError, \ "star tag received an incompatible object type (%s)" % \ type(obj) if starred: image_alt = _("Starred") else: image_alt = _("Click to star") return render_to_string('reviews/star.html', { 'object': obj_info, 'starred': int(starred), 'alt': image_alt, 'user': user, 'MEDIA_URL': settings.MEDIA_URL, })
def get_pending_reply(self, user): """ Returns the pending reply to this review owned by the specified user, if any. """ if user.is_authenticated(): return get_object_or_none(Review, user=user, public=False, base_reply_to=self) return None
def group_list(request, local_site_name=None, template_name='reviews/datagrid.html'): """ Displays a list of all review groups. """ grid = GroupDataGrid( request, local_site=get_object_or_none(LocalSite, name=local_site_name)) return grid.render_to_response(template_name)
def view_diff_fragment( request, diffset_id, filediff_id, base_url, interdiffset_id=None, chunkindex=None, template_name='diffviewer/diff_file_fragment.html', error_template_name='diffviewer/diff_fragment_error.html'): """View which renders a specific fragment from a diff.""" 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) try: file = get_requested_diff_file() if file: context = { 'standalone': chunkindex is not None, 'base_url': base_url, } return HttpResponse( build_diff_fragment(request, file, chunkindex, highlighting, collapseall, context, template_name)) raise UserVisibleError( _(u"Internal error. Unable to locate file record for filediff %s") % \ filediff.id) except Exception, e: return exception_traceback( request, e, error_template_name, extra_context={'file': get_requested_diff_file(False)})
def view_diff_fragment( request, diffset_id, filediff_id, base_url, interdiffset_id=None, chunkindex=None, template_name='diffviewer/diff_file_fragment.html', error_template_name='diffviewer/diff_fragment_error.html'): """View which renders a specific fragment from a diff.""" 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) try: file = get_requested_diff_file() if file: context = { 'standalone': chunkindex is not None, 'base_url': base_url, } return HttpResponse(build_diff_fragment(request, file, chunkindex, highlighting, collapseall, context, template_name)) raise UserVisibleError( _(u"Internal error. Unable to locate file record for filediff %s") % \ filediff.id) except Exception, e: return exception_traceback( request, e, error_template_name, extra_context={'file': get_requested_diff_file(False)})
def screenshotcommentcounts(context, screenshot): """ Returns a JSON array of current comments for a screenshot. Each entry in the array has a dictionary containing the following keys: ================== ==================================================== Key Description ================== ==================================================== text The text of the comment localdraft True if this is the current user's draft comment x The X location of the comment's region y The Y location of the comment's region w The width of the comment's region h The height of the comment's region review_id The ID of the review this comment is associated with review_request_id The ID of the review request this comment is associated with ================== ==================================================== """ comments = {} user = context.get('user', None) for comment in screenshot.comments.all(): review = get_object_or_none(comment.review) if review and (review.public or review.user == user): position = '%dx%d+%d+%d' % (comment.w, comment.h, \ comment.x, comment.y) comments.setdefault(position, []).append({ 'comment_id': comment.id, 'text': comment.text, 'user': { 'username': review.user.username, 'name': review.user.get_full_name() or review.user.username, }, 'url': comment.get_review_url(), 'localdraft' : review.user == user and \ not review.public, 'x' : comment.x, 'y' : comment.y, 'w' : comment.w, 'h' : comment.h, 'review_id': review.id, 'review_request_id': review.review_request.id, 'issue_opened': comment.issue_opened, 'issue_status': BaseComment .issue_status_to_string(comment .issue_status), }) return simplejson.dumps(comments)
def screenshotcommentcounts(context, screenshot): """ Returns a JSON array of current comments for a screenshot. Each entry in the array has a dictionary containing the following keys: ================== ==================================================== Key Description ================== ==================================================== text The text of the comment localdraft True if this is the current user's draft comment x The X location of the comment's region y The Y location of the comment's region w The width of the comment's region h The height of the comment's region review_id The ID of the review this comment is associated with review_request_id The ID of the review request this comment is associated with ================== ==================================================== """ comments = {} user = context.get('user', None) for comment in screenshot.comments.all(): review = get_object_or_none(comment.review) if review and (review.public or review.user == user): position = '%dx%d+%d+%d' % (comment.w, comment.h, \ comment.x, comment.y) comments.setdefault(position, []).append({ 'comment_id': comment.id, 'text': escape(comment.text), 'user': { 'username': review.user.username, 'name': review.user.get_full_name() or review.user.username, }, 'url': comment.get_review_url(), 'localdraft': review.user == user and not review.public, 'x': comment.x, 'y': comment.y, 'w': comment.w, 'h': comment.h, 'review_id': review.id, 'review_request_id': review.review_request.id, 'issue_opened': comment.issue_opened, 'issue_status': BaseComment .issue_status_to_string(comment .issue_status), }) return simplejson.dumps(comments)
def screenshotcommentcounts(context, screenshot): """ Returns a JSON array of current comments for a screenshot. Each entry in the array has a dictionary containing the following keys: ================== ==================================================== Key Description ================== ==================================================== text The text of the comment localdraft True if this is the current user's draft comment x The X location of the comment's region y The Y location of the comment's region w The width of the comment's region h The height of the comment's region review_id The ID of the review this comment is associated with review_request_id The ID of the review request this comment is associated with ================== ==================================================== """ comments = {} user = context.get("user", None) for comment in screenshot.comments.all(): review = get_object_or_none(comment.review) if review and (review.public or review.user == user): position = "%dx%d+%d+%d" % (comment.w, comment.h, comment.x, comment.y) comments.setdefault(position, []).append( { "comment_id": comment.id, "text": comment.text, "user": { "username": review.user.username, "name": review.user.get_full_name() or review.user.username, }, "url": comment.get_review_url(), "localdraft": review.user == user and not review.public, "x": comment.x, "y": comment.y, "w": comment.w, "h": comment.h, "review_id": review.id, "review_request_id": review.review_request.id, "issue_opened": comment.issue_opened, "issue_status": BaseComment.issue_status_to_string(comment.issue_status), } ) return simplejson.dumps(comments)
def count_review_requests(request, func, api_format='json', local_site_name=None, *args, **kwargs): """ Returns the number of review requests. Optional parameters: * status: The status of the returned review requests. This defaults to "pending". """ local_site = get_object_or_none(LocalSite, name=local_site_name) status = string_to_status(request.GET.get('status', 'pending')) return WebAPIResponse(request, { 'count': func(user=request.user, status=status, local_site=local_site, **kwargs).count() })
def all_review_requests(request, local_site_name=None, template_name='reviews/datagrid.html'): """ Displays a list of all review requests. """ local_site = get_object_or_none(LocalSite, name=local_site_name) if local_site_name and not local_site: raise Http404 datagrid = ReviewRequestDataGrid(request, ReviewRequest.objects.public(request.user, status=None, local_site=local_site, with_counts=True), _("All review requests"), local_site=local_site) return datagrid.render_to_response(template_name)
def search(request, template_name='reviews/search.html', local_site_name=None): """ Searches review requests on Review Board based on a query string. """ query = request.GET.get('q', '') siteconfig = SiteConfiguration.objects.get_current() if not siteconfig.get("search_enable"): # FIXME: show something useful raise Http404 if not query: # FIXME: I'm not super thrilled with this return HttpResponseRedirect(reverse("root")) if query.isdigit(): query_review_request = get_object_or_none(ReviewRequest, pk=query) if query_review_request: return HttpResponseRedirect(query_review_request.get_absolute_url()) import lucene lv = [int(x) for x in lucene.VERSION.split('.')] lucene_is_2x = lv[0] == 2 and lv[1] < 9 lucene_is_3x = lv[0] == 3 or (lv[0] == 2 and lv[1] == 9) # We may have already initialized lucene try: lucene.initVM(lucene.CLASSPATH) except ValueError: pass index_file = siteconfig.get("search_index_file") if lucene_is_2x: store = lucene.FSDirectory.getDirectory(index_file, False) elif lucene_is_3x: store = lucene.FSDirectory.open(lucene.File(index_file)) else: assert False try: searcher = lucene.IndexSearcher(store) except lucene.JavaError, e: # FIXME: show a useful error raise e
def publish(self, user): """ Save the current draft attached to this review request. Send out the associated email. Returns the review request that was saved. """ if not self.is_mutable_by(user): raise PermissionError draft = get_object_or_none(self.draft) if draft is not None: # This will in turn save the review request, so we'll be done. changes = draft.publish(self, send_notification=False) draft.delete() else: changes = None self.public = True self.save() review_request_published.send(sender=self.__class__, user=user, review_request=self, changedesc=changes)
def group(request, name, template_name='reviews/datagrid.html', local_site_name=None): """ A list of review requests belonging to a particular group. """ # Make sure the group exists local_site = get_object_or_none(LocalSite, name=local_site_name) group = get_object_or_404(Group, name=name, local_site=local_site) if not group.is_accessible_by(request.user): return _render_permission_denied( request, 'reviews/group_permission_denied.html') datagrid = ReviewRequestDataGrid(request, ReviewRequest.objects.to_group(name, local_site, status=None, with_counts=True), _("Review requests for %s") % name) return datagrid.render_to_response(template_name)
def publish(self, user): """ Save the current draft attached to this review request. Send out the associated email. Returns the review request that was saved. """ if not self.is_mutable_by(user): raise PermissionError draft = get_object_or_none(self.draft) if draft is not None: # This will in turn save the review request, so we'll be done. changes = draft.publish(self) draft.delete() else: changes = None self.public = True self.save() siteconfig = SiteConfiguration.objects.get_current() if siteconfig.get("mail_send_review_mail"): mail_review_request(user, self, changes)
def filecommentcounts(context, files): """ Returns a JSON array of current comments for a screenshot. Each entry in the array has a dictionary containing the following keys: =========== ================================================== Key Description =========== ================================================== text The text of the comment localdraft True if this is the current user's draft comment =========== ================================================== """ fileComments = {} user = context.get('user', None) for upFile in files: default = '%s' % (upFile.id) upfileDefault = fileComments.setdefault(default, []) for comment in upFile.comments.all(): review = get_object_or_none(comment.review) if review and (review.public or review.user == user): position = '%s' % (comment.id) upfileDefault.append({ 'file_id': upFile.id, 'id': comment.id, 'text': comment.text, 'user': { 'username': review.user.username, 'name': review.user.get_full_name() or review.user.username, }, 'url': comment.get_review_url(), 'localdraft' : review.user == user and \ not review.public, }) return simplejson.dumps(fileComments)
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 commentcounts(context, filediff, interfilediff=None): """ Returns a JSON array of current comments for a filediff, sorted by line number. Each entry in the array has a dictionary containing the following keys: =========== ================================================== Key Description =========== ================================================== comment_id The ID of the comment text The text of the comment line The first line number num_lines The number of lines this comment spans user A dictionary containing "username" and "name" keys for the user url The URL to the comment localdraft True if this is the current user's draft comment review_id The ID of the review this comment is associated with ============================================================== """ comment_dict = {} user = context.get('user', None) if interfilediff: query = Comment.objects.filter(filediff=filediff, interfilediff=interfilediff) else: query = Comment.objects.filter(filediff=filediff, interfilediff__isnull=True) for comment in query: review = get_object_or_none(comment.review) if review and (review.public or review.user == user): key = (comment.first_line, comment.num_lines) comment_dict.setdefault(key, []).append({ 'comment_id': comment.id, 'text': comment.text, 'line': comment.first_line, 'num_lines': comment.num_lines, 'user': { 'username': review.user.username, 'name': review.user.get_full_name() or review.user.username, }, #'timestamp': comment.timestamp, 'url': comment.get_review_url(), 'localdraft': review.user == user and \ not review.public, 'review_id': review.id, 'review_request_id': review.review_request.id, 'issue_opened': comment.issue_opened, 'issue_status': BaseComment .issue_status_to_string(comment.issue_status), }) comments_array = [] for key, value in comment_dict.iteritems(): comments_array.append({ 'linenum': key[0], 'num_lines': key[1], 'comments': value, }) comments_array.sort(cmp=lambda x, y: cmp(x['linenum'], y['linenum'] or cmp(x['num_lines'], y['num_lines']))) return simplejson.dumps(comments_array)
def can_publish(self): return not self.public or get_object_or_none(self.draft) is not None
def check_delete_result(self, user, group_name): self.assertIsNone(get_object_or_none(Group, name=group_name))
def get_user(self, user_id): return get_object_or_none(User, pk=user_id)
def view_diff(request, diffset_id, interdiffset_id=None, extra_context={}, template_name='diffviewer/view_diff.html'): #import dbgp.client #dbgp.client.brk(port=9004) diffset = get_object_or_404(DiffSet, pk=diffset_id) interdiffset = get_object_or_none(DiffSet, pk=interdiffset_id) highlighting = get_enable_highlighting(request.user) try: if interdiffset_id: logging.debug( "Generating diff viewer page for interdiffset ids " "%s-%s", diffset_id, interdiffset_id) else: logging.debug("Generating diff viewer page for filediff id %s", diffset_id) files = get_diff_files(diffset, None, interdiffset, highlighting) # Break the list of files into pages siteconfig = SiteConfiguration.objects.get_current() paginator = Paginator(files, siteconfig.get("diffviewer_paginate_by"), siteconfig.get("diffviewer_paginate_orphans")) page_num = int(request.GET.get('page', 1)) if request.GET.get('file', False): file_id = int(request.GET['file']) for i, f in enumerate(files): if f['filediff'].id == file_id: page_num = i // paginator.per_page + 1 if page_num > paginator.num_pages: page_num = paginator.num_pages break page = paginator.page(page_num) if request.GET.get('expand', False): collapseall = False elif request.GET.get('collapse', False): collapseall = True elif request.COOKIES.has_key('collapsediffs'): collapseall = (request.COOKIES['collapsediffs'] == "True") else: collapseall = True context = { 'diffset': diffset, 'interdiffset': interdiffset, 'diffset_pair': (diffset, interdiffset), } context.update(extra_context) # XXX We can probably make this even more awesome and completely skip # the get_diff_files call, caching basically the entire context. for file in page.object_list: file['fragment'] = mark_safe( build_diff_fragment(request, file, None, highlighting, collapseall, context)) context['files'] = page.object_list # Add the pagination context context['is_paginated'] = page.has_other_pages() context['page'] = page.number context['pages'] = paginator.num_pages context['page_numbers'] = paginator.page_range context['has_next'] = page.has_next() context['next_page'] = page.next_page_number() context['has_previous'] = page.has_previous() context['previous_page'] = page.previous_page_number() context['page_start_index'] = page.start_index() response = render_to_response(template_name, RequestContext(request, context)) response.set_cookie('collapsediffs', collapseall) if interdiffset_id: logging.debug( "Done generating diff viewer page for interdiffset " "ids %s-%s", diffset_id, interdiffset_id) else: logging.debug( "Done generating diff viewer page for filediff " "id %s", diffset_id) return response except Exception, e: return exception_traceback(request, e, template_name)
def view_diff(request, diffset_id, interdiffset_id=None, extra_context={}, template_name='diffviewer/view_diff.html'): #import dbgp.client #dbgp.client.brk(port=9004) diffset = get_object_or_404(DiffSet, pk=diffset_id) interdiffset = get_object_or_none(DiffSet, pk=interdiffset_id) highlighting = get_enable_highlighting(request.user) try: if interdiffset_id: logging.debug("Generating diff viewer page for interdiffset ids " "%s-%s", diffset_id, interdiffset_id) else: logging.debug("Generating diff viewer page for filediff id %s", diffset_id) files = get_diff_files(diffset, None, interdiffset, highlighting) # Break the list of files into pages siteconfig = SiteConfiguration.objects.get_current() paginator = Paginator(files, siteconfig.get("diffviewer_paginate_by"), siteconfig.get("diffviewer_paginate_orphans")) page_num = int(request.GET.get('page', 1)) if request.GET.get('file', False): file_id = int(request.GET['file']) for i, f in enumerate(files): if f['filediff'].id == file_id: page_num = i // paginator.per_page + 1 if page_num > paginator.num_pages: page_num = paginator.num_pages break page = paginator.page(page_num) if request.GET.get('expand', False): collapseall = False elif request.GET.get('collapse', False): collapseall = True elif request.COOKIES.has_key('collapsediffs'): collapseall = (request.COOKIES['collapsediffs'] == "True") else: collapseall = True context = { 'diffset': diffset, 'interdiffset': interdiffset, 'diffset_pair': (diffset, interdiffset), } context.update(extra_context) # XXX We can probably make this even more awesome and completely skip # the get_diff_files call, caching basically the entire context. for file in page.object_list: file['fragment'] = mark_safe(build_diff_fragment(request, file, None, highlighting, collapseall, context)) context['files'] = page.object_list # Add the pagination context context['is_paginated'] = page.has_other_pages() context['page'] = page.number context['pages'] = paginator.num_pages context['page_numbers'] = paginator.page_range context['has_next'] = page.has_next() context['next_page'] = page.next_page_number() context['has_previous'] = page.has_previous() context['previous_page'] = page.previous_page_number() context['page_start_index'] = page.start_index() response = render_to_response(template_name, RequestContext(request, context)) response.set_cookie('collapsediffs', collapseall) if interdiffset_id: logging.debug("Done generating diff viewer page for interdiffset " "ids %s-%s", diffset_id, interdiffset_id) else: logging.debug("Done generating diff viewer page for filediff " "id %s", diffset_id) return response except Exception, e: return exception_traceback(request, e, template_name)
def check_delete_result(self, user, review_request_id): self.assertIsNone(get_object_or_none(ReviewRequest, pk=review_request_id))
def view_diff(request, diffset_id, interdiffset_id=None, extra_context={}, template_name='diffviewer/view_diff.html'): diffset = get_object_or_404(DiffSet, pk=diffset_id) interdiffset = get_object_or_none(DiffSet, pk=interdiffset_id) highlighting = get_enable_highlighting(request.user) try: if interdiffset_id: logging.debug("Generating diff viewer page for interdiffset ids " "%s-%s", diffset_id, interdiffset_id) else: logging.debug("Generating diff viewer page for filediff id %s", diffset_id) files = get_diff_files(diffset, None, interdiffset, highlighting, False) # Break the list of files into pages siteconfig = SiteConfiguration.objects.get_current() paginator = Paginator(files, siteconfig.get("diffviewer_paginate_by"), siteconfig.get("diffviewer_paginate_orphans")) page_num = int(request.GET.get('page', 1)) if request.GET.get('file', False): file_id = int(request.GET['file']) for i, f in enumerate(files): if f['filediff'].id == file_id: page_num = i // paginator.per_page + 1 if page_num > paginator.num_pages: page_num = paginator.num_pages break page = paginator.page(page_num) collapse_diffs = get_collapse_diff(request) context = { 'diffset': diffset, 'interdiffset': interdiffset, 'diffset_pair': (diffset, interdiffset), 'files': page.object_list, 'collapseall': collapse_diffs, # Add the pagination context 'is_paginated': page.has_other_pages(), 'page': page.number, 'pages': paginator.num_pages, 'page_numbers': paginator.page_range, 'has_next': page.has_next(), 'next_page': page.next_page_number(), 'has_previous': page.has_previous(), 'previous_page': page.previous_page_number(), 'page_start_index': page.start_index(), } context.update(extra_context) # Attempt to preload the first file before rendering any part of # the page. This helps to remove the perception that the diff viewer # takes longer to load now that we have progressive diffs. Users were # seeing the page itself load quickly, but didn't see that first # diff immediately and instead saw a spinner, making them feel it was # taking longer than it used to to load a page. We just trick the # user by providing that first file. if page.object_list: first_file = page.object_list[0] else: first_file = None if first_file: filediff = first_file['filediff'] if filediff.diffset == interdiffset: temp_files = get_diff_files(interdiffset, filediff, None, highlighting, True) else: temp_files = get_diff_files(diffset, filediff, interdiffset, highlighting, True) if temp_files: file_temp = temp_files[0] file_temp['index'] = first_file['index'] first_file['fragment'] = \ build_diff_fragment(request, file_temp, None, highlighting, collapse_diffs, context, 'diffviewer/diff_file_fragment.html') response = render_to_response(template_name, RequestContext(request, context)) response.set_cookie('collapsediffs', collapse_diffs) if interdiffset_id: logging.debug("Done generating diff viewer page for interdiffset " "ids %s-%s", diffset_id, interdiffset_id) else: logging.debug("Done generating diff viewer page for filediff " "id %s", diffset_id) return response except Exception, e: return exception_traceback(request, e, template_name)
def diff_line_comments(request, review_request_id, line, diff_revision, filediff_id, interdiff_revision=None, interfilediff_id=None): review_request = get_object_or_404(ReviewRequest, pk=review_request_id) filediff = get_object_or_404(FileDiff, pk=filediff_id, diffset__history=review_request.diffset_history, diffset__revision=diff_revision) if interdiff_revision is not None and interfilediff_id is not None: interfilediff = get_object_or_none(FileDiff, pk=interfilediff_id, diffset__history=review_request.diffset_history, diffset__revision=interdiff_revision) else: interfilediff = None if request.POST: if request.user.is_anonymous(): return WebAPIResponseError(request, NOT_LOGGED_IN) num_lines = request.POST['num_lines'] action = request.POST['action'] # TODO: Sanity check the fields if action == "set": text = request.POST['text'] review, review_is_new = Review.objects.get_or_create( review_request=review_request, user=request.user, public=False, base_reply_to__isnull=True) if interfilediff: comment, comment_is_new = review.comments.get_or_create( filediff=filediff, interfilediff=interfilediff, first_line=line) else: comment, comment_is_new = review.comments.get_or_create( filediff=filediff, interfilediff__isnull=True, first_line=line) comment.text = text comment.num_lines = num_lines comment.timestamp = datetime.now() comment.save() if comment_is_new: review.comments.add(comment) review.save() elif action == "delete": review = review_request.get_pending_review(request.user) if not review: raise Http404() q = Q(filediff=filediff, first_line=line) if interfilediff: q = q & Q(interfilediff=interfilediff) else: q = q & Q(interfilediff__isnull=True) try: comment = review.comments.get(q) comment.delete() except Comment.DoesNotExist: pass if review.body_top.strip() == "" and \ review.body_bottom.strip() == "" and \ review.comments.count() == 0 and \ review.screenshot_comments.count() == 0: review.delete() else: return WebAPIResponseError(request, INVALID_ACTION, {'action': action}) comments_query = filediff.comments.filter( Q(review__public=True) | Q(review__user=request.user), first_line=line) if interfilediff: comments_query = comments_query.filter(interfilediff=interfilediff) else: comments_query = comments_query.filter(interfilediff__isnull=True) return WebAPIResponse(request, { 'comments': comments_query })
def commentcounts(context, filediff, interfilediff=None): """ Returns a JSON array of current comments for a filediff, sorted by line number. Each entry in the array has a dictionary containing the following keys: =========== ================================================== Key Description =========== ================================================== comment_id The ID of the comment text The text of the comment line The first line number num_lines The number of lines this comment spans user A dictionary containing "username" and "name" keys for the user url The URL to the comment localdraft True if this is the current user's draft comment =========== ================================================== """ comment_dict = {} user = context.get('user', None) if interfilediff: query = Comment.objects.filter(filediff=filediff, interfilediff=interfilediff) else: query = Comment.objects.filter(filediff=filediff, interfilediff__isnull=True) for comment in query: review = get_object_or_none(comment.review) if review and (review.public or review.user == user): key = (comment.first_line, comment.num_lines) comment_dict.setdefault(key, []).append({ 'comment_id': comment.id, 'text': comment.text, 'line': comment.first_line, 'num_lines': comment.num_lines, 'user': { 'username': review.user.username, 'name': review.user.get_full_name() or review.user.username, }, #'timestamp': comment.timestamp, 'url': comment.get_review_url(), 'localdraft': review.user == user and \ not review.public, }) comments_array = [] for key, value in comment_dict.iteritems(): comments_array.append({ 'linenum': key[0], 'num_lines': key[1], 'comments': value, }) comments_array.sort(cmp=lambda x, y: cmp( x['linenum'], y['linenum'] or cmp(x['num_lines'], y['num_lines']))) return simplejson.dumps(comments_array)