source: asadb/forms/views.py @ cf509c0

space-accessstablestage
Last change on this file since cf509c0 was cf509c0, checked in by Alex Dehnert <adehnert@…>, 13 years ago

Basic list of groups at the midway

  • Property mode set to 100644
File size: 23.2 KB
RevLine 
[aba463b]1import forms.models
[90afb00]2import groups.models
[56e8cb8]3import groups.views
[cd98e17]4import util.emails
[90afb00]5
[afc5348]6from django.conf import settings
[0b72bfd]7from django.contrib.auth.decorators import user_passes_test, login_required, permission_required
[bda4d86]8from django.core.exceptions import PermissionDenied
[ea42397]9from django.views.generic import list_detail, ListView, DetailView
[aba463b]10from django.shortcuts import render_to_response, get_object_or_404
[90afb00]11from django.template import RequestContext
[f921734]12from django.template import Context, Template
13from django.template.loader import get_template
[0b72bfd]14from django.http import Http404, HttpResponseRedirect, HttpResponse
[90afb00]15from django.core.urlresolvers import reverse
[d199ba4]16from django.core.mail import EmailMessage, mail_admins
[d848b98]17from django.forms import FileField
[90afb00]18from django.forms import Form
19from django.forms import ModelForm
[b1a8ea7]20from django.forms import ModelChoiceField, ModelMultipleChoiceField
[3496370]21from django.forms import ValidationError
[4260e2c]22from django.db import connection
[ea42397]23from django.db.models import Q, Count
[aba463b]24
[7d7801f]25import collections
[0b72bfd]26import csv
[aba463b]27import datetime
[0b72bfd]28import StringIO
[aba463b]29
[90afb00]30#################
31# GENERIC VIEWS #
32#################
33
34class SelectGroupForm(Form):
35    group = ModelChoiceField(queryset=groups.models.Group.objects.all())
[2f7114b]36    def __init__(self, *args, **kwargs):
37        queryset = None
38        if 'queryset' in kwargs:
39            queryset = kwargs['queryset']
40            del kwargs['queryset']
[f921734]41        super(SelectGroupForm, self).__init__(*args, **kwargs)
42        if queryset is not None:
43            self.fields["group"].queryset = queryset
[90afb00]44
[bda4d86]45def select_group(request, url_name_after, url_args=[], pagename='homepage', queryset=None, title="", msg=""):
[90afb00]46    if request.method == 'POST': # If the form has been submitted...
[f921734]47        # A form bound to the POST data
48        form = SelectGroupForm(request.POST, queryset=queryset, )
[90afb00]49        if form.is_valid(): # All validation rules pass
50            group = form.cleaned_data['group'].id
[bda4d86]51            return HttpResponseRedirect(reverse(url_name_after, args=url_args+[group],)) # Redirect after POST
[90afb00]52    else:
[f921734]53        form = SelectGroupForm(queryset=queryset, ) # An unbound form
[90afb00]54
[bda4d86]55    if not title: title = "Select group"
[90afb00]56    context = {
57        'form':form,
[bda4d86]58        'title':title,
59        'msg':msg,
[0b488d4]60        'pagename':pagename,
[90afb00]61    }
62    return render_to_response('forms/select.html', context, context_instance=RequestContext(request), )
63
64#############################
65# FIRST-YEAR SUMMER MAILING #
66#############################
67
[00e16ed]68@login_required
[97399af]69def fysm_by_years(request, year, category, ):
[aba463b]70    if year is None: year = datetime.date.today().year
71    queryset = forms.models.FYSM.objects.filter(year=year).order_by('group__name')
[dafa3c8]72    category_obj = None
[a10dd4b]73    category_name = 'main'
[dafa3c8]74    if category != None:
[c27da9e]75        category_obj = get_object_or_404(forms.models.FYSMCategory, slug=category)
[a10dd4b]76        category_name = category_obj.name
[c27da9e]77        queryset = queryset.filter(categories=category_obj)
[a10dd4b]78    forms.models.FYSMView.record_metric(request=request, fysm=None, year=year, page=category_name, )
[c27da9e]79    categories = forms.models.FYSMCategory.objects.all()
[aba463b]80    return list_detail.object_list(
81        request,
82        queryset=queryset,
[90afb00]83        template_name="fysm/fysm_listing.html",
[aba463b]84        template_object_name="fysm",
85        extra_context={
86            "year": year,
87            "pagename": "fysm",
[dafa3c8]88            "category": category_obj,
[189506e]89            "categories": categories,
[aba463b]90        }
91    )
[90afb00]92
[00e16ed]93@login_required
[aaa8e04]94def fysm_view(request, year, submission, ):
[ae881e5]95    submit_obj = get_object_or_404(forms.models.FYSM, pk=submission,)
96    all = forms.models.FYSM.objects.only("id", "display_name", )
97    try:
98        prev = all.filter(display_name__lt=submit_obj.display_name).order_by("-display_name")[0]
99    except IndexError:
100        prev = None
101    try:
102        next = all.filter(display_name__gt=submit_obj.display_name).order_by("display_name")[0]
103    except IndexError:
104        next = None
[a10dd4b]105    forms.models.FYSMView.record_metric(request=request, fysm=submit_obj, year=year, page="detail", )
[aaa8e04]106    return list_detail.object_detail(
107        request,
108        forms.models.FYSM.objects,
109        object_id=submission,
110        template_name="fysm/fysm_detail.html",
111        template_object_name="fysm",
112        extra_context={
113            "year": year,
114            "pagename": "fysm",
[ae881e5]115            "prev": prev,
116            "next": next,
[aaa8e04]117        },
118    )
119
[f462be6]120def fysm_link(request, year, link_type, submission, ):
121    submit_obj = get_object_or_404(forms.models.FYSM, pk=submission,)
122    if submit_obj.year != int(year):
123        raise Http404("Year mismatch: fysm.year='%s', request's year='%s'" % (submit_obj.year, year, ))
124    if link_type == 'join':
125        url = submit_obj.join_url
126    elif link_type == 'website':
127        url = submit_obj.website
128    else:
129        raise Http404("Unknown link type")
[a10dd4b]130    forms.models.FYSMView.record_metric(request=request, fysm=submit_obj, year=year, page=link_type, )
[f462be6]131    return HttpResponseRedirect(url)
132
[f921734]133def select_group_fysm(request, ):
[2c0eaa1]134    qobj = Q(activity_category__isnull = True) | ~(Q(activity_category__name='Dorm') | Q(activity_category__name='FSILG'))
[d3167b9]135    queryset = groups.models.Group.active_groups.filter(qobj)
[f921734]136    return select_group(
137        request,
138        url_name_after='fysm-manage',
139        pagename='fysm',
140        queryset=queryset,
141    )
142
[90afb00]143class FYSMRequestForm(ModelForm):
144    class Meta:
145        model = forms.models.FYSM
146        fields = (
147            'display_name',
148            'website',
149            'join_url',
150            'contact_email',
151            'description',
152            'logo',
[3400018]153            'slide',
[57f8ffa]154            'tags',
[c27da9e]155            'categories',
[90afb00]156        )
157
[3496370]158    def clean_display_name(self, ):
159        name = self.cleaned_data['display_name']
160        if ',' in name:
161            raise ValidationError("""In general, commas in a display name are a mistake and will look bad (group names like "Punctuation Society, MIT" should probably be "Punctuation Society"). If you do want a comma, contact asa-fysm@mit.edu and we'll put it in for you.""")
162        return name
163
[cbdbd1f]164    def clean_description(self, ):
165        description = self.cleaned_data['description']
166        length = len(description)
167        if length > 400:
168            raise ValidationError("Descriptions are capped at 400 characters, and this one is %d characters." % (length, ))
169        return description
170
[00e16ed]171@login_required
[90afb00]172def fysm_manage(request, group, ):
173    year = datetime.date.today().year
174    group_obj = get_object_or_404(groups.models.Group, pk=group)
175
176    initial = {}
177    try:
178        fysm_obj = forms.models.FYSM.objects.get(group=group_obj, year=year, )
179    except forms.models.FYSM.DoesNotExist:
180        fysm_obj = forms.models.FYSM()
181        fysm_obj.group = group_obj
182        fysm_obj.year = year
183        initial['display_name'] = group_obj.name
184        initial['year'] = year
185        initial['website'] = group_obj.website_url
186        initial['join_url'] = group_obj.website_url
187        initial['contact_email'] = group_obj.officer_email
188
189    if request.method == 'POST': # If the form has been submitted...
190        form = FYSMRequestForm(request.POST, request.FILES, instance=fysm_obj, ) # A form bound to the POST data
191
192        if form.is_valid(): # All validation rules pass
193            request_obj = form.save()
194
[1f4ee0b]195            view_uri = request.build_absolute_uri(reverse('fysm-view', args=[year, request_obj.pk, ]))
[adfe18c]196
[90afb00]197            # Send email
[cd98e17]198            email = util.emails.email_from_template(
199                tmpl='fysm/update_email.txt',
200                context = Context({
201                    'group': group_obj,
202                    'fysm': fysm_obj,
203                    'view_uri': view_uri,
204                    'submitter': request.user,
205                    'request': request,
206                    'sender': "ASA FYSM team",
207                }),
[d199ba4]208                subject='FYSM entry for "%s" updated by "%s"' % (
[90afb00]209                    group_obj.name,
210                    request.user,
211                ),
[c49fbe2]212                to=[group_obj.officer_email, request.user.email, ],
[cd98e17]213                from_email='asa-fysm@mit.edu',
[90afb00]214            )
[cd98e17]215            email.bcc = ['asa-fysm-submissions@mit.edu']
[d199ba4]216            email.send()
[90afb00]217            return HttpResponseRedirect(reverse('fysm-thanks', args=[fysm_obj.pk],)) # Redirect after POST
218
219    else:
220        form = FYSMRequestForm(instance=fysm_obj, initial=initial, ) # An unbound form
221
222    context = {
223        'group':group_obj,
224        'fysm':fysm_obj,
225        'form':form,
[07caee0]226        'categories':forms.models.FYSMCategory.objects.all(),
[90afb00]227        'pagename':'fysm',
228    }
229    return render_to_response('fysm/submit.html', context, context_instance=RequestContext(request), )
230
231
232def fysm_thanks(request, fysm, ):
233    year = datetime.date.today().year
234    fysm_obj = get_object_or_404(forms.models.FYSM, pk=fysm)
235
236    context = {
237        'group':fysm_obj.group,
238        'fysm':fysm_obj,
239        'pagename':'fysm',
240    }
241    return render_to_response('fysm/thanks.html', context, context_instance=RequestContext(request), )
[5b834ab]242
243#####################
244# Membership update #
245#####################
246
[055a7e9]247membership_update_qs = groups.models.Group.objects.filter(group_status__slug__in=['active', 'suspended', ])
248
[bda4d86]249@login_required
250def group_membership_update_select_group(request, ):
251    cycle = forms.models.GroupConfirmationCycle.latest()
252
253    users_groups = groups.models.Group.involved_groups(request.user.username)
254    qs = membership_update_qs.filter(pk__in=users_groups)
[b1a8ea7]255
[bda4d86]256    return select_group(request=request,
257        url_name_after='membership-update-group',
258        url_args=[cycle.slug],
259        pagename='groups',
260        queryset=qs,
261        title="Submit membership update for...",
262        msg="The list below contains only groups that list you as being involved. You must be an administrator of a group to submit an update.",
263    )
264
265class Form_GroupMembershipUpdate(ModelForm):
[5b834ab]266    def __init__(self, *args, **kwargs):
267        super(Form_GroupMembershipUpdate, self).__init__(*args, **kwargs)
268        self.fields['no_hazing'].required = True
269
270    class Meta:
271        model = forms.models.GroupMembershipUpdate
272        fields = [
273            'updater_title',
274            'group_email',
275            'officer_email',
[185fde1]276            'email_preface',
[5b834ab]277            'no_hazing',
[185fde1]278            'no_discrimination',
[5b834ab]279            'membership_definition',
280            'num_undergrads',
281            'num_grads',
[ceaf3bd]282            'num_alum',
283            'num_other_affiliate',
[5b834ab]284            'num_other',
285            'membership_list',
286        ]
287
288@login_required
[bda4d86]289def group_membership_update(request, cycle_slug, pk, ):
290    cycle = get_object_or_404(forms.models.GroupConfirmationCycle, slug=cycle_slug)
291    group_obj = get_object_or_404(groups.models.Group, pk=pk)
292    if not request.user.has_perm('groups.admin_group', group_obj):
293        raise PermissionDenied
294
295    try:
296        update_obj = forms.models.GroupMembershipUpdate.objects.get(group=group_obj, cycle=cycle, )
297    except forms.models.GroupMembershipUpdate.DoesNotExist:
298        update_obj = None
[5b834ab]299
[1f4ee0b]300    confirm_uri = request.build_absolute_uri(reverse('membership-confirm'))
[6e247d3]301    submitted_uri = request.build_absolute_uri(reverse('membership-submitted'))
[5b834ab]302
[bda4d86]303    if request.method == 'POST':
[5b834ab]304        form = Form_GroupMembershipUpdate(request.POST, request.FILES, instance=update_obj) # A form bound to the POST data
305
306        if form.is_valid(): # All validation rules pass
[bda4d86]307            # Update the updater info
308            form.instance.group = group_obj
309            form.instance.cycle = cycle
310            form.instance.update_time  = datetime.datetime.now()
311            form.instance.updater_name = request.user.username
[5b834ab]312            request_obj = form.save()
313
314            # Send email
315            tmpl = get_template('membership/anti-hazing.txt')
316            ctx = Context({
317                'update': request_obj,
318                'group': group_obj,
319                'submitter': request.user,
320            })
321            body = tmpl.render(ctx)
322            email = EmailMessage(
[185fde1]323                subject='Anti-Hazing and Non-Discrimination Acknowledgement for %s' % (
[5b834ab]324                    group_obj.name,
325                ),
326                body=body,
327                from_email=request.user.email,
328                to=[request_obj.group_email, ],
329                cc=[request_obj.officer_email, ],
[5c68184]330                bcc=['asa-db-outgoing@mit.edu', ],
[5b834ab]331            )
332            email.send()
333
334            # Send email
335            tmpl = get_template('membership/submit-confirm-email.txt')
336            ctx = Context({
337                'update': request_obj,
338                'group': group_obj,
339                'submitter': request.user,
340                'confirm_uri': confirm_uri,
[6e247d3]341                'submitted_uri': submitted_uri,
[5b834ab]342            })
343            body = tmpl.render(ctx)
344            email = EmailMessage(
345                subject='ASA Membership Information for %s' % (
346                    group_obj.name,
347                ),
348                body=body,
349                from_email=request.user.email,
350                to=[request_obj.officer_email, ],
[5c68184]351                bcc=['asa-db-outgoing@mit.edu', ],
[5b834ab]352            )
353            email.send()
354
355            return HttpResponseRedirect(reverse('membership-thanks', )) # Redirect after POST
356
357    else:
[bda4d86]358        form = Form_GroupMembershipUpdate(instance=update_obj)
[5b834ab]359
360    context = {
361        'form':form,
[bda4d86]362        'group':group_obj,
[c7b6a3a]363        'cycle':cycle,
[5b834ab]364        'confirm_uri': confirm_uri,
365        'pagename':'groups',
366    }
367    return render_to_response('membership/update.html', context, context_instance=RequestContext(request), )
368
369class Form_PersonMembershipUpdate(ModelForm):
[055a7e9]370    groups = ModelMultipleChoiceField(queryset=membership_update_qs)
[5b834ab]371    class Meta:
372        model = forms.models.PersonMembershipUpdate
373        fields = [
374            'groups',
375        ]
376
377@login_required
378def person_membership_update(request, ):
379    initial = {
380    }
[c297267]381    cycle = forms.models.GroupConfirmationCycle.latest()
[ecb0997]382
383    # Initialize/find the PersonMembershipUpdate for this user
[c297267]384    try:
385        update_obj = forms.models.PersonMembershipUpdate.objects.get(
386            username=request.user.username,
387            deleted__isnull=True,
388            cycle=cycle,
389        )
390        selected_groups = update_obj.groups.all()
391    except forms.models.PersonMembershipUpdate.DoesNotExist:
392        update_obj = forms.models.PersonMembershipUpdate()
393        update_obj.update_time  = datetime.datetime.now()
394        update_obj.username = request.user.username
395        update_obj.cycle = cycle
396        selected_groups = []
397
[21c6ad4]398    # Determine whether the submitter is a student or not
[c297267]399    accounts = groups.models.AthenaMoiraAccount
400    try:
401        person = accounts.active_accounts.get(username=request.user.username)
402        if person.is_student():
403            update_obj.valid = forms.models.VALID_AUTOVALIDATED
404        else:
405            update_obj.valid = forms.models.VALID_AUTOREJECTED
406    except accounts.DoesNotExist:
407        pass
408        update_obj.valid = forms.models.VALID_AUTOREJECTED
409
[8dfd3db]410    update_obj.save()
411
[21c6ad4]412    # Find groups that list a role for the user
413    office_holders = groups.models.OfficeHolder.current_holders.filter(person=request.user.username)
414    role_groups = {}
415    for office_holder in office_holders:
416        if office_holder.group.pk not in role_groups:
417            role_groups[office_holder.group.pk] = (office_holder.group, set())
418        role_groups[office_holder.group.pk][1].add(office_holder.role.display_name)
419
420    # Find groups the user searched for
[055a7e9]421    filterset = groups.views.GroupFilter(request.GET, membership_update_qs)
[56e8cb8]422    filtered_groups = filterset.qs.all()
423    show_filtered_groups = ('search' in request.GET)
424
[c297267]425    message = ""
[56e8cb8]426    message_type = "info"
427
[11941e1]428    if update_obj.valid <= forms.models.VALID_UNSET:
429        message = "You are not listed as a student. While you're welcome to confirm your membership in groups anyway, you will not count towards the five student member requirement. If you are a student, please contact asa-exec so that we can correct our records."
430        message_type = "warn"
431
[ecb0997]432    # Handle the single group add/remove forms
433    # * removing previously confirmed groups
434    # * add/remove groups that list the user in a role
435    # * add/remove groups the user searched for
[56e8cb8]436    if request.method == 'POST' and 'add-remove' in request.POST:
437        group = groups.models.Group.objects.get(id=request.POST['group'])
438        if request.POST['action'] == 'remove':
439            if group in update_obj.groups.all():
440                update_obj.groups.remove(group)
[a50f67b]441                message = "You have successfully unconfirmed membership in %s." % (group, )
[56e8cb8]442            else:
[a50f67b]443                message = "Removal failed because you had not confirmed membership in %s." % (group, )
[56e8cb8]444                message_type = "warn"
445        elif request.POST['action'] == 'add':
446            if group in update_obj.groups.all():
[a50f67b]447                message = "Membership in %s already confirmed." % (group, )
[56e8cb8]448                message_type = "warn"
449            else:
450                update_obj.groups.add(group)
[a50f67b]451                message = "You have successfully confirmed membership in %s." % (group, )
[56e8cb8]452        else:
453            message = "Uh, somehow you tried to do something besides adding and removing..."
454            message_type = "alert"
455
[ecb0997]456    # Handle the big list of groups
457    if request.method == 'POST' and 'list' in request.POST:
458        form = Form_PersonMembershipUpdate(request.POST, request.FILES, instance=update_obj)
459        if form.is_valid():
[5b834ab]460            request_obj = form.save()
[c297267]461            message = "Update saved"
[5b834ab]462    else:
[ecb0997]463        form = Form_PersonMembershipUpdate(initial=initial, instance=update_obj, )
[4d79976]464    form.fields['groups'].widget.attrs['size'] = 20
[5b834ab]465
[ecb0997]466    # Render the page
[5b834ab]467    context = {
[21c6ad4]468        'role_groups':role_groups,
[5b834ab]469        'form':form,
[56e8cb8]470        'filter':filterset,
471        'show_filtered_groups':show_filtered_groups,
472        'filtered_groups':filtered_groups,
473        'member_groups':selected_groups,
[c297267]474        'message': message,
[56e8cb8]475        'message_type': message_type,
[5b834ab]476        'pagename':'groups',
477    }
478    return render_to_response('membership/confirm.html', context, context_instance=RequestContext(request), )
[ea42397]479
480
481class View_GroupMembershipList(ListView):
482    context_object_name = "group_list"
483    template_name = "membership/submitted.html"
484
485    def get_queryset(self):
[bda4d86]486        cycle = forms.models.GroupConfirmationCycle.latest()
[ea42397]487        group_updates = forms.models.GroupMembershipUpdate.objects.all()
[4260e2c]488        group_updates = group_updates.filter(
[bda4d86]489            cycle=cycle,
490            group__personmembershipupdate__cycle=cycle,
[4260e2c]491            group__personmembershipupdate__deleted__isnull=True,
492            group__personmembershipupdate__valid__gt=0,
493        )
494        group_updates = group_updates.annotate(num_confirms=Count('group__personmembershipupdate'))
495        #print len(list(group_updates))
496        #for query in connection.queries: print query
[ea42397]497        return group_updates
498
[0b72bfd]499
500@permission_required('groups.view_group_private_info')
501def group_confirmation_issues(request, ):
[d6f8984]502    account_numbers = ("accounts" in request.GET) and request.GET['accounts'] == "1"
503
[0b72bfd]504    active_groups = groups.models.Group.active_groups
505    group_updates = forms.models.GroupMembershipUpdate.objects.all()
506    people_confirmations = forms.models.PersonMembershipUpdate.objects.filter(
507        deleted__isnull=True,
508        valid__gt=0,
509    )
510
511    buf = StringIO.StringIO()
512    output = csv.writer(buf)
[d6f8984]513    fields = ['group_id', 'group_name', 'issue', 'num_confirm', 'officer_email', ]
514    if account_numbers: fields.append("main_account")
515    output.writerow(fields)
[0b72bfd]516
517    q_present = Q(id__in=group_updates.values('group'))
518    missing_groups = active_groups.filter(~q_present)
519    #print len(list(group_updates))
520    for group in missing_groups:
521        num_confirms = len(people_confirmations.filter(groups=group))
[d6f8984]522        fields = [
[0b72bfd]523            group.id,
524            group.name,
525            'unsubmitted',
526            num_confirms,
527            group.officer_email,
[d6f8984]528        ]
529        if account_numbers: fields.append(group.main_account_id)
530        output.writerow(fields)
[0b72bfd]531
532    for group_update in group_updates:
533        group = group_update.group
534        num_confirms = len(people_confirmations.filter(groups=group))
[de025c2]535        problems = []
536
[0b72bfd]537        if num_confirms < 5:
[de025c2]538            problems.append("confirmations")
539
540        num_students = group_update.num_undergrads + group_update.num_grads
541        num_other = group_update.num_alum + group_update.num_other_affiliate + group_update.num_other
542        if num_students < num_other:
543            problems.append("50%")
544
545        for problem in problems:
[d6f8984]546            fields = [
[0b72bfd]547                group.id,
548                group.name,
[de025c2]549                problem,
[0b72bfd]550                num_confirms,
551                group.officer_email,
[d6f8984]552            ]
553            if account_numbers: fields.append(group.main_account_id)
554            output.writerow(fields)
[0b72bfd]555
556
[360b3d4]557    return HttpResponse(buf.getvalue(), mimetype='text/csv', )
[d848b98]558
559
560
561##########
562# Midway #
563##########
564
565
566
567class MidwayMapView(DetailView):
568    context_object_name = "midway"
569    model = forms.models.Midway
570    template_name = 'midway/map.html'
571
572    def get_context_data(self, **kwargs):
573        # Call the base implementation first to get a context
574        context = super(MidwayMapView, self).get_context_data(**kwargs)
575       
576        midway = context['midway']
577        assignments = forms.models.MidwayAssignment.objects.filter(midway=midway)
578        context['assignments'] = assignments
[7d7801f]579        context['pagename'] = 'midway'
[d848b98]580
581        return context
582
583
584class MidwayAssignmentsUploadForm(Form):
585    assignments = FileField()
586
587@permission_required('forms.add_midway_assignment')
588def midway_assignment_upload(request, slug, ):
589    midway = get_object_or_404(forms.models.Midway, slug=slug, )
590
[7d7801f]591    uploaded = False
592    found = []
593    issues = collections.defaultdict(list)
594
[d848b98]595    if request.method == 'POST': # If the form has been submitted...
596        form = MidwayAssignmentsUploadForm(request.POST, request.FILES, ) # A form bound to the POST data
597
598        if form.is_valid(): # All validation rules pass
[7d7801f]599            uploaded = True
600            reader = csv.DictReader(request.FILES['assignments'])
601            for row in reader:
602                group_name = row['Group']
603                group_officers = row['officers']
604                table = row['Table']
605                issue = False
606                try:
607                    group = groups.models.Group.objects.get(name=group_name)
608                    assignment = forms.models.MidwayAssignment(
609                        midway=midway,
610                        location=table,
611                        group=group,
612                    )
613                    assignment.save()
614                    found.append(assignment)
615                    status = group.group_status.slug
616                    if status != 'active':
617                        issue = 'status=%s (added anyway)' % (status, )
618                except groups.models.Group.DoesNotExist:
619                    issue = 'unknown group (ignored)'
620                if issue:
621                    issues[issue].append((group_name, group_officers, table))
622            for issue in issues:
623                issues[issue] = sorted(issues[issue], key=lambda x: x[0])
624
[d848b98]625    else:
626        form = MidwayAssignmentsUploadForm() # An unbound form
627
628    context = {
629        'midway':midway,
630        'form':form,
[7d7801f]631        'uploaded': uploaded,
632        'found': found,
633        'issues': dict(issues),
[d848b98]634        'pagename':'midway',
635    }
636    return render_to_response('midway/upload.html', context, context_instance=RequestContext(request), )
Note: See TracBrowser for help on using the repository browser.