def _summarize_review_request(self, request, review_request, commit=None):
        """Returns a dict summarizing a ReviewRequest object.

        Example return value for a child request (a parent looks the same but
        without a 'commit' key):

        {
            'commit': 'ece2029d013af68f9f32aa0a6199fcb2201d5aae',
            'id': 3,
            'issue_open_count': 0,
            'last_updated': '2015-04-13T18:58:25Z',
            'links': {
                    'self': {
                        'href': 'http://127.0.0.1:50936/api/extensions/mozreview.extension.MozReviewExtension/summary/3/',
                        'method': 'GET'
                    }
            },
            'reviewers': [
                'jrandom'
            ],
            'reviewers_status': {
                'jrandom': {
                    'ship_it': True
                }
            },
            'status': 'pending',
            'submitter': 'mcote',
            'summary': 'Bug 1 - Update README.md.'
        }
        """
        reviewers = list(review_request.target_people.all())
        d = {}

        for field in ('id', 'summary', 'last_updated', 'issue_open_count'):
            d[field] = getattr(review_request, field)

        # TODO: 'submitter' and 'submitter_bmo_id' should be combined into one
        # attribute, likewise with 'reviewers' and 'reviewers_bmo_ids'.  See
        # bug 1164756.
        d['submitter'] = review_request.submitter.username
        d['submitter_bmo_id'] = BugzillaUserMap.objects.get(
            user_id=review_request.submitter.id).bugzilla_user_id
        d['status'] = status_to_string(review_request.status)
        d['reviewers'] = [reviewer.username for reviewer in reviewers]

        # If we have a commit (i.e. we are on a child) add reviewer_status.
        if commit:
            d['reviewers_status'] = get_reviewers_status(review_request,
                                                         reviewers)
        d['reviewers_bmo_ids'] = [bzuser.bugzilla_user_id for bzuser in
                                  BugzillaUserMap.objects.filter(user_id__in=[
                                      reviewer.id for reviewer in reviewers])]

        d['links'] = self.get_links(obj=review_request, request=request)

        if commit:
            d['commit'] = commit

        return d
Exemple #2
0
def get_review_request_data(rr):
    """Obtain a dictionary containing review request metadata.

    The dict consists of plain types (as opposed to ReviewBoard types).

    Some values may be unicode, not str.
    """
    rd = {
        'status': status_to_string(rr.status),
    }

    thing = rr
    try:
        thing = rr.draft.get()
        rd['public'] = False
    except ReviewRequestDraft.DoesNotExist:
        rd['public'] = rr.public

    rd['reviewers'] = [p.username for p in thing.target_people.all()]

    return rd
def get_review_request_data(rr):
    """Obtain a dictionary containing review request metadata.

    The dict consists of plain types (as opposed to ReviewBoard types).

    Some values may be unicode, not str.
    """
    rd = {
        'status': status_to_string(rr.status),
    }

    thing = rr
    try:
        thing = rr.draft.get()
        rd['public'] = False
    except ReviewRequestDraft.DoesNotExist:
        rd['public'] = rr.public

    rd['reviewers'] = [p.username for p in thing.target_people.all()]

    return rd
 def serialize_status_field(self, obj, **kwargs):
     return status_to_string(obj.status)
 def serialize_status_field(self, obj, **kwargs):
     return status_to_string(obj.status)
