internlm/SWE-Fixer-Train-110K huggingface dataset:
Repository: carpentries/amy

Issue:
displaying duplicate entries
@chrismedrela writes: It looks like we need to replace:

`return self.filter(conditional).order_by('slug', 'id')`

with:

`return self.filter(conditional).order_by('slug', 'id').distinct()`

in `EventQuerySet.unpublished_events` [1].

The same change may be necessary in `EventQuerySet.published_events`

[1] https://github.com/swcarpentry/amy/blob/develop/workshops/models.py#L767



Discussion:

Resolving patch:
diff --git a/workshops/models.py b/workshops/models.py
--- a/workshops/models.py
+++ b/workshops/models.py
@@ -764,13 +764,13 @@ def unpublished_events(self):
         """Return events considered as unpublished (see
         `unpublished_conditional` above)."""
         conditional = self.unpublished_conditional()
-        return self.filter(conditional).order_by('slug', 'id')
+        return self.filter(conditional).order_by('slug', 'id').distinct()
 
     def published_events(self):
         """Return events considered as published (see `unpublished_conditional`
         above)."""
         conditional = self.unpublished_conditional()
-        return self.exclude(conditional).order_by('-start', 'id')
+        return self.exclude(conditional).order_by('-start', 'id').distinct()
 
     def uninvoiced_events(self):
         '''Return a queryset for events that have not yet been invoiced.
@@ -787,7 +787,7 @@ def metadata_changed(self):
 
     def ttt(self):
         """Return only TTT events."""
-        return self.filter(tags__name='TTT')
+        return self.filter(tags__name='TTT').distinct()
 
 
 @reversion.register


Test patch:
diff --git a/workshops/test/test_event.py b/workshops/test/test_event.py
--- a/workshops/test/test_event.py
+++ b/workshops/test/test_event.py
@@ -110,6 +110,25 @@ def test_unpublished_events(self):
         self.assertNotIn(event_considered_published,
                          Event.objects.unpublished_events())
 
+    def test_unpublished_events_displayed_once(self):
+        """Regression test: unpublished events can't be displayed more than
+        once on the dashboard.  Refer to #977."""
+        self._setUpTags()
+        unpublished_event = Event.objects.create(
+            slug='2016-10-20-unpublished',
+            start=date(2016, 10, 20),
+            end=date(2016, 10, 21),
+            host=Organization.objects.first(),
+            administrator=Organization.objects.first(),
+        )
+        unpublished_event.tags = Tag.objects.filter(name__in=['TTT', 'online'])
+
+        unpublished = Event.objects.unpublished_events().select_related('host')
+        self.assertIn(unpublished_event, unpublished)
+        self.assertEqual(
+            1, len(unpublished.filter(slug='2016-10-20-unpublished'))
+        )
+
     def test_delete_event(self):
         """Make sure deleted event and its tasks are no longer accessible."""
         event = Event.objects.get(slug="starts-today-ongoing")
Repository: carpentries/amy

Issue:
"Unresponsive" workshops should not show up in "Workshop issues" attendance report 
If a workshop is marked "unresponsive" that means that the host/organizer/instructor has not responded to multiple attempts to get attendance data.

These should no longer show up in the attendance column of workshop issues.



Discussion:
A simple condition in the template should fix this.


Resolving patch:
diff --git a/workshops/views.py b/workshops/views.py
--- a/workshops/views.py
+++ b/workshops/views.py
@@ -2191,8 +2191,9 @@ def workshop_issues(request):
             )
         )
     )
+    no_attendance = Q(attendance=None) | Q(attendance=0)
     events = events.filter(
-        Q(attendance=None) | Q(attendance=0) |
+        (no_attendance & ~Q(tags__name='unresponsive')) |
         Q(country=None) |
         Q(venue=None) | Q(venue__exact='') |
         Q(address=None) | Q(address__exact='') |


Test patch:
diff --git a/workshops/test/test_issues.py b/workshops/test/test_issues.py
--- a/workshops/test/test_issues.py
+++ b/workshops/test/test_issues.py
@@ -2,7 +2,7 @@
 
 from django.core.urlresolvers import reverse
 
-from ..models import Event, Organization, Role, Person
+from ..models import Event, Organization, Role, Person, Tag
 from .base import TestBase
 
 
@@ -10,6 +10,7 @@ class TestIssuesViews(TestBase):
     def setUp(self):
         super()._setUpUsersAndLogin()
         super()._setUpRoles()
+        super()._setUpTags()
 
         self.url = reverse('workshop_issues')
         self.today = date.today()
@@ -62,9 +63,19 @@ def test_workshop_issues_no_attendance(self):
             country='US', address='A', venue='B', latitude=89, longitude=179)
         no_attendance.task_set.create(person=Person.objects.first(),
                                       role=self.instructor_role)
+        no_attendance_unresponsive = Event.objects.create(
+            slug='unresponsive-event-with-no-attendance',
+            start=self.weekago, end=self.yesterday,
+            attendance=0, host=Organization.objects.first(),
+            country='US', address='A', venue='B', latitude=89, longitude=179)
+        no_attendance_unresponsive.task_set.create(
+            person=Person.objects.first(), role=self.instructor_role)
+        no_attendance_unresponsive.tags.add(
+            Tag.objects.get(name='unresponsive'))
 
         rv = self.client.get(self.url)
         self.assertNotIn(attendance, rv.context['events'])
+        self.assertNotIn(no_attendance_unresponsive, rv.context['events'])
         self.assertIn(no_attendance, rv.context['events'])
 
     def test_workshop_issues_no_location(self):
Repository: carpentries/amy

Issue:
Server error when submitting trainee-match form without selected trainees
1. Go to the page for matching trainees to training sessions.
2. Select a training session, but do _not_ select a person.
3. Submit.
4. Boom - 500 error.



Discussion:

Resolving patch:
diff --git a/workshops/forms.py b/workshops/forms.py
--- a/workshops/forms.py
+++ b/workshops/forms.py
@@ -1410,7 +1410,7 @@ class BulkMatchTrainingRequestForm(forms.Form):
     def clean(self):
         super().clean()
 
-        if any(r.person is None for r in self.cleaned_data['requests']):
+        if any(r.person is None for r in self.cleaned_data.get('requests', [])):
             raise ValidationError('Some of the requests are not matched '
                                   'to a trainee yet. Before matching them to '
                                   'a training, you need to accept them '


Test patch:
Repository: carpentries/amy

Issue:
Remove $1250 from partner form item
Your call @maneesha, but shouldn't we remove the "$1250" from this line as our partnerships include coordinated workshops now?

https://github.com/swcarpentry/amy/blob/da20218f2497792962c96b42ecc21759cf928687/workshops/models.py#L1218



Discussion:
yes

@pbanaszkiewicz Can you please put this on the list for an upcoming milestone. Should be an easy fix.


Resolving patch:
diff --git a/workshops/migrations/0118_auto_20160922_0009.py b/workshops/migrations/0118_auto_20160922_0009.py
new file mode 100644
--- /dev/null
+++ b/workshops/migrations/0118_auto_20160922_0009.py
@@ -0,0 +1,20 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.9.9 on 2016-09-22 05:09
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('workshops', '0117_auto_20160904_0525'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='eventrequest',
+            name='admin_fee_payment',
+            field=models.CharField(choices=[('NP1', 'Non-profit / non-partner: US$2500'), ('FP1', 'For-profit: US$10,000'), ('self-organized', 'Self-organized: no fee (please let us know if you wish to make a donation)'), ('waiver', 'Waiver requested (please give details in "Anything else")')], default='NP1', max_length=40, verbose_name='Which of the following applies to your payment for the administrative fee?'),
+        ),
+    ]
diff --git a/workshops/models.py b/workshops/models.py
--- a/workshops/models.py
+++ b/workshops/models.py
@@ -1215,7 +1215,6 @@ class EventRequest(AssignmentMixin, ActiveMixin, CreatedUpdatedMixin,
 
     ADMIN_FEE_PAYMENT_CHOICES = (
         ('NP1', 'Non-profit / non-partner: US$2500'),
-        ('partner', 'Partner: US$1250'),
         ('FP1', 'For-profit: US$10,000'),
         ('self-organized', 'Self-organized: no fee (please let us know if you '
                            'wish to make a donation)'),


Test patch:
Repository: carpentries/amy

Issue:
Disable event submission form
@maneesha requested to disable the form so that people who know the link (Google?) can't submit before we actually go live with the form.



Discussion:

Resolving patch:
diff --git a/workshops/urls.py b/workshops/urls.py
--- a/workshops/urls.py
+++ b/workshops/urls.py
@@ -158,7 +158,7 @@
         url(r'^assign/(?P<person_id>[\w\.-]+)/$', views.eventsubmission_assign, name='eventsubmission_assign'),
     ])),
     url(r'^submit/$', views.EventSubmission.as_view(), name='event_submit'),
-    url(r'^submit/confirm/$', views.EventSubmissionConfirm.as_view(), name='event_submission_confirm'),
+    # url(r'^submit/confirm/$', views.EventSubmissionConfirm.as_view(), name='event_submission_confirm'),
 
     url(r'^profile_updates/$', views.AllProfileUpdateRequests.as_view(), name='all_profileupdaterequests'),
     url(r'^profile_updates/closed/$', views.AllClosedProfileUpdateRequests.as_view(), name='all_closed_profileupdaterequests'),
diff --git a/workshops/views.py b/workshops/views.py
--- a/workshops/views.py
+++ b/workshops/views.py
@@ -2712,7 +2712,10 @@ def profileupdaterequest_accept(request, request_id, person_id=None):
     return redirect(person.get_absolute_url())
 
 
-class EventSubmission(LoginNotRequiredMixin, EmailSendMixin, CreateViewContext):
+# This form is disabled as per @maneesha's request
+# class EventSubmission(LoginNotRequiredMixin, EmailSendMixin,
+#                       CreateViewContext):
+class EventSubmission(LoginNotRequiredMixin, TemplateView):
     """Display form for submitting existing workshops."""
     model = EventSubmissionModel
     form_class = EventSubmitForm


Test patch:
diff --git a/workshops/test/test_event_submissions.py b/workshops/test/test_event_submissions.py
--- a/workshops/test/test_event_submissions.py
+++ b/workshops/test/test_event_submissions.py
@@ -1,3 +1,5 @@
+import unittest
+
 from django.core import mail
 from django.core.urlresolvers import reverse
 
@@ -24,6 +26,7 @@ def test_exact_fields(self):
         ]
         self.assertEqual(fields_left, fields_right)
 
+    @unittest.skip('Event submission disabled as per @maneesha\'s request.')
     def test_submission_added(self):
         """Test if the submitted form adds a new event submission."""
         self.assertEqual(len(EventSubmission.objects.all()), 1)
@@ -42,6 +45,7 @@ def test_submission_added(self):
         self.assertNotIn('form', rv.context)
         self.assertEqual(len(EventSubmission.objects.all()), 2)
 
+    @unittest.skip('Event submission disabled as per @maneesha\'s request.')
     def test_submission_sends_email(self):
         """Test if the submitted form results in email sent."""
         data = {
Repository: carpentries/amy

Issue:
In bulk add person, interpret "role" column and use <select>.
In bulk add persons (https://amy.software-carpentry.org/workshops/persons/bulkadd/) we are given a csv template which is useful.

However, the names of roles as they display to the end user are not the same as the names of roles as stored in the database.  Can we either have instructions on what the roles need to be or have the csv importer translate this?



Discussion:
@maneesha, here is the translation:

| name in db | verbose name |
| --- | --- |
| contributor | Contributed to lesson materials |
| organizer | Workshop organizer |
| learner | Learner |
| host | Workshop host |
| instructor | Instructor |
| helper | Helper |

Where could I put the instructions you asked for?

We should:
1. match any-case 
2. provide a `<select>` to choose from for roles when editing a role in the table

@chrismedrela The instructions should go on the Bulk Import page.  I also like @pbanaszkiewicz idea to match case and select to edit.


Resolving patch:
diff --git a/workshops/views.py b/workshops/views.py
--- a/workshops/views.py
+++ b/workshops/views.py
@@ -687,6 +687,7 @@ def person_bulk_add(request):
         'title': 'Bulk Add People',
         'form': form,
         'charset': settings.DEFAULT_CHARSET,
+        'roles': Role.objects.all()
     }
     return render(request, 'workshops/person_bulk_add_form.html', context)
 


Test patch:
Repository: carpentries/amy

Issue:
Display SWC or DC tag next to workshop slug in "Current" list
On the main page  -  it would be useful to see at a glance whether the workshops listed as "Current" were SWC or DC. 

If you need room for this, the "Uninvoiced" column can be narrower.  The "ID" column in the "Unpublished" column can also be removed - this is unnecessary.  



Discussion:
Something like that? Do you want the labels to be on the left side or maybe somewhere else?
![image](https://cloud.githubusercontent.com/assets/1645996/18809672/63949ed6-8282-11e6-9552-0b80250b6474.png)

@chrismedrela - Yes, that's along the lines of what I was thinking of.  
Could we have the labels and slug text aligned?  See sample:
![63949ed6-8282-11e6-9552-0b80250b6474](https://cloud.githubusercontent.com/assets/829690/18878860/30c1e084-84a0-11e6-8e4a-1969c857cb18.png)


Resolving patch:
diff --git a/workshops/models.py b/workshops/models.py
--- a/workshops/models.py
+++ b/workshops/models.py
@@ -657,6 +657,11 @@ def __str__(self):
 
 #------------------------------------------------------------
 
+class TagQuerySet(models.query.QuerySet):
+    def carpentries(self):
+        return Tag.objects.filter(name__in=['SWC', 'DC', 'LC']).order_by('id')
+
+
 class Tag(models.Model):
     '''Label for grouping events.'''
 
@@ -666,6 +671,8 @@ class Tag(models.Model):
     def __str__(self):
         return self.name
 
+    objects = TagQuerySet.as_manager()
+
 #------------------------------------------------------------
 
 class Language(models.Model):
diff --git a/workshops/views.py b/workshops/views.py
--- a/workshops/views.py
+++ b/workshops/views.py
@@ -346,7 +346,8 @@ def admin_dashboard(request):
 
     current_events = (
         Event.objects.upcoming_events() | Event.objects.ongoing_events()
-    ).active()
+    ).active().prefetch_related('tags')
+
     uninvoiced_events = Event.objects.active().uninvoiced_events()
     unpublished_events = Event.objects.active().unpublished_events() \
                                       .select_related('host')
@@ -390,6 +391,7 @@ def admin_dashboard(request):
         'todos_start_date': TodoItemQuerySet.current_week_dates()[0],
         'todos_end_date': TodoItemQuerySet.next_week_dates()[1],
         'updated_metadata': updated_metadata,
+        'carpentries': Tag.objects.carpentries(),
     }
     return render(request, 'workshops/admin_dashboard.html', context)
 


Test patch:
Repository: carpentries/amy

Issue:
Transform github repo url into website url
If a website's github repo is https://github.com/barack_obama/2016-01-01-whitehouse then we know the website is https://barack_obama.github.io/2016-01-01-whitehouse

When using the "Import" or "Update from URL" it requires the _website_ rather than the _repo_.  However, if given the repo, can't we have AMY transform the URL into a valid website URL?  

Often I get a repo url from an instructor (esp. for self organized) workshops and I manually do that transformation myself.



Discussion:

Resolving patch:
diff --git a/workshops/util.py b/workshops/util.py
--- a/workshops/util.py
+++ b/workshops/util.py
@@ -473,8 +473,7 @@ class WrongWorkshopURL(ValueError):
     (see `generate_url_to_event_index` below)."""
 
     def __str__(self):
-        return ('Event\'s URL doesn\'t match Github website format '
-                '"http://user.github.io/2015-12-08-workshop".')
+        return 'Event\'s URL doesn\'t match Github website or repo format.'
 
 
 def generate_url_to_event_index(website_url):
@@ -482,11 +481,11 @@ def generate_url_to_event_index(website_url):
     file in GitHub repository."""
     template = ('https://raw.githubusercontent.com/{name}/{repo}'
                 '/gh-pages/index.html')
-    regex = Event.WEBSITE_REGEX
 
-    results = regex.match(website_url)
-    if results:
-        return template.format(**results.groupdict()), results.group('repo')
+    for regex in [Event.WEBSITE_REGEX, Event.REPO_REGEX]:
+        results = regex.match(website_url)
+        if results:
+            return template.format(**results.groupdict()), results.group('repo')
     raise WrongWorkshopURL()
 
 


Test patch:
diff --git a/workshops/test/test_util.py b/workshops/test/test_util.py
--- a/workshops/test/test_util.py
+++ b/workshops/test/test_util.py
@@ -99,6 +99,8 @@ def test_generating_url_to_index(self):
             'http://swcarpentry.github.io/workshop-template',
             'https://swcarpentry.github.com/workshop-template',
             'http://swcarpentry.github.com/workshop-template/',
+            'http://github.com/swcarpentry/workshop-template',
+            'https://github.com/swcarpentry/workshop-template',
         ]
         expected_url = ('https://raw.githubusercontent.com/swcarpentry/'
                         'workshop-template/gh-pages/index.html')
Repository: carpentries/amy

Issue:
Django Debug Toolbar should have SQL panel ON by default
Turning the panel ON allows to spot bottlenecks right on - just by looking at the number of queries (>8? Investigate).

This panel is the most useful and most often used by me. The next one is template variables, which is ON by default already.

Django Debug Toolbar should have SQL panel ON by default
Turning the panel ON allows to spot bottlenecks right on - just by looking at the number of queries (>8? Investigate).

This panel is the most useful and most often used by me. The next one is template variables, which is ON by default already.



Discussion:

Resolving patch:
diff --git a/amy/settings.py b/amy/settings.py
--- a/amy/settings.py
+++ b/amy/settings.py
@@ -346,10 +346,3 @@
 # Debug Toolbar
 DEBUG_TOOLBAR_PATCH_SETTINGS = False
 INTERNAL_IPS = ['127.0.0.1', '::1']
-DEBUG_TOOLBAR_CONFIG = {
-    # Disable all panels (except for timer) by default in order not to slow
-    # down page loading.
-    'DISABLE_PANELS': [
-        'debug_toolbar.panels.sql.SQLPanel',
-    ],
-}


Test patch:
Repository: carpentries/amy

Issue:
Add filter by group name in training applications list view

Add filter by group name in training applications list view



Discussion:

Resolving patch:
diff --git a/workshops/filters.py b/workshops/filters.py
--- a/workshops/filters.py
+++ b/workshops/filters.py
@@ -389,6 +389,11 @@ class TrainingRequestFilter(AMYFilterSet):
         action=filter_by_person,
     )
 
+    group_name = django_filters.CharFilter(
+        name='group_name',
+        lookup_type='icontains',
+        label='Group')
+
     state = django_filters.ChoiceFilter(
         label='State',
         choices=[('', 'Pending or accepted')] + TrainingRequest.STATES,
@@ -416,6 +421,7 @@ class Meta:
         model = TrainingRequest
         fields = [
             'search',
+            'group_name',
             'state',
             'matched',
             'affiliation',


Test patch:
Repository: carpentries/amy

Issue:
Display current partnership level in organization display.
Related to #1032, the "all organizations" page should have a column to show current membership status (if any).  Note "current": this page doesn't need to show memberships that are out of date.



Discussion:
@gvwilson, what exactly should be displayed in the column? `Membership.variant` (partner/affiliate/other) and `Membership.contribution_type` (financial/person-days/other)?


Resolving patch:
diff --git a/workshops/views.py b/workshops/views.py
--- a/workshops/views.py
+++ b/workshops/views.py
@@ -18,8 +18,10 @@
 from django.core.mail import EmailMultiAlternatives
 from django.core.urlresolvers import reverse, reverse_lazy
 from django.db import IntegrityError
-from django.db.models import Case, When, Value, IntegerField
-from django.db.models import Count, Q, F, Model, ProtectedError, Sum
+from django.db.models import (
+    Case, When, Value, IntegerField, Count, Q, F, Model, ProtectedError, Sum,
+    Prefetch,
+)
 from django.http import Http404, HttpResponse, JsonResponse
 from django.http import HttpResponseBadRequest, HttpResponseRedirect
 from django.shortcuts import redirect, render, get_object_or_404
@@ -406,9 +408,17 @@ def changes_log(request):
 @admin_required
 def all_organizations(request):
     '''List all organization.'''
+    now = datetime.datetime.now()
     filter = OrganizationFilter(
         request.GET,
-        queryset=Organization.objects.all()
+        queryset=Organization.objects.prefetch_related(Prefetch(
+            'membership_set',
+            to_attr='current_memberships',
+            queryset=Membership.objects.filter(
+                agreement_start__lte=now,
+                agreement_end__gte=now,
+            )
+        ))
     )
     organizations = get_pagination_items(request, filter)
     context = {'title' : 'All Organizations',


Test patch:
Repository: carpentries/amy

Issue:
Enable filtering by multiple partnership levels on organizations.
We should be able to filter organizations according to their partnership level.  User should be able to select multiple partnership levels, which should be combined with 'or' (i.e., show me silver or bronze).  For now, don't worry about temporal nature of partnerships: show all organizations that have, or have ever had, a particular partnership level.

Enable filtering by multiple partnership levels on organizations.
We should be able to filter organizations according to their partnership level.  User should be able to select multiple partnership levels, which should be combined with 'or' (i.e., show me silver or bronze).  For now, don't worry about temporal nature of partnerships: show all organizations that have, or have ever had, a particular partnership level.



Discussion:
@gvwilson, when you say partnership, do you mean `Membership`? 

Also, I don't think we track partnership levels (silver, bronze etc.) -- we only track variant (partner/affiliate/sponsor) and contribution type (financial/person-days/other).

Ahh, ok, I've just had a look at #1034 and I see there are new variants (bronze, silver etc.).

@gvwilson, when you say partnership, do you mean `Membership`? 

Also, I don't think we track partnership levels (silver, bronze etc.) -- we only track variant (partner/affiliate/sponsor) and contribution type (financial/person-days/other).

Ahh, ok, I've just had a look at #1034 and I see there are new variants (bronze, silver etc.).


Resolving patch:
diff --git a/workshops/filters.py b/workshops/filters.py
--- a/workshops/filters.py
+++ b/workshops/filters.py
@@ -19,6 +19,7 @@
     EventSubmission,
     DCSelfOrganizedEventRequest,
     TrainingRequest,
+    Membership,
 )
 
 EMPTY_SELECTION = (None, '---------')
@@ -172,6 +173,11 @@ class Meta:
 class OrganizationFilter(AMYFilterSet):
     country = AllCountriesFilter()
 
+    membership__variant = django_filters.MultipleChoiceFilter(
+        label='Memberships (current or past)',
+        choices=Membership.MEMBERSHIP_CHOICES,
+    )
+
     class Meta:
         model = Organization
         fields = [


Test patch: