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
RevLine 
[aba463b]1import forms.models
[90afb00]2import groups.models
[56e8cb8]3import groups.views
[90afb00]4import settings
[cd98e17]5import util.emails
[90afb00]6
[0b72bfd]7from django.contrib.auth.decorators import user_passes_test, login_required, permission_required
[ea42397]8from django.views.generic import list_detail, ListView, DetailView
[aba463b]9from django.shortcuts import render_to_response, get_object_or_404
[90afb00]10from django.template import RequestContext
[f921734]11from django.template import Context, Template
12from django.template.loader import get_template
[0b72bfd]13from django.http import Http404, HttpResponseRedirect, HttpResponse
[90afb00]14from django.core.urlresolvers import reverse
[d199ba4]15from django.core.mail import EmailMessage, mail_admins
[90afb00]16from django.forms import Form
17from django.forms import ModelForm
[b1a8ea7]18from django.forms import ModelChoiceField, ModelMultipleChoiceField
[3496370]19from django.forms import ValidationError
[4260e2c]20from django.db import connection
[ea42397]21from django.db.models import Q, Count
[aba463b]22
[0b72bfd]23import csv
[aba463b]24import datetime
[0b72bfd]25import StringIO
[aba463b]26
[90afb00]27#################
28# GENERIC VIEWS #
29#################
30
31class SelectGroupForm(Form):
32    group = ModelChoiceField(queryset=groups.models.Group.objects.all())
[2f7114b]33    def __init__(self, *args, **kwargs):
34        queryset = None
35        if 'queryset' in kwargs:
36            queryset = kwargs['queryset']
37            del kwargs['queryset']
[f921734]38        super(SelectGroupForm, self).__init__(*args, **kwargs)
39        if queryset is not None:
40            self.fields["group"].queryset = queryset
[90afb00]41
[f921734]42def select_group(request, url_name_after, pagename='homepage', queryset=None, ):
[90afb00]43    if request.method == 'POST': # If the form has been submitted...
[f921734]44        # A form bound to the POST data
45        form = SelectGroupForm(request.POST, queryset=queryset, )
[90afb00]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:
[f921734]50        form = SelectGroupForm(queryset=queryset, ) # An unbound form
[90afb00]51
52    context = {
53        'form':form,
[0b488d4]54        'pagename':pagename,
[90afb00]55    }
56    return render_to_response('forms/select.html', context, context_instance=RequestContext(request), )
57
58#############################
59# FIRST-YEAR SUMMER MAILING #
60#############################
61
[00e16ed]62@login_required
[97399af]63def fysm_by_years(request, year, category, ):
[aba463b]64    if year is None: year = datetime.date.today().year
65    queryset = forms.models.FYSM.objects.filter(year=year).order_by('group__name')
[dafa3c8]66    category_obj = None
[a10dd4b]67    category_name = 'main'
[dafa3c8]68    if category != None:
[c27da9e]69        category_obj = get_object_or_404(forms.models.FYSMCategory, slug=category)
[a10dd4b]70        category_name = category_obj.name
[c27da9e]71        queryset = queryset.filter(categories=category_obj)
[a10dd4b]72    forms.models.FYSMView.record_metric(request=request, fysm=None, year=year, page=category_name, )
[c27da9e]73    categories = forms.models.FYSMCategory.objects.all()
[aba463b]74    return list_detail.object_list(
75        request,
76        queryset=queryset,
[90afb00]77        template_name="fysm/fysm_listing.html",
[aba463b]78        template_object_name="fysm",
79        extra_context={
80            "year": year,
81            "pagename": "fysm",
[dafa3c8]82            "category": category_obj,
[189506e]83            "categories": categories,
[aba463b]84        }
85    )
[90afb00]86
[00e16ed]87@login_required
[aaa8e04]88def fysm_view(request, year, submission, ):
[ae881e5]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
[a10dd4b]99    forms.models.FYSMView.record_metric(request=request, fysm=submit_obj, year=year, page="detail", )
[aaa8e04]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",
[ae881e5]109            "prev": prev,
110            "next": next,
[aaa8e04]111        },
112    )
113
[f462be6]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")
[a10dd4b]124    forms.models.FYSMView.record_metric(request=request, fysm=submit_obj, year=year, page=link_type, )
[f462be6]125    return HttpResponseRedirect(url)
126
[f921734]127def select_group_fysm(request, ):
[2c0eaa1]128    qobj = Q(activity_category__isnull = True) | ~(Q(activity_category__name='Dorm') | Q(activity_category__name='FSILG'))
[d3167b9]129    queryset = groups.models.Group.active_groups.filter(qobj)
[f921734]130    return select_group(
131        request,
132        url_name_after='fysm-manage',
133        pagename='fysm',
134        queryset=queryset,
135    )
136
[90afb00]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',
[3400018]147            'slide',
[57f8ffa]148            'tags',
[c27da9e]149            'categories',
[90afb00]150        )
151
[3496370]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
[cbdbd1f]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
[00e16ed]165@login_required
[90afb00]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
[adfe18c]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
[90afb00]194            # Send email
[cd98e17]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                }),
[d199ba4]205                subject='FYSM entry for "%s" updated by "%s"' % (
[90afb00]206                    group_obj.name,
207                    request.user,
208                ),
[c49fbe2]209                to=[group_obj.officer_email, request.user.email, ],
[cd98e17]210                from_email='asa-fysm@mit.edu',
[90afb00]211            )
[cd98e17]212            email.bcc = ['asa-fysm-submissions@mit.edu']
[d199ba4]213            email.send()
[90afb00]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,
[07caee0]223        'categories':forms.models.FYSMCategory.objects.all(),
[90afb00]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), )
[5b834ab]239
240#####################
241# Membership update #
242#####################
243
[055a7e9]244membership_update_qs = groups.models.Group.objects.filter(group_status__slug__in=['active', 'suspended', ])
245
[5b834ab]246class Form_GroupMembershipUpdate(ModelForm):
[055a7e9]247    group = ModelChoiceField(queryset=membership_update_qs)
[b1a8ea7]248
[5b834ab]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',
[185fde1]260            'email_preface',
[5b834ab]261            'no_hazing',
[185fde1]262            'no_discrimination',
[5b834ab]263            'membership_definition',
264            'num_undergrads',
265            'num_grads',
[ceaf3bd]266            'num_alum',
267            'num_other_affiliate',
[5b834ab]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(
[185fde1]303                subject='Anti-Hazing and Non-Discrimination Acknowledgement for %s' % (
[5b834ab]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, ],
[5c68184]310                bcc=['asa-db-outgoing@mit.edu', ],
[5b834ab]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, ],
[5c68184]330                bcc=['asa-db-outgoing@mit.edu', ],
[5b834ab]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):
[055a7e9]347    groups = ModelMultipleChoiceField(queryset=membership_update_qs)
[5b834ab]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    }
[c297267]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
[8dfd3db]387    update_obj.save()
388
[055a7e9]389    filterset = groups.views.GroupFilter(request.GET, membership_update_qs)
[56e8cb8]390    filtered_groups = filterset.qs.all()
391    show_filtered_groups = ('search' in request.GET)
392
[c297267]393    message = ""
[56e8cb8]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...
[5b834ab]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()
[c297267]421            message = "Update saved"
[5b834ab]422
423    else:
[c297267]424        form = Form_PersonMembershipUpdate(initial=initial, instance=update_obj, ) # An unbound form
[5b834ab]425
426    context = {
427        'form':form,
[56e8cb8]428        'filter':filterset,
429        'show_filtered_groups':show_filtered_groups,
430        'filtered_groups':filtered_groups,
431        'member_groups':selected_groups,
[c297267]432        'message': message,
[56e8cb8]433        'message_type': message_type,
[5b834ab]434        'pagename':'groups',
435    }
436    return render_to_response('membership/confirm.html', context, context_instance=RequestContext(request), )
[ea42397]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()
[4260e2c]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
[ea42397]452        return group_updates
453
[0b72bfd]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.