Exemple #6
0
def review_detail(request,
                  review_request_id,
                  local_site_name=None,
                  template_name="reviews/review_detail.html"):
    """
    Main view for review requests. This covers the review request information
    and all the reviews on it.
    """
    # If there's a local_site passed in the URL, we want to look up the review
    # request based on the local_id instead of the pk. This allows each
    # local_site configured to have its own review request ID namespace
    # starting from 1.
    review_request, response = \
        _find_review_request(request, review_request_id, local_site_name)

    if not review_request:
        return response

    reviews = review_request.get_public_reviews()
    review = review_request.get_pending_review(request.user)
    review_timestamp = 0
    last_visited = 0
    starred = False

    if request.user.is_authenticated():
        # If the review request is public and pending review and if the user
        # is logged in, mark that they've visited this review request.
        if review_request.public and review_request.status == "P":
            visited, visited_is_new = ReviewRequestVisit.objects.get_or_create(
                user=request.user, review_request=review_request)
            last_visited = visited.timestamp
            visited.timestamp = datetime.now()
            visited.save()

        profile, profile_is_new = Profile.objects.get_or_create(user=request.user)
        starred = review_request in profile.starred_review_requests.all()

        # Unlike review above, this covers replies as well.
        try:
            last_draft_review = Review.objects.filter(
                review_request=review_request,
                user=request.user,
                public=False).latest()
            review_timestamp = last_draft_review.timestamp
        except Review.DoesNotExist:
            pass


    draft = review_request.get_draft(request.user)

    # Find out if we can bail early. Generate an ETag for this.
    last_activity_time, updated_object = review_request.get_last_activity()

    if draft:
        draft_timestamp = draft.last_updated
    else:
        draft_timestamp = ""

    etag = "%s:%s:%s:%s:%s:%s" % (request.user, last_activity_time,
                                  draft_timestamp, review_timestamp,
                                  int(starred),
                                  settings.AJAX_SERIAL)

    if etag_if_none_match(request, etag):
        return HttpResponseNotModified()

    changedescs = review_request.changedescs.filter(public=True)
    latest_changedesc = None

    try:
        latest_changedesc = changedescs.latest()
        latest_timestamp = latest_changedesc.timestamp
    except ChangeDescription.DoesNotExist:
        latest_timestamp = None

    entries = []

    for temp_review in reviews:
        temp_review.ordered_comments = \
            temp_review.comments.order_by('filediff', 'first_line')

        state = ''

        # Mark as collapsed if the review is older than the latest change
        if latest_timestamp and temp_review.timestamp < latest_timestamp:
            state = 'collapsed'

        try:
            latest_reply = temp_review.public_replies().latest('timestamp').timestamp
        except Review.DoesNotExist:
            latest_reply = None

        # Mark as expanded if there is a reply newer than last_visited
        if latest_reply and last_visited and last_visited < latest_reply:
          state = ''

        entries.append({
            'review': temp_review,
            'timestamp': temp_review.timestamp,
            'class': state,
        })

    for changedesc in changedescs:
        fields_changed = []

        for name, info in changedesc.fields_changed.items():
            multiline = False

            if 'added' in info or 'removed' in info:
                change_type = 'add_remove'

                # We don't hard-code URLs in the bug info, since the
                # tracker may move, but we can do it here.
                if (name == "bugs_closed" and
                    review_request.repository.bug_tracker):
                    bug_url = review_request.repository.bug_tracker
                    for field in info:
                        for i, buginfo in enumerate(info[field]):
                            try:
                                full_bug_url = bug_url % buginfo[0]
                                info[field][i] = (buginfo[0], full_bug_url)
                            except TypeError:
                                logging.warning("Invalid bugtracker url format")

            elif 'old' in info or 'new' in info:
                change_type = 'changed'
                multiline = (name == "description" or name == "testing_done")

                # Branch text is allowed to have entities, so mark it safe.
                if name == "branch":
                    if 'old' in info:
                        info['old'][0] = mark_safe(info['old'][0])

                    if 'new' in info:
                        info['new'][0] = mark_safe(info['new'][0])

                # Make status human readable.
                if name == 'status':
                    if 'old' in info:
                        info['old'][0] = status_to_string(info['old'][0])

                    if 'new' in info:
                        info['new'][0] = status_to_string(info['new'][0])

            elif name == "screenshot_captions":
                change_type = 'screenshot_captions'
            elif name == "file_captions":
                change_type = 'file_captions'
            else:
                # No clue what this is. Bail.
                continue

            fields_changed.append({
                'title': fields_changed_name_map.get(name, name),
                'multiline': multiline,
                'info': info,
                'type': change_type,
            })

        # Expand the latest review change
        state = ''

        # Mark as collapsed if the change is older than a newer change
        if latest_timestamp and changedesc.timestamp < latest_timestamp:
            state = 'collapsed'

        entries.append({
            'changeinfo': fields_changed,
            'changedesc': changedesc,
            'timestamp': changedesc.timestamp,
            'class': state,
        })

    entries.sort(key=lambda item: item['timestamp'])

    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,
            'latest_changedesc': latest_changedesc,
            'PRE_CREATION': PRE_CREATION,
        })))
    set_etag(response, etag)

    return response
