source: asadb/forms/views.py @ 68c93e8

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

Cap FYSM descriptions at 400 characters (ASA-#129)

  • Property mode set to 100644
File size: 17.6 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        print "Successfully found", fysm_obj.__dict__
174    except forms.models.FYSM.DoesNotExist:
175        fysm_obj = forms.models.FYSM()
176        fysm_obj.group = group_obj
177        fysm_obj.year = year
178        initial['display_name'] = group_obj.name
179        initial['year'] = year
180        initial['website'] = group_obj.website_url
181        initial['join_url'] = group_obj.website_url
182        initial['contact_email'] = group_obj.officer_email
183
184    if request.method == 'POST': # If the form has been submitted...
185        form = FYSMRequestForm(request.POST, request.FILES, instance=fysm_obj, ) # A form bound to the POST data
186
187        if form.is_valid(): # All validation rules pass
188            request_obj = form.save()
189
190            view_path = reverse('fysm-view', args=[year, request_obj.pk, ])
191            view_uri = '%s://%s%s' % (request.is_secure() and 'https' or 'http',
192                 request.get_host(), view_path)
193
194            # Send email
195            email = util.emails.email_from_template(
196                tmpl='fysm/update_email.txt',
197                context = Context({
198                    'group': group_obj,
199                    'fysm': fysm_obj,
200                    'view_uri': view_uri,
201                    'submitter': request.user,
202                    'request': request,
203                    'sender': "ASA FYSM team",
204                }),
205                subject='FYSM entry for "%s" updated by "%s"' % (
206                    group_obj.name,
207                    request.user,
208                ),
209                to=[group_obj.officer_email, request.user.email, ],
210                from_email='asa-fysm@mit.edu',
211            )
212            email.bcc = ['asa-fysm-submissions@mit.edu']
213            email.send()
214            return HttpResponseRedirect(reverse('fysm-thanks', args=[fysm_obj.pk],)) # Redirect after POST
215
216    else:
217        form = FYSMRequestForm(instance=fysm_obj, initial=initial, ) # An unbound form
218
219    context = {
220        'group':group_obj,
221        'fysm':fysm_obj,
222        'form':form,
223        'categories':forms.models.FYSMCategory.objects.all(),
224        'pagename':'fysm',
225    }
226    return render_to_response('fysm/submit.html', context, context_instance=RequestContext(request), )
227
228
229def fysm_thanks(request, fysm, ):
230    year = datetime.date.today().year
231    fysm_obj = get_object_or_404(forms.models.FYSM, pk=fysm)
232
233    context = {
234        'group':fysm_obj.group,
235        'fysm':fysm_obj,
236        'pagename':'fysm',
237    }
238    return render_to_response('fysm/thanks.html', context, context_instance=RequestContext(request), )
239
240#####################
241# Membership update #
242#####################
243
244membership_update_qs = groups.models.Group.objects.filter(group_status__slug__in=['active', 'suspended', ])
245
246class Form_GroupMembershipUpdate(ModelForm):
247    group = ModelChoiceField(queryset=membership_update_qs)
248
249    def __init__(self, *args, **kwargs):
250        super(Form_GroupMembershipUpdate, self).__init__(*args, **kwargs)
251        self.fields['no_hazing'].required = True
252
253    class Meta:
254        model = forms.models.GroupMembershipUpdate
255        fields = [
256            'group',
257            'updater_title',
258            'group_email',
259            'officer_email',
260            'email_preface',
261            'no_hazing',
262            'no_discrimination',
263            'membership_definition',
264            'num_undergrads',
265            'num_grads',
266            'num_alum',
267            'num_other_affiliate',
268            'num_other',
269            'membership_list',
270        ]
271
272@login_required
273def group_membership_update(request, ):
274    year = datetime.date.today().year
275
276    initial = {
277    }
278    update_obj = forms.models.GroupMembershipUpdate()
279    update_obj.update_time  = datetime.datetime.now()
280    update_obj.updater_name = request.user.username
281
282    confirm_path = reverse('membership-confirm', )
283    confirm_uri = '%s://%s%s' % (request.is_secure() and 'https' or 'http',
284         request.get_host(), confirm_path)
285
286    if request.method == 'POST': # If the form has been submitted...
287        form = Form_GroupMembershipUpdate(request.POST, request.FILES, instance=update_obj) # A form bound to the POST data
288
289        if form.is_valid(): # All validation rules pass
290            request_obj = form.save()
291            group_obj = request_obj.group
292
293
294            # Send email
295            tmpl = get_template('membership/anti-hazing.txt')
296            ctx = Context({
297                'update': request_obj,
298                'group': group_obj,
299                'submitter': request.user,
300            })
301            body = tmpl.render(ctx)
302            email = EmailMessage(
303                subject='Anti-Hazing and Non-Discrimination Acknowledgement for %s' % (
304                    group_obj.name,
305                ),
306                body=body,
307                from_email=request.user.email,
308                to=[request_obj.group_email, ],
309                cc=[request_obj.officer_email, ],
310                bcc=['asa-db-outgoing@mit.edu', ],
311            )
312            email.send()
313
314            # Send email
315            tmpl = get_template('membership/submit-confirm-email.txt')
316            ctx = Context({
317                'update': request_obj,
318                'group': group_obj,
319                'submitter': request.user,
320                'confirm_uri': confirm_uri,
321            })
322            body = tmpl.render(ctx)
323            email = EmailMessage(
324                subject='ASA Membership Information for %s' % (
325                    group_obj.name,
326                ),
327                body=body,
328                from_email=request.user.email,
329                to=[request_obj.officer_email, ],
330                bcc=['asa-db-outgoing@mit.edu', ],
331            )
332            email.send()
333
334            return HttpResponseRedirect(reverse('membership-thanks', )) # Redirect after POST
335
336    else:
337        form = Form_GroupMembershipUpdate(initial=initial, ) # An unbound form
338
339    context = {
340        'form':form,
341        'confirm_uri': confirm_uri,
342        'pagename':'groups',
343    }
344    return render_to_response('membership/update.html', context, context_instance=RequestContext(request), )
345
346class Form_PersonMembershipUpdate(ModelForm):
347    groups = ModelMultipleChoiceField(queryset=membership_update_qs)
348    class Meta:
349        model = forms.models.PersonMembershipUpdate
350        fields = [
351            'groups',
352        ]
353
354@login_required
355def person_membership_update(request, ):
356    year = datetime.date.today().year
357
358    initial = {
359    }
360    cycle = forms.models.GroupConfirmationCycle.latest()
361    try:
362        update_obj = forms.models.PersonMembershipUpdate.objects.get(
363            username=request.user.username,
364            deleted__isnull=True,
365            cycle=cycle,
366        )
367        selected_groups = update_obj.groups.all()
368        print "Got update"
369    except forms.models.PersonMembershipUpdate.DoesNotExist:
370        update_obj = forms.models.PersonMembershipUpdate()
371        update_obj.update_time  = datetime.datetime.now()
372        update_obj.username = request.user.username
373        update_obj.cycle = cycle
374        selected_groups = []
375
376    accounts = groups.models.AthenaMoiraAccount
377    try:
378        person = accounts.active_accounts.get(username=request.user.username)
379        if person.is_student():
380            update_obj.valid = forms.models.VALID_AUTOVALIDATED
381        else:
382            update_obj.valid = forms.models.VALID_AUTOREJECTED
383    except accounts.DoesNotExist:
384        pass
385        update_obj.valid = forms.models.VALID_AUTOREJECTED
386
387    update_obj.save()
388
389    filterset = groups.views.GroupFilter(request.GET, membership_update_qs)
390    filtered_groups = filterset.qs.all()
391    show_filtered_groups = ('search' in request.GET)
392
393    message = ""
394    message_type = "info"
395
396    if request.method == 'POST' and 'add-remove' in request.POST:
397        group = groups.models.Group.objects.get(id=request.POST['group'])
398        if request.POST['action'] == 'remove':
399            if group in update_obj.groups.all():
400                update_obj.groups.remove(group)
401                message = "You have been successfully removed from %s." % (group, )
402            else:
403                message = "Sorry, but you're not in %s." % (group, )
404                message_type = "warn"
405        elif request.POST['action'] == 'add':
406            if group in update_obj.groups.all():
407                message = "Sorry, but you're already in %s." % (group, )
408                message_type = "warn"
409            else:
410                update_obj.groups.add(group)
411                message = "You have been successfully added to %s." % (group, )
412        else:
413            message = "Uh, somehow you tried to do something besides adding and removing..."
414            message_type = "alert"
415
416    if request.method == 'POST' and 'list' in request.POST: # If the form has been submitted...
417        form = Form_PersonMembershipUpdate(request.POST, request.FILES, instance=update_obj) # A form bound to the POST data
418
419        if form.is_valid(): # All validation rules pass
420            request_obj = form.save()
421            message = "Update saved"
422
423    else:
424        form = Form_PersonMembershipUpdate(initial=initial, instance=update_obj, ) # An unbound form
425
426    context = {
427        'form':form,
428        'filter':filterset,
429        'show_filtered_groups':show_filtered_groups,
430        'filtered_groups':filtered_groups,
431        'member_groups':selected_groups,
432        'message': message,
433        'message_type': message_type,
434        'pagename':'groups',
435    }
436    return render_to_response('membership/confirm.html', context, context_instance=RequestContext(request), )
437
438
439class View_GroupMembershipList(ListView):
440    context_object_name = "group_list"
441    template_name = "membership/submitted.html"
442
443    def get_queryset(self):
444        group_updates = forms.models.GroupMembershipUpdate.objects.all()
445        group_updates = group_updates.filter(
446            group__personmembershipupdate__deleted__isnull=True,
447            group__personmembershipupdate__valid__gt=0,
448        )
449        group_updates = group_updates.annotate(num_confirms=Count('group__personmembershipupdate'))
450        #print len(list(group_updates))
451        #for query in connection.queries: print query
452        return group_updates
453
454
455@permission_required('groups.view_group_private_info')
456def group_confirmation_issues(request, ):
457    active_groups = groups.models.Group.active_groups
458    group_updates = forms.models.GroupMembershipUpdate.objects.all()
459    people_confirmations = forms.models.PersonMembershipUpdate.objects.filter(
460        deleted__isnull=True,
461        valid__gt=0,
462    )
463
464    buf = StringIO.StringIO()
465    output = csv.writer(buf)
466    output.writerow(['group_id', 'group_name', 'issue', 'num_confirm', 'officer_email', ])
467
468    q_present = Q(id__in=group_updates.values('group'))
469    missing_groups = active_groups.filter(~q_present)
470    #print len(list(group_updates))
471    for group in missing_groups:
472        num_confirms = len(people_confirmations.filter(groups=group))
473        output.writerow([
474            group.id,
475            group.name,
476            'unsubmitted',
477            num_confirms,
478            group.officer_email,
479        ])
480
481    for group_update in group_updates:
482        group = group_update.group
483        num_confirms = len(people_confirmations.filter(groups=group))
484        if num_confirms < 5:
485            output.writerow([
486                group.id,
487                group.name,
488                'confirmations',
489                num_confirms,
490                group.officer_email,
491            ])
492
493
494    return HttpResponse(buf.getvalue(), mimetype='text/plain', )
Note: See TracBrowser for help on using the repository browser.