From patchwork Mon Aug 23 14:58:44 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Raxel Gutierrez X-Patchwork-Id: 1519749 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.ozlabs.org (client-ip=112.213.38.117; helo=lists.ozlabs.org; envelope-from=patchwork-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org; receiver=) Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=google.com header.i=@google.com header.a=rsa-sha256 header.s=20161025 header.b=d2EaN3oJ; dkim-atps=neutral Received: from lists.ozlabs.org (lists.ozlabs.org [112.213.38.117]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4Gtb423fzCz9t0Y for ; Tue, 24 Aug 2021 00:59:14 +1000 (AEST) Received: from boromir.ozlabs.org (localhost [IPv6:::1]) by lists.ozlabs.org (Postfix) with ESMTP id 4Gtb422Y2sz2xsg for ; Tue, 24 Aug 2021 00:59:14 +1000 (AEST) Authentication-Results: lists.ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=google.com header.i=@google.com header.a=rsa-sha256 header.s=20161025 header.b=d2EaN3oJ; dkim-atps=neutral X-Original-To: patchwork@lists.ozlabs.org Delivered-To: patchwork@lists.ozlabs.org Authentication-Results: lists.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=flex--raxel.bounces.google.com (client-ip=2607:f8b0:4864:20::749; helo=mail-qk1-x749.google.com; envelope-from=3rlcjyqukcbkqzwdkfnnfkd.bnlozsbgvnqjkhrsr.nykzar.nqf@flex--raxel.bounces.google.com; receiver=) Authentication-Results: lists.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=google.com header.i=@google.com header.a=rsa-sha256 header.s=20161025 header.b=d2EaN3oJ; dkim-atps=neutral Received: from mail-qk1-x749.google.com (mail-qk1-x749.google.com [IPv6:2607:f8b0:4864:20::749]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 4Gtb3h5Yd5z2xff for ; Tue, 24 Aug 2021 00:58:55 +1000 (AEST) Received: by mail-qk1-x749.google.com with SMTP id d202-20020a3768d3000000b003d30722c98fso12008988qkc.10 for ; Mon, 23 Aug 2021 07:58:55 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=1xB+G2uWdhUXdd0vLcSTGJmGH54UxB2dDB9IlancL9I=; b=d2EaN3oJzqqvgc4cVzxZHZGeJDUOyitgsN9yP7e6ExS+oRuyoACzD/Vuorh+T1A/o6 4NJcCv1hKvRcMDt/gD8zW/uldHug2xrJZlDSLw/quGU5EGvlLjduMSjhk2hhipYHs+tF kuyjOqjb2cW9iI8PdBFp7Dcyy2AzJGOtuNS7oOZ6uNulFfLo6TcBfggwomNOvPAzSCV7 MiemTFtZWNPFIFW/PWhxxaptVIjVMC5wRhNmLgYKxC2v3xwsY5tEha4+WMjtC2ugtKTM /yqAKSyYb0kfGZXug3W/XMsI+vDh+gXCFmCgRa6HkAl8LyrGDpkTdZT8XNQZ7eSgmYcv z8jg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=1xB+G2uWdhUXdd0vLcSTGJmGH54UxB2dDB9IlancL9I=; b=pcg6yysCv7iKiUsuty/MnTtOAtxMKuo7/5WRJOZo56fFN0jtNRGR50EjVP9dXlx17j 6tvN3KVNG4e3nPzcbrdTNQ8++lq45SBTaJZuc1FH19WpzrLY4iFeucw/VOF0A5NLUuy6 ljeyl9EjLNikNrN4mTwWQEEiSIzROKpa66Jevas5XTPaKr5C2WnIbTPKC9WqpM4Sb/I3 uU/wuYfOuxUqF13XU+y38lW2PT1C03+aF5Azj5oTzqTsd825qyfOohXkdWArGN+I4bDZ bLyFuZM7ohKqqVX8WESFwUGBeBLd3DI4dboAfGc0xskcbxlOKfwOBa4m3lFWIg0Mn+MP E41A== X-Gm-Message-State: AOAM533lOPumbPMOIzufdAhW0T005F9GYg6bhk9yG0ScmKCGzmzKUNN5 JzDuZHl+m5abInH4WbKBqc6Q2Hg3FcvPI7fOb/3VuF2/yq//RczKILlB9zi3NR+D1LJy2HJQDCC kT+0kUf24U1iRZgNleHgpFBX8KGeMYqA980ikNZmEbv9egPQvPqhPujmQQRElK6GN X-Google-Smtp-Source: ABdhPJzoIyTqU8gS/Re1sFmHrgWu2SIYNhX9c6kmu7KzXTzNrnznPQnC4QUAJrsl4eVcK2/U4furgf9MyA== X-Received: from raxel-pw.c.googlers.com ([fda3:e722:ac3:cc00:14:4d90:c0a8:2fda]) (user=raxel job=sendgmr) by 2002:a05:6214:1501:: with SMTP id e1mr5595730qvy.62.1629730732521; Mon, 23 Aug 2021 07:58:52 -0700 (PDT) Date: Mon, 23 Aug 2021 14:58:44 +0000 In-Reply-To: <20210823145847.3944896-1-raxel@google.com> Message-Id: <20210823145847.3944896-2-raxel@google.com> Mime-Version: 1.0 References: <20210823145847.3944896-1-raxel@google.com> X-Mailer: git-send-email 2.33.0.rc2.250.ged5fa647cd-goog Subject: [RFC PATCH 1/4] patch-detail: add patch relation context From: Raxel Gutierrez To: patchwork@lists.ozlabs.org X-BeenThere: patchwork@lists.ozlabs.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Patchwork development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: patchwork-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org Sender: "Patchwork" These changes are setup for the upcoming change that adds a patch relations table to the submission page. In particular: - Add unaddressed and addressed counts to patches and patch relations to be able to view the information in the patch relations table. - Change the current patch tags count filter to a function of the patch object so that it can be used by the patch relations tags count filter. - Add template filter that retrieves a summary of the existence of tags (e.g. A/R/T) for a given patch relation. - Add the project maintainers as context to be auto-generate them in an email in the case that patch relations need to be modified. Signed-off-by: Raxel Gutierrez --- patchwork/models.py | 36 +++++++++++++++++++ patchwork/templates/patchwork/submission.html | 4 +++ patchwork/templatetags/patch.py | 34 ++++++++++++------ patchwork/views/patch.py | 23 +++++++++--- 4 files changed, 83 insertions(+), 14 deletions(-) diff --git a/patchwork/models.py b/patchwork/models.py index 58e4c51e..b1d8c5bc 100644 --- a/patchwork/models.py +++ b/patchwork/models.py @@ -462,6 +462,14 @@ class Patch(SubmissionMixin): objects = PatchManager() + @property + def unaddressed_comments_count(self): + return self.comments.filter(addressed=False).count() + + @property + def addressed_comments_count(self): + return self.comments.filter(addressed=True).count() + @staticmethod def extract_tags(content, tags): counts = Counter() @@ -494,6 +502,18 @@ class Patch(SubmissionMixin): for tag in tags: self._set_tag(tag, counter[tag]) + def patch_tags_count(self): + counts = [] + titles = [] + for tag in [t for t in self.project.tags if t.show_column]: + count = getattr(self, tag.attr_name) + titles.append('%d %s' % (count, tag.name)) + if count == 0: + counts.append("-") + else: + counts.append(count) + return counts, titles + def save(self, *args, **kwargs): if not hasattr(self, 'state') or not self.state: self.state = get_default_initial_patch_state() @@ -950,6 +970,22 @@ class BundlePatch(models.Model): class PatchRelation(models.Model): + @property + def unaddressed_comments_total(self): + total = 0 + patches = self.patches.all() + for patch in patches: + total += patch.unaddressed_comments_count + return total + + @property + def addressed_comments_total(self): + total = 0 + patches = self.patches.all() + for patch in patches: + total += patch.addressed_comments_count + return total + def __str__(self): patches = self.patches.all() if not patches: diff --git a/patchwork/templates/patchwork/submission.html b/patchwork/templates/patchwork/submission.html index 2238e82e..7dd6ae97 100644 --- a/patchwork/templates/patchwork/submission.html +++ b/patchwork/templates/patchwork/submission.html @@ -9,6 +9,10 @@ {% block headers %} + {% endblock %} {% block title %}{{submission.name}}{% endblock %} diff --git a/patchwork/templatetags/patch.py b/patchwork/templatetags/patch.py index 3837798d..c07c0bee 100644 --- a/patchwork/templatetags/patch.py +++ b/patchwork/templatetags/patch.py @@ -16,18 +16,25 @@ register = template.Library() @register.filter(name='patch_tags') def patch_tags(patch): - counts = [] - titles = [] - for tag in [t for t in patch.project.tags if t.show_column]: - count = getattr(patch, tag.attr_name) - titles.append('%d %s' % (count, tag.name)) - if count == 0: - counts.append("-") - else: - counts.append(str(count)) + counts, titles = patch.patch_tags_count() return mark_safe('%s' % ( ' / '.join(titles), - ' '.join(counts))) + ' '.join([str(x) for x in counts]))) + + +@register.filter(name='patch_relation_tags') +def patch_relation_tags(related_patches, project): + tags = [tag.abbrev for tag in project.tags] + tags_summary = ["-" for _ in range(len(tags))] + for patch in related_patches: + counts = patch.patch_tags_count()[0] + for i, count in enumerate(counts): + if count != '-': + # Replaces a non-zero tag count with tag abbreviation + # to indicate that existence of such tag in the set + # of related patches + tags_summary[i] = tags[i] + return mark_safe('%s' % (' '.join(tags_summary))) @register.filter(name='patch_checks') @@ -71,3 +78,10 @@ def patch_commit_display(patch): return mark_safe('%s' % (escape(fmt.format(commit)), escape(commit))) + + +# TODO: can be modularized into a utils.py templatetags file +# to get is_editable from any object +@register.filter(name='patch_is_editable') +def patch_is_editable(patch, user): + return patch.is_editable(user) diff --git a/patchwork/views/patch.py b/patchwork/views/patch.py index 00b0147f..8e685add 100644 --- a/patchwork/views/patch.py +++ b/patchwork/views/patch.py @@ -40,7 +40,11 @@ def patch_detail(request, project_id, msgid): # redirect to cover letters where necessary try: - patch = Patch.objects.get(project_id=project.id, msgid=db_msgid) + # Current patch needs tag counts when no relation exists + patch_qs = Patch.objects.filter( + project_id=project.id, msgid=db_msgid + ).with_tag_counts(project) + patch = patch_qs.get() except Patch.DoesNotExist: covers = Cover.objects.filter( project_id=project.id, @@ -113,15 +117,19 @@ def patch_detail(request, project_id, msgid): 'addressed') if patch.related: - related_same_project = patch.related.patches.only( - 'name', 'msgid', 'project', 'related') + related_same_project = patch.related.patches.order_by('-id').only( + 'name', 'msgid', 'project', 'related').with_tag_counts(project) + related_ids = {'ids': [rp.id for rp in related_same_project]} # avoid a second trip out to the db for info we already have related_different_project = [ related_patch for related_patch in related_same_project if related_patch.project_id != patch.project_id ] else: - related_same_project = [] + # If no patch relation exists, then current patch is only related. + # Add tag counts to the patch to display in patch relation table. + related_same_project = [patch] + related_ids = {'ids': [patch.id]} related_different_project = [] context['comments'] = comments @@ -133,7 +141,14 @@ def patch_detail(request, project_id, msgid): context['patchform'] = form context['createbundleform'] = createbundleform context['project'] = patch.project + context['maintainers'] = { + 'maintainers': [ + m.user.email for m in patch.project.maintainer_project.all() + ] + } + context['patch_relation'] = patch.related context['related_same_project'] = related_same_project + context['related_ids'] = related_ids context['related_different_project'] = related_different_project return render(request, 'patchwork/submission.html', context)