Patchwork A new page that displays the patches for which the user is waiting feedback

login
register
mail settings
Submitter Guilherme Salgado
Date April 15, 2011, 8:45 p.m.
Message ID <20110415204519.26917.23542.stgit@localhost6.localdomain6>
Download mbox | patch
Permalink /patch/91437/
State Changes Requested
Headers show

Comments

Guilherme Salgado - April 15, 2011, 8:45 p.m.
This page shows all patches in a state that requires action and that have been
submitted by the logged in user to a given project.

Also, the profile page now has an extra section with links to this page for
every project on which the user has patches that need feedback.

Signed-off-by: Guilherme Salgado <guilherme.salgado@linaro.org>
---
 apps/patchwork/models.py         |    6 +++++
 apps/patchwork/tests/__init__.py |    1 +
 apps/patchwork/tests/models.py   |   46 ++++++++++++++++++++++++++++++++++++++
 apps/patchwork/urls.py           |    2 ++
 apps/patchwork/views/user.py     |   27 +++++++++++++++++++---
 5 files changed, 78 insertions(+), 4 deletions(-)
 create mode 100644 apps/patchwork/tests/models.py
Guilherme Salgado - April 29, 2011, 1:25 p.m.
Hi Jeremy,

This patch is marked on patchwork.ozlabs.org as having changes
requested, but I didn't get a reply from you about it.  Is that because
of the test changes to use the factory singleton rather than creating a
new instance?  If that's the case, I'd rather do those changes together
with any other changes you might want.

Cheers,

