source: asadb/forms/views.py @ ef00d33

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

Remove some dead code

Membership confirmations don't use the year...

  • Property mode set to 100644
File size: 18.9 KB
Line 
1import forms.models
2import groups.models
3import groups.views
4import settings
5import util.emails
6
7from django.contrib.auth.decorators import user_passes_test, login_required, permission_required
8from django.views.generic import list_detail, ListView, DetailView
9from django.shortcuts import render_to_response, get_object_or_404
10from django.template import RequestContext
11from django.template import Context, Template
12from django.template.loader import get_template
13from django.http import Http404, HttpResponseRedirect, HttpResponse
14from django.core.urlresolvers import reverse
15from django.core.mail import EmailMessage, mail_admins
16from django.forms import Form
17from django.forms import ModelForm
18from django.forms import ModelChoiceField, ModelMultipleChoiceField
19from django.forms import ValidationError
20from django.db import connection
21from django.db.models import Q, Count
22
23import csv
24import datetime
25import StringIO
26
27#################
28# GENERIC VIEWS #
29#################
30
31class SelectGroupForm(Form):
32    group = ModelChoiceField(queryset=groups.models.Group.objects.all())
33    def __init__(self, *args, **kwargs):
34        queryset = None
35        if 'queryset' in kwargs:
36            queryset = kwargs['queryset']
37            del kwargs['queryset']
38        super(SelectGroupForm, self).__init__(*args, **kwargs)
39        if queryset is not None:
40            self.fields["group"].queryset = queryset
41
42def select_group(request, url_name_after, pagename='homepage', queryset=None, ):
43    if request.method == 'POST': # If the form has been submitted...
44        # A form bound to the POST data
45        form = SelectGroupForm(request.POST, queryset=queryset, )
46        if form.is_valid(): # All validation rules pass
47            group = form.cleaned_data['group'].id
48            return HttpResponseRedirect(reverse(url_name_after, args=[group],)) # Redirect after POST
49    else:
50        form = SelectGroupForm(queryset=queryset, ) # An unbound form
51
52    context = {
53        'form':form,
54        'pagename':pagename,
55    }
56    return render_to_response('forms/select.html', context, context_instance=RequestContext(request), )
57
58#############################
59# FIRST-YEAR SUMMER MAILING #
60#############################
61
62@login_required
63def fysm_by_years(request, year, category, ):
64    if year is None: year = datetime.date.today().year
65    queryset = forms.models.FYSM.objects.filter(year=year).order_by('group__name')
66    category_obj = None
67    category_name = 'main'
68    if category != None:
69        category_obj = get_object_or_404(forms.models.FYSMCategory, slug=category)
70        category_name = category_obj.name
71        queryset = queryset.filter(categories=category_obj)
72    forms.models.FYSMView.record_metric(request=request, fysm=None, year=year, page=category_name, )
73    categories = forms.models.FYSMCategory.objects.all()
74    return list_detail.object_list(
75        request,
76        queryset=queryset,
77        template_name="fysm/fysm_listing.html",
78        template_object_name="fysm",
79        extra_context={
80            "year": year,
81            "pagename": "fysm",
82            "category": category_obj,
83            "categories": categories,
84        }
85    )
86
87@login_required
88def fysm_view(request, year, submission, ):
89    submit_obj = get_object_or_404(forms.models.FYSM, pk=submission,)
90    all = forms.models.FYSM.objects.only("id", "display_name", )
91    try:
92        prev = all.filter(display_name__lt=submit_obj.display_name).order_by("-display_name")[0]
93    except IndexError:
94        prev = None
95    try:
96        next = all.filter(display_name__gt=submit_obj.display_name).order_by("display_name")[0]
97    except IndexError:
98        next = None
99    forms.models.FYSMView.record_metric(request=request, fysm=submit_obj, year=year, page="detail", )
100    return list_detail.object_detail(
101        request,
102        forms.models.FYSM.objects,
103        object_id=submission,
104        template_name="fysm/fysm_detail.html",
105        template_object_name="fysm",
106        extra_context={
107            "year": year,
108            "pagename": "fysm",
109            "prev": prev,
110            "next": next,
111        },
112    )
113
114def fysm_link(request, year, link_type, submission, ):
115    submit_obj = get_object_or_404(forms.models.FYSM, pk=submission,)
116    if submit_obj.year != int(year):
117        raise Http404("Year mismatch: fysm.year='%s', request's year='%s'" % (submit_obj.year, year, ))
118    if link_type == 'join':
119        url = submit_obj.join_url
120    elif link_type == 'website':
121        url = submit_obj.website
122    else:
123        raise Http404("Unknown link type")
124    forms.models.FYSMView.record_metric(request=request, fysm=submit_obj, year=year, page=link_type, )
125    return HttpResponseRedirect(url)
126
127def select_group_fysm(request, ):
128    qobj = Q(activity_category__isnull = True) | ~(Q(activity_category__name='Dorm') | Q(activity_category__name='FSILG'))
129    queryset = groups.models.Group.active_groups.filter(qobj)
130    return select_group(
131        request,
132        url_name_after='fysm-manage',
133        pagename='fysm',
134        queryset=queryset,
135    )
136
137class FYSMRequestForm(ModelForm):
138    class Meta:
139        model = forms.models.FYSM
140        fields = (
141            'display_name',
142            'website',
143            'join_url',
144            'contact_email',
145            'description',
146            'logo',
147            'slide',
148            'tags',
149            'categories',
150        )
151
152    def clean_display_name(self, ):
153        name = self.cleaned_data['display_name']
154        if ',' in name:
155            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.""")
156        return name
157
158    def clean_description(self, ):
159        description = self.cleaned_data['description']
160        length = len(description)
161        if length > 400:
162            raise ValidationError("Descriptions are capped at 400 characters, and this one is %d characters." % (length, ))
163        return description
164
165@login_required
166def fysm_manage(request, group, ):
167    year = datetime.date.today().year
168    group_obj = get_object_or_404(groups.models.Group, pk=group)
169
170    initial = {}
171    try:
172        fysm_obj = forms.models.FYSM.objects.get(group=group_obj, year=year, )
173    except forms.models.FYSM.DoesNotExist:
174        fysm_obj = forms.models.FYSM()
175        fysm_obj.group = group_obj
176        fysm_obj.year = year
177        initial['display_name'] = group_obj.name
178        initial['year'] = year
179        initial['website'] = group_obj.website_url
180        initial['join_url'] = group_obj.website_url
181        initial['contact_email'] = group_obj.officer_email
182
183    if request.method == 'POST': # If the form has been submitted...
184        form = FYSMRequestForm(request.POST, request.FILES, instance=fysm_obj, ) # A form bound to the POST data
185
186        if form.is_valid(): # All validation rules pass
187            request_obj = form.save()
188
189            view_path = reverse('fysm-view', args=[year, request_obj.pk, ])
190            view_uri = '%s://%s%s' % (request.is_secure() and 'https' or 'http',
191                 request.get_host(), view_path)
192
193            # Send email
194            email = util.emails.email_from_template(
195                tmpl='fysm/update_email.txt',
196                context = Context({
197                    'group': group_obj,
198                    'fysm': fysm_obj,
199                    'view_uri': view_uri,
200                    'submitter': request.user,
201                    'request': request,
202                    'sender': "ASA FYSM team",
203                }),
204                subject='FYSM entry for "%s" updated by "%s"' % (
205                    group_obj.name,
206                    request.user,
207                ),
208                to=[group_obj.officer_email, request.user.email, ],
209                from_email='asa-fysm@mit.edu',
210            )
211            email.bcc = ['asa-fysm-submissions@mit.edu']
212            email.send()
213            return HttpResponseRedirect(reverse('fysm-thanks', args=[fysm_obj.pk],)) # Redirect after POST
214
215    else:
216        form = FYSMRequestForm(instance=fysm_obj, initial=initial, ) # An unbound form
217
218    context = {
219        'group':group_obj,
220        'fysm':fysm_obj,
221        'form':form,
222        'categories':forms.models.FYSMCategory.objects.all(),
223        'pagename':'fysm',
224    }
225    return render_to_response('fysm/submit.html', context, context_instance=RequestContext(request), )
226
227
228def fysm_thanks(request, fysm, ):
229    year = datetime.date.today().year
230    fysm_obj = get_object_or_404(forms.models.FYSM, pk=fysm)
231
232    context = {
233        'group':fysm_obj.group,
234        'fysm':fysm_obj,
235        'pagename':'fysm',
236    }
237    return render_to_response('fysm/thanks.html', context, context_instance=RequestContext(request), )
238
239#####################
240# Membership update #
241#####################
242
243membership_update_qs = groups.models.Group.objects.filter(group_status__slug__in=['active', 'suspended', ])
244
245class Form_GroupMembershipUpdate(ModelForm):
246    group = ModelChoiceField(queryset=membership_update_qs)
247
248    def __init__(self, *args, **kwargs):
249        super(Form_GroupMembershipUpdate, self).__init__(*args, **kwargs)
250        self.fields['no_hazing'].required = True
251
252    class Meta:
253        model = forms.models.GroupMembershipUpdate
254        fields = [
255            'group',
256            'updater_title',
257            'group_email',
258            'officer_email',
259            'email_preface',
260            'no_hazing',
261            'no_discrimination',
262            'membership_definition',
263            'num_undergrads',
264            'num_grads',
265            'num_alum',
266            'num_other_affiliate',
267            'num_other',
268            'membership_list',
269        ]
270
271@login_required
272def group_membership_update(request, ):
273    initial = {
274    }
275    update_obj = forms.models.GroupMembershipUpdate()
276    update_obj.update_time  = datetime.datetime.now()
277    update_obj.updater_name = request.user.username
278
279    confirm_path = reverse('membership-confirm', )
280    confirm_uri = '%s://%s%s' % (request.is_secure() and 'https' or 'http',
281         request.get_host(), confirm_path)
282
283    if request.method == 'POST': # If the form has been submitted...
284        form = Form_GroupMembershipUpdate(request.POST, request.FILES, instance=update_obj) # A form bound to the POST data
285
286        if form.is_valid(): # All validation rules pass
287            request_obj = form.save()
288            group_obj = request_obj.group
289
290
291            # Send email
292            tmpl = get_template('membership/anti-hazing.txt')
293            ctx = Context({
294                'update': request_obj,
295                'group': group_obj,
296                'submitter': request.user,
297            })
298            body = tmpl.render(ctx)
299            email = EmailMessage(
300                subject='Anti-Hazing and Non-Discrimination Acknowledgement for %s' % (
301                    group_obj.name,
302                ),
303                body=body,
304                from_email=request.user.email,
305                to=[request_obj.group_email, ],
306                cc=[request_obj.officer_email, ],
307                bcc=['asa-db-outgoing@mit.edu', ],
308            )
309            email.send()
310
311            # Send email
312            tmpl = get_template('membership/submit-confirm-email.txt')
313            ctx = Context({
314                'update': request_obj,
315                'group': group_obj,
316                'submitter': request.user,
317                'confirm_uri': confirm_uri,
318            })
319            body = tmpl.render(ctx)
320            email = EmailMessage(
321                subject='ASA Membership Information for %s' % (
322                    group_obj.name,
323                ),
324                body=body,
325                from_email=request.user.email,
326                to=[request_obj.officer_email, ],
327                bcc=['asa-db-outgoing@mit.edu', ],
328            )
329            email.send()
330
331            return HttpResponseRedirect(reverse('membership-thanks', )) # Redirect after POST
332
333    else:
334        form = Form_GroupMembershipUpdate(initial=initial, ) # An unbound form
335
336    context = {
337        'form':form,
338        'confirm_uri': confirm_uri,
339        'pagename':'groups',
340    }
341    return render_to_response('membership/update.html', context, context_instance=RequestContext(request), )
342
343class Form_PersonMembershipUpdate(ModelForm):
344    groups = ModelMultipleChoiceField(queryset=membership_update_qs)
345    class Meta:
346        model = forms.models.PersonMembershipUpdate
347        fields = [
348            'groups',
349        ]
350
351@login_required
352def person_membership_update(request, ):
353    initial = {
354    }
355    cycle = forms.models.GroupConfirmationCycle.latest()
356
357    # Initialize/find the PersonMembershipUpdate for this user
358    try:
359        update_obj = forms.models.PersonMembershipUpdate.objects.get(
360            username=request.user.username,
361            deleted__isnull=True,
362            cycle=cycle,
363        )
364        selected_groups = update_obj.groups.all()
365    except forms.models.PersonMembershipUpdate.DoesNotExist:
366        update_obj = forms.models.PersonMembershipUpdate()
367        update_obj.update_time  = datetime.datetime.now()
368        update_obj.username = request.user.username
369        update_obj.cycle = cycle
370        selected_groups = []
371
372    # Determine whether the submitter is a student or not
373    accounts = groups.models.AthenaMoiraAccount
374    try:
375        person = accounts.active_accounts.get(username=request.user.username)
376        if person.is_student():
377            update_obj.valid = forms.models.VALID_AUTOVALIDATED
378        else:
379            update_obj.valid = forms.models.VALID_AUTOREJECTED
380    except accounts.DoesNotExist:
381        pass
382        update_obj.valid = forms.models.VALID_AUTOREJECTED
383
384    update_obj.save()
385
386    # Find groups that list a role for the user
387    office_holders = groups.models.OfficeHolder.current_holders.filter(person=request.user.username)
388    role_groups = {}
389    for office_holder in office_holders:
390        if office_holder.group.pk not in role_groups:
391            role_groups[office_holder.group.pk] = (office_holder.group, set())
392        role_groups[office_holder.group.pk][1].add(office_holder.role.display_name)
393
394    # Find groups the user searched for
395    filterset = groups.views.GroupFilter(request.GET, membership_update_qs)
396    filtered_groups = filterset.qs.all()
397    show_filtered_groups = ('search' in request.GET)
398
399    message = ""
400    message_type = "info"
401
402    if update_obj.valid <= forms.models.VALID_UNSET:
403        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."
404        message_type = "warn"
405
406    # Handle the single group add/remove forms
407    # * removing previously confirmed groups
408    # * add/remove groups that list the user in a role
409    # * add/remove groups the user searched for
410    if request.method == 'POST' and 'add-remove' in request.POST:
411        group = groups.models.Group.objects.get(id=request.POST['group'])
412        if request.POST['action'] == 'remove':
413            if group in update_obj.groups.all():
414                update_obj.groups.remove(group)
415                message = "You have successfully unconfirmed membership in %s." % (group, )
416            else:
417                message = "Removal failed because you had not confirmed membership in %s." % (group, )
418                message_type = "warn"
419        elif request.POST['action'] == 'add':
420            if group in update_obj.groups.all():
421                message = "Membership in %s already confirmed." % (group, )
422                message_type = "warn"
423            else:
424                update_obj.groups.add(group)
425                message = "You have successfully confirmed membership in %s." % (group, )
426        else:
427            message = "Uh, somehow you tried to do something besides adding and removing..."
428            message_type = "alert"
429
430    # Handle the big list of groups
431    if request.method == 'POST' and 'list' in request.POST:
432        form = Form_PersonMembershipUpdate(request.POST, request.FILES, instance=update_obj)
433        if form.is_valid():
434            request_obj = form.save()
435            message = "Update saved"
436    else:
437        form = Form_PersonMembershipUpdate(initial=initial, instance=update_obj, )
438
439    # Render the page
440    context = {
441        'role_groups':role_groups,
442        'form':form,
443        'filter':filterset,
444        'show_filtered_groups':show_filtered_groups,
445        'filtered_groups':filtered_groups,
446        'member_groups':selected_groups,
447        'message': message,
448        'message_type': message_type,
449        'pagename':'groups',
450    }
451    return render_to_response('membership/confirm.html', context, context_instance=RequestContext(request), )
452
453
454class View_GroupMembershipList(ListView):
455    context_object_name = "group_list"
456    template_name = "membership/submitted.html"
457
458    def get_queryset(self):
459        group_updates = forms.models.GroupMembershipUpdate.objects.all()
460        group_updates = group_updates.filter(
461            group__personmembershipupdate__deleted__isnull=True,
462            group__personmembershipupdate__valid__gt=0,
463        )
464        group_updates = group_updates.annotate(num_confirms=Count('group__personmembershipupdate'))
465        #print len(list(group_updates))
466        #for query in connection.queries: print query
467        return group_updates
468
469
470@permission_required('groups.view_group_private_info')
471def group_confirmation_issues(request, ):
472    active_groups = groups.models.Group.active_groups
473    group_updates = forms.models.GroupMembershipUpdate.objects.all()
474    people_confirmations = forms.models.PersonMembershipUpdate.objects.filter(
475        deleted__isnull=True,
476        valid__gt=0,
477    )
478
479    buf = StringIO.StringIO()
480    output = csv.writer(buf)
481    output.writerow(['group_id', 'group_name', 'issue', 'num_confirm', 'officer_email', ])
482
483    q_present = Q(id__in=group_updates.values('group'))
484    missing_groups = active_groups.filter(~q_present)
485    #print len(list(group_updates))
486    for group in missing_groups:
487        num_confirms = len(people_confirmations.filter(groups=group))
488        output.writerow([
489            group.id,
490            group.name,
491            'unsubmitted',
492            num_confirms,
493            group.officer_email,
494        ])
495
496    for group_update in group_updates:
497        group = group_update.group
498        num_confirms = len(people_confirmations.filter(groups=group))
499        problems = []
500
501        if num_confirms < 5:
502            problems.append("confirmations")
503
504        num_students = group_update.num_undergrads + group_update.num_grads
505        num_other = group_update.num_alum + group_update.num_other_affiliate + group_update.num_other
506        if num_students < num_other:
507            problems.append("50%")
508
509        for problem in problems:
510            output.writerow([
511                group.id,
512                group.name,
513                problem,
514                num_confirms,
515                group.officer_email,
516            ])
517
518
519    return HttpResponse(buf.getvalue(), mimetype='text/csv', )
Note: See TracBrowser for help on using the repository browser.