Exemple #7
0
def review_detail(request,
                  review_request_id,
                  local_site_name=None,
                  template_name="reviews/review_detail.html"):
    """
    Main view for review requests. This covers the review request information
    and all the reviews on it.
    """
    # If there's a local_site passed in the URL, we want to look up the review
    # request based on the local_id instead of the pk. This allows each
    # local_site configured to have its own review request ID namespace
    # starting from 1.
    review_request, response = \
        _find_review_request(request, review_request_id, local_site_name)

    if not review_request:
        return response

    reviews = review_request.get_public_reviews()
    review = review_request.get_pending_review(request.user)
    review_timestamp = 0
    last_visited = 0
    starred = False

    if request.user.is_authenticated():
        # If the review request is public and pending review and if the user
        # is logged in, mark that they've visited this review request.
        if review_request.public and review_request.status == "P":
            visited, visited_is_new = ReviewRequestVisit.objects.get_or_create(
                user=request.user, review_request=review_request)
            last_visited = visited.timestamp
            visited.timestamp = datetime.now()
            visited.save()

        profile, profile_is_new = Profile.objects.get_or_create(
            user=request.user)
        starred = review_request in profile.starred_review_requests.all()

        # Unlike review above, this covers replies as well.
        try:
            last_draft_review = Review.objects.filter(
                review_request=review_request, user=request.user,
                public=False).latest()
            review_timestamp = last_draft_review.timestamp
        except Review.DoesNotExist:
            pass

    draft = review_request.get_draft(request.user)

    # Find out if we can bail early. Generate an ETag for this.
    last_activity_time, updated_object = review_request.get_last_activity()

    if draft:
        draft_timestamp = draft.last_updated
    else:
        draft_timestamp = ""

    etag = "%s:%s:%s:%s:%s:%s" % (request.user, last_activity_time,
                                  draft_timestamp, review_timestamp,
                                  int(starred), settings.AJAX_SERIAL)

    if etag_if_none_match(request, etag):
        return HttpResponseNotModified()

    changedescs = review_request.changedescs.filter(public=True)
    latest_changedesc = None

    try:
        latest_changedesc = changedescs.latest()
        latest_timestamp = latest_changedesc.timestamp
    except ChangeDescription.DoesNotExist:
        latest_timestamp = None

    entries = []

    for temp_review in reviews:
        temp_review.ordered_comments = \
            temp_review.comments.order_by('filediff', 'first_line')

        state = ''

        # Mark as collapsed if the review is older than the latest change
        if latest_timestamp and temp_review.timestamp < latest_timestamp:
            state = 'collapsed'

        try:
            latest_reply = temp_review.public_replies().latest(
                'timestamp').timestamp
        except Review.DoesNotExist:
            latest_reply = None

        # Mark as expanded if there is a reply newer than last_visited
        if latest_reply and last_visited and last_visited < latest_reply:
            state = ''

        entries.append({
            'review': temp_review,
            'timestamp': temp_review.timestamp,
            'class': state,
        })

    for changedesc in changedescs:
        fields_changed = []

        for name, info in changedesc.fields_changed.items():
            multiline = False

            if 'added' in info or 'removed' in info:
                change_type = 'add_remove'

                # We don't hard-code URLs in the bug info, since the
                # tracker may move, but we can do it here.
                if (name == "bugs_closed"
                        and review_request.repository.bug_tracker):
                    bug_url = review_request.repository.bug_tracker
                    for field in info:
                        for i, buginfo in enumerate(info[field]):
                            try:
                                full_bug_url = bug_url % buginfo[0]
                                info[field][i] = (buginfo[0], full_bug_url)
                            except TypeError:
                                logging.warning(
                                    "Invalid bugtracker url format")

            elif 'old' in info or 'new' in info:
                change_type = 'changed'
                multiline = (name == "description" or name == "testing_done")

                # Branch text is allowed to have entities, so mark it safe.
                if name == "branch":
                    if 'old' in info:
                        info['old'][0] = mark_safe(info['old'][0])

                    if 'new' in info:
                        info['new'][0] = mark_safe(info['new'][0])

                # Make status human readable.
                if name == 'status':
                    if 'old' in info:
                        info['old'][0] = status_to_string(info['old'][0])

                    if 'new' in info:
                        info['new'][0] = status_to_string(info['new'][0])

            elif name == "screenshot_captions":
                change_type = 'screenshot_captions'
            elif name == "file_captions":
                change_type = 'file_captions'
            else:
                # No clue what this is. Bail.
                continue

            fields_changed.append({
                'title':
                fields_changed_name_map.get(name, name),
                'multiline':
                multiline,
                'info':
                info,
                'type':
                change_type,
            })

        # Expand the latest review change
        state = ''

        # Mark as collapsed if the change is older than a newer change
        if latest_timestamp and changedesc.timestamp < latest_timestamp:
            state = 'collapsed'

        entries.append({
            'changeinfo': fields_changed,
            'changedesc': changedesc,
            'timestamp': changedesc.timestamp,
            'class': state,
        })

    entries.sort(key=lambda item: item['timestamp'])

    close_description = ''

    if latest_changedesc and 'status' in latest_changedesc.fields_changed:
        status = latest_changedesc.fields_changed['status']['new'][0]

        if status in (ReviewRequest.DISCARDED, ReviewRequest.SUBMITTED):
            close_description = latest_changedesc.text

    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