On Fri, 2011-04-15 at 17:45 -0300, Guilherme Salgado wrote:
> This page shows all patches in a state that requires action and that have been
> submitted by the logged in user to a given project.
> 
> Also, the profile page now has an extra section with links to this page for
> every project on which the user has patches that need feedback.
> 
> Signed-off-by: Guilherme Salgado <guilherme.salgado@linaro.org>
> ---
>  apps/patchwork/models.py         |    6 +++++
>  apps/patchwork/tests/__init__.py |    1 +
>  apps/patchwork/tests/models.py   |   46 ++++++++++++++++++++++++++++++++++++++
>  apps/patchwork/urls.py           |    2 ++
>  apps/patchwork/views/user.py     |   27 +++++++++++++++++++---
>  5 files changed, 78 insertions(+), 4 deletions(-)
>  create mode 100644 apps/patchwork/tests/models.py
> 
> diff --git a/apps/patchwork/models.py b/apps/patchwork/models.py
> index 6c8fc71..6a7ffc5 100644
> --- a/apps/patchwork/models.py
> +++ b/apps/patchwork/models.py
> @@ -104,6 +104,12 @@ class UserProfile(models.Model):
>      def n_todo_patches(self):
>          return self.todo_patches().count()
>  
> +    def submitted_patches_waiting_feedback(self, project):
> +        people = Person.objects.filter(user=self.user)
> +        states = State.objects.filter(action_required=True)
> +        return Patch.objects.filter(
> +            project=project, submitter__in=people, state__in=states)
> +
>      def todo_patches(self, project = None):
>  
>          # filter on project, if necessary
> diff --git a/apps/patchwork/tests/__init__.py b/apps/patchwork/tests/__init__.py
> index 68fe563..3adbbe7 100644
> --- a/apps/patchwork/tests/__init__.py
> +++ b/apps/patchwork/tests/__init__.py
> @@ -23,3 +23,4 @@ from patchwork.tests.bundles import *
>  from patchwork.tests.mboxviews import *
>  from patchwork.tests.updates import *
>  from patchwork.tests.filters import *
> +from patchwork.tests.models import *
> diff --git a/apps/patchwork/tests/models.py b/apps/patchwork/tests/models.py
> new file mode 100644
> index 0000000..501100e
> --- /dev/null
> +++ b/apps/patchwork/tests/models.py
> @@ -0,0 +1,46 @@
> +
> +from django.test import TestCase
> +
> +from patchwork.models import State
> +from patchwork.tests.factory import ObjectFactory
> +
> +
> +class UserProfileTestCase(TestCase):
> +
> +    def setUp(self):
> +        super(UserProfileTestCase, self).setUp()
> +        self.factory = ObjectFactory()
> +
> +    def test_submitted_patches_waiting_feedback(self):
> +        # Create two people linked to the same user.
> +        person = self.factory.makePerson(is_user=True)
> +        profile = person.user.get_profile()
> +        person2 = self.factory.makePerson(is_user=False)
> +        person2.user = person.user
> +        person2.save()
> +
> +        # Create 3 patches that
> +        #   - apply to the same project;
> +        #   - have been submitted by a Person linked to our newly created user
> +        # Of those 3 patches, only the first two are in a state that needs
> +        # action, so only those will be returned by
> +        # submitted_patches_waiting_feedback().
> +        # We also create a couple more patches, but one of them applies to a
> +        # different project than the ones created above and the other has not
> +        # been submitted by a Person linked to our user, so they are not in
> +        # the patches returned by submitted_patches_waiting_feedback().
> +        patch1 = self.factory.makePatch(submitter=person)
> +        project = patch1.project
> +        patch2 = self.factory.makePatch(project=project, submitter=person2)
> +        patch3 = self.factory.makePatch(project=project, submitter=person2)
> +        patch3.state = State.objects.get(name='Accepted')
> +        patch3.save()
> +        patch4 = self.factory.makePatch(submitter=person2)
> +        patch5 = self.factory.makePatch(project=project)
> +
> +        # Here we see that UserProfile.submitted_patches_waiting_feedback()
> +        # only returns the two patches that are in a state that requires
> +        # action and that have been submitted by a person linked to that
> +        # profile.
> +        patches = profile.submitted_patches_waiting_feedback(patch1.project)
> +        self.assertEquals([patch1, patch2], list(patches))
> diff --git a/apps/patchwork/urls.py b/apps/patchwork/urls.py
> index b49b4e1..984b843 100644
> --- a/apps/patchwork/urls.py
> +++ b/apps/patchwork/urls.py
> @@ -33,6 +33,8 @@ urlpatterns = patterns('',
>  
>      # logged-in user stuff
>      (r'^user/$', 'patchwork.views.user.profile'),
> +    (r'^user/submitted/(?P<project_id>[^/]+)/$',
> +        'patchwork.views.user.submitted_patches_list'),
>      (r'^user/todo/$', 'patchwork.views.user.todo_lists'),
>      (r'^user/todo/(?P<project_id>[^/]+)/$', 'patchwork.views.user.todo_list'),
>  
> diff --git a/apps/patchwork/views/user.py b/apps/patchwork/views/user.py
> index 1ae3c2d..6220156 100644
> --- a/apps/patchwork/views/user.py
> +++ b/apps/patchwork/views/user.py
> @@ -36,15 +36,22 @@ import django.core.urlresolvers
>  def profile(request):
>      context = PatchworkRequestContext(request)
>  
> +    profile = request.user.get_profile()
>      if request.method == 'POST':
> -        form = UserProfileForm(instance = request.user.get_profile(),
> -                data = request.POST)
> +        form = UserProfileForm(instance = profile, data = request.POST)
>          if form.is_valid():
>              form.save()
>      else:
> -        form = UserProfileForm(instance = request.user.get_profile())
> +        form = UserProfileForm(instance = profile)
>  
> -    context.project = request.user.get_profile().primary_project
> +    patches_waiting_for_feedback = {}
> +    for project in profile.contributor_projects():
> +        patches = profile.submitted_patches_waiting_feedback(project)
> +        if patches.count() > 0:
> +            patches_waiting_for_feedback[project] = patches
> +    context['patches_waiting_for_feedback'] = patches_waiting_for_feedback
> +
> +    context.project = profile.primary_project
>      context['bundles'] = Bundle.objects.filter(owner = request.user)
>      context['profileform'] = form
>  
> @@ -109,6 +116,18 @@ def unlink(request, person_id):
>  
> 
>  @login_required
> +def submitted_patches_list(request, project_id):
> +    project = get_object_or_404(Project, linkname=project_id)
> +    profile = request.user.get_profile()
> +    context = generic_list(
> +        request, project, 'patchwork.views.user.submitted_patches_list',
> +        view_args={'project_id': project_id},
> +        patches=profile.submitted_patches_waiting_feedback(project))
> +
> +    return render_to_response('patchwork/submitted-list.html', context)
> +
> +
> +@login_required
>  def todo_lists(request):
>      todo_lists = []
>  
> diff --git a/templates/patchwork/profile.html b/templates/patchwork/profile.html
> index 44df921..d4759c7 100644
> --- a/templates/patchwork/profile.html
> +++ b/templates/patchwork/profile.html
> @@ -36,6 +36,19 @@ Contributor to
>  </div>
>  
>  <div class="box">
> +<h2>Patches for which you are waiting feedback</h2>
> + {% if patches_waiting_for_feedback %}
> +  {% for project, patches in patches_waiting_for_feedback.items %}
> +   <p><a href="{% url patchwork.views.user.submitted_patches_list project.linkname %}">
> +    {{ patches.count }} <strong>{{ project.linkname }}</strong> patches</a>
> +   </p>
> +  {% endfor %}
> + {% else %}
> +  <p>There doesn't seem to be any patches for which you are waiting feedback.</p>
> + {% endif %}
> +</div>
> +
> +<div class="box">
>  <h2>Linked email addresses</h2>
>  <p>The following email addresses are associated with this patchwork account.
>  Adding alternative addresses allows patchwork to group contributions that
> diff --git a/templates/patchwork/submitted-list.html b/templates/patchwork/submitted-list.html
> new file mode 100644
> index 0000000..1604187
> --- /dev/null
> +++ b/templates/patchwork/submitted-list.html
> @@ -0,0 +1,14 @@
> +{% extends "base.html" %}
> +
> +{% load person %}
> +
> +{% block title %}Your patches for {{ project.name }}{% endblock %}
> +{% block heading %}Your patches for {{ project.name }}{% endblock %}
> +
> +{% block body %}
> +
> +<h2>Patches for which you are waiting feedback</h2>
> +
> +{% include "patchwork/patch-list.html" %}
> +
> +{% endblock %}
> 
> _______________________________________________
> Patchwork mailing list
> Patchwork@lists.ozlabs.org
> https://lists.ozlabs.org/listinfo/patchwork
Jeremy Kerr - April 29, 2011, 2:42 p.m.
Hi Guilherme,

> This patch is marked on patchwork.ozlabs.org as having changes
> requested, but I didn't get a reply from you about it.  Is that because
> of the test changes to use the factory singleton rather than creating a
> new instance?

Yes, that's exactly it - this will need to be altered to use the new
factory singleton.

Cheers,

Jeremy
Guilherme Salgado - April 29, 2011, 3:40 p.m.
On Fri, 2011-04-29 at 22:42 +0800, Jeremy Kerr wrote:
> Hi Guilherme,
> 
> > This patch is marked on patchwork.ozlabs.org as having changes
> > requested, but I didn't get a reply from you about it.  Is that because
> > of the test changes to use the factory singleton rather than creating a
> > new instance?
> 
> Yes, that's exactly it - this will need to be altered to use the new
> factory singleton.

Do you want me to make those changes before you review the patch?  I
thought it'd be ok for you to review it before that as they wouldn't
change anything significantly, but if you prefer I can do them before.

Cheers,

Patch

diff --git a/apps/patchwork/models.py b/apps/patchwork/models.py
index 6c8fc71..6a7ffc5 100644
--- a/apps/patchwork/models.py
+++ b/apps/patchwork/models.py
@@ -104,6 +104,12 @@  class UserProfile(models.Model):
     def n_todo_patches(self):
         return self.todo_patches().count()
 
+    def submitted_patches_waiting_feedback(self, project):
+        people = Person.objects.filter(user=self.user)
+        states = State.objects.filter(action_required=True)
+        return Patch.objects.filter(
+            project=project, submitter__in=people, state__in=states)
+
     def todo_patches(self, project = None):
 
         # filter on project, if necessary
diff --git a/apps/patchwork/tests/__init__.py b/apps/patchwork/tests/__init__.py
index 68fe563..3adbbe7 100644
--- a/apps/patchwork/tests/__init__.py
+++ b/apps/patchwork/tests/__init__.py
@@ -23,3 +23,4 @@  from patchwork.tests.bundles import *
 from patchwork.tests.mboxviews import *
 from patchwork.tests.updates import *
 from patchwork.tests.filters import *
+from patchwork.tests.models import *
diff --git a/apps/patchwork/tests/models.py b/apps/patchwork/tests/models.py
new file mode 100644
index 0000000..501100e
--- /dev/null
+++ b/apps/patchwork/tests/models.py
@@ -0,0 +1,46 @@ 
+
+from django.test import TestCase
+
+from patchwork.models import State
+from patchwork.tests.factory import ObjectFactory
+
+
+class UserProfileTestCase(TestCase):
+
+    def setUp(self):
+        super(UserProfileTestCase, self).setUp()
+        self.factory = ObjectFactory()
+
+    def test_submitted_patches_waiting_feedback(self):
+        # Create two people linked to the same user.
+        person = self.factory.makePerson(is_user=True)
+        profile = person.user.get_profile()
+        person2 = self.factory.makePerson(is_user=False)
+        person2.user = person.user
+        person2.save()
+
+        # Create 3 patches that
+        #   - apply to the same project;
+        #   - have been submitted by a Person linked to our newly created user
+        # Of those 3 patches, only the first two are in a state that needs
+        # action, so only those will be returned by
+        # submitted_patches_waiting_feedback().
+        # We also create a couple more patches, but one of them applies to a
+        # different project than the ones created above and the other has not
+        # been submitted by a Person linked to our user, so they are not in
+        # the patches returned by submitted_patches_waiting_feedback().
+        patch1 = self.factory.makePatch(submitter=person)
+        project = patch1.project
+        patch2 = self.factory.makePatch(project=project, submitter=person2)
+        patch3 = self.factory.makePatch(project=project, submitter=person2)
+        patch3.state = State.objects.get(name='Accepted')
+        patch3.save()
+        patch4 = self.factory.makePatch(submitter=person2)
+        patch5 = self.factory.makePatch(project=project)
+
+        # Here we see that UserProfile.submitted_patches_waiting_feedback()
+        # only returns the two patches that are in a state that requires
+        # action and that have been submitted by a person linked to that
+        # profile.
+        patches = profile.submitted_patches_waiting_feedback(patch1.project)
+        self.assertEquals([patch1, patch2], list(patches))
diff --git a/apps/patchwork/urls.py b/apps/patchwork/urls.py
index b49b4e1..984b843 100644
--- a/apps/patchwork/urls.py
+++ b/apps/patchwork/urls.py
@@ -33,6 +33,8 @@  urlpatterns = patterns('',
 
     # logged-in user stuff
     (r'^user/$', 'patchwork.views.user.profile'),
+    (r'^user/submitted/(?P<project_id>[^/]+)/$',
+        'patchwork.views.user.submitted_patches_list'),
     (r'^user/todo/$', 'patchwork.views.user.todo_lists'),
     (r'^user/todo/(?P<project_id>[^/]+)/$', 'patchwork.views.user.todo_list'),
 
diff --git a/apps/patchwork/views/user.py b/apps/patchwork/views/user.py
index 1ae3c2d..6220156 100644
--- a/apps/patchwork/views/user.py
+++ b/apps/patchwork/views/user.py
@@ -36,15 +36,22 @@  import django.core.urlresolvers
 def profile(request):
     context = PatchworkRequestContext(request)
 
+    profile = request.user.get_profile()
     if request.method == 'POST':
-        form = UserProfileForm(instance = request.user.get_profile(),
-                data = request.POST)
+        form = UserProfileForm(instance = profile, data = request.POST)
         if form.is_valid():
             form.save()
     else:
-        form = UserProfileForm(instance = request.user.get_profile())
+        form = UserProfileForm(instance = profile)
 
-    context.project = request.user.get_profile().primary_project
+    patches_waiting_for_feedback = {}
+    for project in profile.contributor_projects():
+        patches = profile.submitted_patches_waiting_feedback(project)
+        if patches.count() > 0:
+            patches_waiting_for_feedback[project] = patches
+    context['patches_waiting_for_feedback'] = patches_waiting_for_feedback
+
+    context.project = profile.primary_project
     context['bundles'] = Bundle.objects.filter(owner = request.user)
     context['profileform'] = form
 
@@ -109,6 +116,18 @@  def unlink(request, person_id):
 
 
 @login_required
+def submitted_patches_list(request, project_id):
+    project = get_object_or_404(Project, linkname=project_id)
+    profile = request.user.get_profile()
+    context = generic_list(
+        request, project, 'patchwork.views.user.submitted_patches_list',
+        view_args={'project_id': project_id},
+        patches=profile.submitted_patches_waiting_feedback(project))
+
+    return render_to_response('patchwork/submitted-list.html', context)
+
+
+@login_required
 def todo_lists(request):
     todo_lists = []
 
diff --git a/templates/patchwork/profile.html b/templates/patchwork/profile.html
index 44df921..d4759c7 100644
--- a/templates/patchwork/profile.html
+++ b/templates/patchwork/profile.html
@@ -36,6 +36,19 @@  Contributor to
 </div>
 
 <div class="box">
+<h2>Patches for which you are waiting feedback</h2>
+ {% if patches_waiting_for_feedback %}
+  {% for project, patches in patches_waiting_for_feedback.items %}
+   <p><a href="{% url patchwork.views.user.submitted_patches_list project.linkname %}">
+    {{ patches.count }} <strong>{{ project.linkname }}</strong> patches</a>
+   </p>
+  {% endfor %}
+ {% else %}
+  <p>There doesn't seem to be any patches for which you are waiting feedback.</p>
+ {% endif %}
+</div>
+
+<div class="box">
 <h2>Linked email addresses</h2>
 <p>The following email addresses are associated with this patchwork account.
 Adding alternative addresses allows patchwork to group contributions that
diff --git a/templates/patchwork/submitted-list.html b/templates/patchwork/submitted-list.html
new file mode 100644
index 0000000..1604187
--- /dev/null
+++ b/templates/patchwork/submitted-list.html
@@ -0,0 +1,14 @@ 
+{% extends "base.html" %}
+
+{% load person %}
+
+{% block title %}Your patches for {{ project.name }}{% endblock %}
+{% block heading %}Your patches for {{ project.name }}{% endblock %}
+
+{% block body %}
+
+<h2>Patches for which you are waiting feedback</h2>
+
+{% include "patchwork/patch-list.html" %}
+
+{% endblock %}