def update_issue_status(self, request, comment_resource, *args, **kwargs): """Updates the issue status for a comment. Handles all of the logic for updating an issue status. """ try: review_request = \ resources.review_request.get_object(request, *args, **kwargs) comment = comment_resource.get_object(request, *args, **kwargs) except ObjectDoesNotExist: return DOES_NOT_EXIST # Check permissions to change the issue status if not comment.can_change_issue_status(request.user): return self._no_access_error(request.user) # We can only update the status of an issue if an issue has been # opened if not comment.issue_opened: raise PermissionDenied # We can only update the status of the issue issue_status = \ BaseComment.issue_string_to_status(kwargs.get('issue_status')) comment.issue_status = issue_status comment.save() last_activity_time, updated_object = review_request.get_last_activity() comment.timestamp = localize(comment.timestamp) return 200, { comment_resource.item_result_key: comment, 'last_activity_time': last_activity_time.isoformat(), }
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.get_comments(): review = comment.get_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, '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.get_comments(): review = comment.get_review() if review and (review.public or review.user == user): comments.append( { "comment_id": comment.id, "text": normalize_text_for_edit(user, comment.text, comment.rich_text), "rich_text": comment.rich_text, "user": { "username": escape(review.user.username), "name": escape(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, "issue_opened": comment.issue_opened, "issue_status": escape(BaseComment.issue_status_to_string(comment.issue_status)), } ) return json.dumps(comments)
def update_issue_status(self, request, comment_resource, *args, **kwargs): """Updates the issue status for a comment. Handles all of the logic for updating an issue status. """ try: review_request = \ resources.review_request.get_object(request, *args, **kwargs) comment = comment_resource.get_object(request, *args, **kwargs) except ObjectDoesNotExist: return DOES_NOT_EXIST # Check permissions to change the issue status if not comment.can_change_issue_status(request.user): return self.get_no_access_error(request) # We can only update the status of an issue if an issue has been # opened if not comment.issue_opened: raise PermissionDenied comment._review_request = review_request # We can only update the status of the issue issue_status = \ BaseComment.issue_string_to_status(kwargs.get('issue_status')) comment.issue_status = issue_status comment.save(update_fields=['issue_status']) last_activity_time, updated_object = review_request.get_last_activity() return 200, { comment_resource.item_result_key: comment, 'last_activity_time': last_activity_time.isoformat(), }
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.get_comments(): review = comment.get_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, 'issue_opened': comment.issue_opened, 'issue_status': BaseComment.issue_status_to_string( comment.issue_status), }) return json.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 ================== ==================================================== """ comments = {} user = context.get('user', None) for comment in screenshot.get_comments(): review = comment.get_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, '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 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 ================== ==================================================== """ comments = {} user = context.get('user', None) for comment in screenshot.get_comments(): review = comment.get_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, 'issue_opened': comment.issue_opened, 'issue_status': BaseComment.issue_status_to_string( comment.issue_status), }) return simplejson.dumps(comments)
def comment_issue(context, review_request, comment, comment_type): """ Renders the code responsible for handling comment issue statuses. """ issue_status = BaseComment.issue_status_to_string(comment.issue_status) user = context.get('user', None) return { 'comment': comment, 'comment_type': comment_type, 'issue_status': issue_status, 'review': comment.get_review(), 'interactive': comment.can_change_issue_status(user), }
def comment_issue(context, review_request, comment, comment_type): """ Renders the code responsible for handling comment issue statuses. """ issue_status = BaseComment.issue_status_to_string(comment.issue_status) user = context.get("user", None) return { "comment": comment, "comment_type": comment_type, "issue_status": issue_status, "review": comment.get_review(), "interactive": comment.can_change_issue_status(user), }
def should_update_issue_status(self, comment, issue_status=None, issue_opened=None, **kwargs): """Returns True if the comment should have its issue status updated. Determines if a comment should have its issue status updated based on the current state of the comment, the review, and the arguments passed in the request. """ if not issue_status: return False issue_status = BaseComment.issue_string_to_status(issue_status) return (comment.review.get().public and (comment.issue_opened or issue_opened) and issue_status != comment.issue_status)
def update_issue_status(self, request, comment_resource, *args, **kwargs): """Updates the issue status for a comment. Handles all of the logic for updating an issue status. """ try: review_request = \ resources.review_request.get_object(request, *args, **kwargs) comment = comment_resource.get_object(request, *args, **kwargs) except ObjectDoesNotExist: return DOES_NOT_EXIST # Check permissions to change the issue status if not comment.can_change_issue_status(request.user): return self.get_no_access_error(request) # We can only update the status of an issue if an issue has been # opened if not comment.issue_opened: raise PermissionDenied comment._review_request = review_request issue_status = \ BaseComment.issue_string_to_status(kwargs.get('issue_status')) # If the issue requires verification, ensure that only people who are # authorized can close it. if (comment.require_verification and issue_status in (BaseComment.RESOLVED, BaseComment.DROPPED) and comment.issue_status in (BaseComment.OPEN, BaseComment.VERIFYING_RESOLVED, BaseComment.VERIFYING_DROPPED) and not comment.can_verify_issue_status(request.user)): return self.get_no_access_error(request) # We can only update the status of the issue comment.issue_status = issue_status comment.save(update_fields=['issue_status']) last_activity_time = \ review_request.get_last_activity_info()['timestamp'] return 200, { comment_resource.item_result_key: comment, 'last_activity_time': last_activity_time.isoformat(), }
def update_issue_status(self, request, comment_resource, *args, **kwargs): """Updates the issue status for a comment. Handles all of the logic for updating an issue status. """ try: review_request = \ resources.review_request.get_object(request, *args, **kwargs) comment = comment_resource.get_object(request, *args, **kwargs) except ObjectDoesNotExist: return DOES_NOT_EXIST # Check permissions to change the issue status if not comment.can_change_issue_status(request.user): return self.get_no_access_error(request) # We can only update the status of an issue if an issue has been # opened if not comment.issue_opened: raise PermissionDenied comment._review_request = review_request issue_status = \ BaseComment.issue_string_to_status(kwargs.get('issue_status')) # If the issue requires verification, ensure that only people who are # authorized can close it. if (comment.require_verification and issue_status in (BaseComment.RESOLVED, BaseComment.DROPPED) and comment.issue_status in (BaseComment.OPEN, BaseComment.VERIFYING_RESOLVED, BaseComment.VERIFYING_DROPPED) and not comment.can_verify_issue_status(request.user)): return self.get_no_access_error(request) # We can only update the status of the issue comment.issue_status = issue_status comment.save(update_fields=['issue_status']) last_activity_time, updated_object = review_request.get_last_activity() return 200, { comment_resource.item_result_key: comment, 'last_activity_time': last_activity_time.isoformat(), }
def comment_issue(context, review_request, comment, comment_type): """ Renders the code responsible for handling comment issue statuses. """ issue_status = BaseComment.issue_status_to_string(comment.issue_status) user = context.get("user", None) interactive = "false" if user and user.is_authenticated() and user == review_request.submitter: interactive = "true" return { "comment": comment, "comment_type": comment_type, "issue_status": issue_status, "review": comment.review.get(), "interactive": interactive, }
def comment_issue(context, review_request, comment, comment_type): """ Renders the code responsible for handling comment issue statuses. """ issue_status = BaseComment.issue_status_to_string(comment.issue_status) user = context.get('user', None) interactive = 'false' if user and user.is_authenticated() and \ user == review_request.submitter: interactive = 'true' return { 'comment': comment, 'comment_type': comment_type, 'issue_status': issue_status, 'review': comment.get_review(), 'interactive': interactive, }
def comment_counts(user, all_comments, filediff, interfilediff=None): """ Returns an 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 plain or rich text of the comment rich_text The rich text flag for 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 = {} if interfilediff: key = (filediff.pk, interfilediff.pk) else: key = (filediff.pk, None) comments = all_comments.get(key, []) for comment in comments: review = comment.get_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': normalize_text_for_edit(user, comment.text, comment.rich_text), 'html': markdown_render_conditional(comment.text, comment.rich_text), 'rich_text': comment.rich_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), }, 'url': comment.get_review_url(), 'localdraft': (review.user == user and not review.public), 'review_id': review.id, 'issue_opened': comment.issue_opened, 'issue_status': BaseComment.issue_status_to_string( comment.issue_status), 'reply_to_id': comment.reply_to_id, }) comments_array = [] for key, value in six.iteritems(comment_dict): 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 comments_array
def pretty_print_issue_status(status): """Turns an issue status code into a human-readable status string.""" return BaseComment.issue_status_to_string(status)
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 issues = {'total': 0, 'open': 0, 'resolved': 0, 'dropped': 0} for entry in entries: if 'review' in entry: for comment in entry['review'].get_all_comments(issue_opened=True): issues['total'] += 1 issues[BaseComment.issue_status_to_string( comment.issue_status)] += 1 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, 'issues': issues, }))) 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 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 issues = { 'total': 0, 'open': 0, 'resolved': 0, 'dropped': 0 } for entry in entries: if 'review' in entry: for comment in entry['review'].get_all_comments(issue_opened=True): issues['total'] += 1 issues[BaseComment.issue_status_to_string( comment.issue_status)] += 1 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, 'issues': issues, }))) set_etag(response, etag) return response
def serialize_issue_status_field(self, obj, **kwargs): return BaseComment.issue_status_to_string(obj.issue_status)
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 comment_counts(user, all_comments, filediff, interfilediff=None): """ Returns an 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 plain or rich text of the comment rich_text The rich text flag for 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 = {} if interfilediff: key = (filediff.pk, interfilediff.pk) else: key = (filediff.pk, None) comments = all_comments.get(key, []) for comment in comments: review = comment.get_review() if review and (review.public or review.user_id == user.pk): key = (comment.first_line, comment.num_lines) comment_dict.setdefault(key, []).append({ 'comment_id': comment.id, 'text': normalize_text_for_edit(user, comment.text, comment.rich_text), 'html': markdown_render_conditional(comment.text, comment.rich_text), 'rich_text': comment.rich_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), }, 'url': comment.get_review_url(), 'localdraft': (review.user == user and not review.public), 'review_id': review.id, 'issue_opened': comment.issue_opened, 'issue_status': BaseComment.issue_status_to_string( comment.issue_status), 'reply_to_id': comment.reply_to_id, }) comments_array = [] for key, value in six.iteritems(comment_dict): comments_array.append({ 'linenum': key[0], 'num_lines': key[1], 'comments': value, }) comments_array.sort(key=cmp_to_key( lambda x, y: cmp(x['linenum'], y['linenum'] or cmp(x['num_lines'], y['num_lines'])))) return comments_array
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) all_comments = context.get('comments', {}) if interfilediff: key = (filediff.pk, interfilediff.pk) else: key = (filediff.pk, None) comments = all_comments.get(key, []) for comment in comments: review = comment.get_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': escape(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), }, 'url': comment.get_review_url(), 'localdraft': (review.user == user and not review.public), 'review_id': review.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)