Exemple #8
0
    def _summarize_review_request(self, request, review_request, commit=None):
        """Returns a dict summarizing a ReviewRequest object.

        Example return value for a child request (a parent looks the same but
        without a 'commit' key):

        {
            'commit': 'ece2029d013af68f9f32aa0a6199fcb2201d5aae',
            'diff': {
                'insert': 15,
                'delete': 20
            },
            'has_draft': False,
            'id': 3,
            'issue_open_count': 0,
            'last_updated': '2015-04-13T18:58:25Z',
            'links': {
                'self': {
                    'href': 'http://127.0.0.1:50936/api/extensions/mozreview.extension.MozReviewExtension/summary/3/',
                    'method': 'GET'
                }
            },
            'reviewers': [
                'jrandom'
            ],
            'reviewers_status': {
                'jrandom': {
                    'ship_it': True
                }
            },
            'status': 'pending',
            'submitter': 'mcote',
            'summary': 'Bug 1 - Update README.md.'
        }
        """
        reviewers = list(review_request.target_people.all())
        d = {}

        for field in ('id', 'summary', 'last_updated', 'issue_open_count'):
            d[field] = getattr(review_request, field)

        # TODO: 'submitter' and 'submitter_bmo_id' should be combined into one
        # attribute, likewise with 'reviewers' and 'reviewers_bmo_ids'.  See
        # bug 1164756.
        d['submitter'] = review_request.submitter.username
        d['submitter_bmo_id'] = BugzillaUserMap.objects.get(
            user_id=review_request.submitter.id).bugzilla_user_id
        d['status'] = status_to_string(review_request.status)
        d['reviewers'] = [reviewer.username for reviewer in reviewers]
        d['diff'] = get_diffstats(review_request, request.user)

        # If we have a commit (i.e. we are on a child) add reviewer_status.
        if commit:
            d['reviewers_status'] = get_reviewers_status(review_request,
                                                         reviewers)
        d['reviewers_bmo_ids'] = [bzuser.bugzilla_user_id for bzuser in
                                  BugzillaUserMap.objects.filter(user_id__in=[
                                      reviewer.id for reviewer in reviewers])]

        d['links'] = self.get_links(obj=review_request, request=request)

        if commit:
            d['commit'] = commit

        d['has_draft'] = review_request.get_draft() is not None

        return d
Exemple #9
0
def review_detail(request, review_request_id, local_site_name=None, template_name="reviews/review_detail.html"):
    """
    Main view for review requests. This covers the review request information
    and all the reviews on it.
    """
    # If there's a local_site passed in the URL, we want to look up the review
    # request based on the local_id instead of the pk. This allows each
    # local_site configured to have its own review request ID namespace
    # starting from 1.
    review_request, response = _find_review_request(request, review_request_id, local_site_name)

    if not review_request:
        return response

    reviews = review_request.get_public_reviews()
    review = review_request.get_pending_review(request.user)
    review_timestamp = 0
    last_visited = 0
    starred = False

    if request.user.is_authenticated():
        # If the review request is public and pending review and if the user
        # is logged in, mark that they've visited this review request.
        if review_request.public and review_request.status == "P":
            visited, visited_is_new = ReviewRequestVisit.objects.get_or_create(
                user=request.user, review_request=review_request
            )
            last_visited = visited.timestamp
            visited.timestamp = datetime.now()
            visited.save()

        profile, profile_is_new = Profile.objects.get_or_create(user=request.user)
        starred = review_request in profile.starred_review_requests.all()

        # Unlike review above, this covers replies as well.
        try:
            last_draft_review = Review.objects.filter(
                review_request=review_request, user=request.user, public=False
            ).latest()
            review_timestamp = last_draft_review.timestamp
        except Review.DoesNotExist:
            pass

    draft = review_request.get_draft(request.user)

    # Find out if we can bail early. Generate an ETag for this.
    last_activity_time, updated_object = review_request.get_last_activity()

    if draft:
        draft_timestamp = draft.last_updated
    else:
        draft_timestamp = ""

    etag = "%s:%s:%s:%s:%s:%s" % (
        request.user,
        last_activity_time,
        draft_timestamp,
        review_timestamp,
        int(starred),
        settings.AJAX_SERIAL,
    )

    if etag_if_none_match(request, etag):
        return HttpResponseNotModified()

    changedescs = review_request.changedescs.filter(public=True)
    latest_changedesc = None

    try:
        latest_changedesc = changedescs.latest()
        latest_timestamp = latest_changedesc.timestamp
    except ChangeDescription.DoesNotExist:
        latest_timestamp = None

    entries = []

    for temp_review in reviews:
        temp_review.ordered_comments = temp_review.comments.order_by("filediff", "first_line")

        state = ""

        # Mark as collapsed if the review is older than the latest change
        if latest_timestamp and temp_review.timestamp < latest_timestamp:
            state = "collapsed"

        try:
            latest_reply = temp_review.public_replies().latest("timestamp").timestamp
        except Review.DoesNotExist:
            latest_reply = None

        # Mark as expanded if there is a reply newer than last_visited
        if latest_reply and last_visited and last_visited < latest_reply:
            state = ""

        entries.append({"review": temp_review, "timestamp": temp_review.timestamp, "class": state})

    for changedesc in changedescs:
        fields_changed = []

        for name, info in changedesc.fields_changed.items():
            multiline = False

            if "added" in info or "removed" in info:
                change_type = "add_remove"

                # We don't hard-code URLs in the bug info, since the
                # tracker may move, but we can do it here.
                if name == "bugs_closed" and review_request.repository.bug_tracker:
                    bug_url = review_request.repository.bug_tracker
                    for field in info:
                        for i, buginfo in enumerate(info[field]):
                            try:
                                full_bug_url = bug_url % buginfo[0]
                                info[field][i] = (buginfo[0], full_bug_url)
                            except TypeError:
                                logging.warning("Invalid bugtracker url format")

            elif "old" in info or "new" in info:
                change_type = "changed"
                multiline = name == "description" or name == "testing_done"

                # Branch text is allowed to have entities, so mark it safe.
                if name == "branch":
                    if "old" in info:
                        info["old"][0] = mark_safe(info["old"][0])

                    if "new" in info:
                        info["new"][0] = mark_safe(info["new"][0])

                # Make status human readable.
                if name == "status":
                    if "old" in info:
                        info["old"][0] = status_to_string(info["old"][0])

                    if "new" in info:
                        info["new"][0] = status_to_string(info["new"][0])

            elif name == "screenshot_captions":
                change_type = "screenshot_captions"
            elif name == "file_captions":
                change_type = "file_captions"
            else:
                # No clue what this is. Bail.
                continue

            fields_changed.append(
                {
                    "title": fields_changed_name_map.get(name, name),
                    "multiline": multiline,
                    "info": info,
                    "type": change_type,
                }
            )

        # Expand the latest review change
        state = ""

        # Mark as collapsed if the change is older than a newer change
        if latest_timestamp and changedesc.timestamp < latest_timestamp:
            state = "collapsed"

        entries.append(
            {"changeinfo": fields_changed, "changedesc": changedesc, "timestamp": changedesc.timestamp, "class": state}
        )

    entries.sort(key=lambda item: item["timestamp"])

    close_description = ""

    if latest_changedesc and "status" in latest_changedesc.fields_changed:
        status = latest_changedesc.fields_changed["status"]["new"][0]

        if status in (ReviewRequest.DISCARDED, ReviewRequest.SUBMITTED):
            close_description = latest_changedesc.text

    response = render_to_response(
        template_name,
        RequestContext(
            request,
            _make_review_request_context(
                review_request,
                {
                    "draft": draft,
                    "detail_hooks": ReviewRequestDetailHook.hooks,
                    "review_request_details": draft or review_request,
                    "entries": entries,
                    "last_activity_time": last_activity_time,
                    "review": review,
                    "request": request,
                    "latest_changedesc": latest_changedesc,
                    "close_description": close_description,
                    "PRE_CREATION": PRE_CREATION,
                },
            ),
        ),
    )
    set_etag(response, etag)

    return response