Changeset 0ac15a1 for asadb/groups
- Timestamp:
- Apr 5, 2012, 1:12:37 AM (14 years ago)
- Branches:
- master, space-access, stable, stage
- Children:
- a03cb61
- Parents:
- ffecc7f (diff), a9a8f3d (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent. - git-author:
- Alex Dehnert <adehnert@…> (04/05/12 01:12:37)
- git-committer:
- Alex Dehnert <adehnert@…> (04/05/12 01:12:37)
- Location:
- asadb/groups
- Files:
-
- 1 added
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
asadb/groups/urls.py
r8708a86 r0ac15a1 2 2 3 3 import groups.views 4 import space.views 4 5 5 6 group_patterns = patterns('', … … 8 9 url(r'^edit/officers$', groups.views.manage_officers, name='group-manage-officers', ), 9 10 url(r'^history/$', groups.views.GroupHistoryView.as_view(), name='group-manage-history', ), 11 url(r'^space/$', space.views.manage_access, name='group-space-access', ), 10 12 ) 11 13 -
asadb/groups/models.py
rfd5cc07 r4325823 97 97 def __str__(self, ): 98 98 return self.name 99 100 @classmethod 101 def reporting_prefetch(cls, ): 102 return set(['activity_category', 'group_class', 'group_status', 'group_funding']) 103 104 @classmethod 105 def reporting_fields(cls, ): 106 fields = cls._meta.fields 107 return [(f.name, f.verbose_name) for f in fields] 99 108 100 109 class Meta: -
asadb/groups/views.py
r58a5c6a rffecc7f 2 2 3 3 import collections 4 import csv 4 5 import datetime 5 6 … … 14 15 from django.template import Context, Template 15 16 from django.template.loader import get_template 16 from django.http import Http 404, HttpResponseRedirect17 from django.http import HttpResponse, Http404, HttpResponseRedirect 17 18 from django.core.urlresolvers import reverse 19 from django.core.validators import URLValidator, EmailValidator, email_re 18 20 from django.core.mail import EmailMessage, mail_admins 19 21 from django import forms … … 21 23 from django.db import connection 22 24 from django.db.models import Q 25 from django.utils import html 23 26 from django.utils.safestring import mark_safe 24 27 … … 29 32 from util.db_form_utils import StaticWidget 30 33 from util.emails import email_from_template 34 35 urlvalidator = URLValidator() 36 emailvalidator = EmailValidator(email_re) 31 37 32 38 … … 142 148 ('size', { 143 149 'legend':'Membership Numbers', 150 'description':'Count each person in your group exactly once. Count only MIT students as "undergrads" or "grads". "Community" should be MIT community members who are not students, such as alums and staff.', 144 151 'fields': ['num_undergrads', 'num_grads', 'num_community', 'num_other',], 145 152 }), … … 202 209 } 203 210 return render_to_response('groups/group_change_main.html', context, context_instance=RequestContext(request), ) 211 212 213 214 ################## 215 # ACCOUNT LOOKUP # 216 ################## 217 218 class AccountLookupForm(forms.Form): 219 account_number = forms.IntegerField() 220 username = forms.CharField(help_text="Athena username of person to check") 221 222 def account_lookup(request, ): 223 msg = None 224 msg_type = "" 225 account_number = None 226 username = None 227 group = None 228 office_holders = [] 229 230 visible_roles = groups.models.OfficerRole.objects.filter(publicly_visible=True) 231 232 initial = {} 233 234 if 'search' in request.GET: # If the form has been submitted... 235 # A form bound to the POST data 236 form = AccountLookupForm(request.GET) 237 238 if form.is_valid(): # All validation rules pass 239 account_number = form.cleaned_data['account_number'] 240 username = form.cleaned_data['username'] 241 account_q = Q(main_account_id=account_number) | Q(funding_account_id=account_number) 242 try: 243 group = groups.models.Group.objects.get(account_q) 244 office_holders = group.officers(person=username) 245 office_holders = office_holders.filter(role__in=visible_roles) 246 except groups.models.Group.DoesNotExist: 247 msg = "Group not found" 248 msg_type = "error" 249 250 else: 251 form = AccountLookupForm() 252 253 context = { 254 'username': username, 255 'account_number': account_number, 256 'group': group, 257 'office_holders': office_holders, 258 'form': form, 259 'msg': msg, 260 'msg_type': msg_type, 261 'visible_roles': visible_roles, 262 } 263 return render_to_response('groups/account_lookup.html', context, context_instance=RequestContext(request), ) 264 204 265 205 266 … … 387 448 group.set_updater(request.user) 388 449 form.save() 389 officer_emails = create_group_officers(group, form.cleaned_data, )450 officer_emails = create_group_officers(group, form.cleaned_data, save=True, ) 390 451 391 452 return redirect(reverse('groups:group-detail', args=[group.pk])) … … 471 532 } 472 533 return render_to_response('groups/create/startup.html', context, context_instance=RequestContext(request), ) 473 474 class GroupRecognitionForm(forms.Form):475 test = forms.BooleanField()476 534 477 535 @permission_required('groups.recognize_group') … … 547 605 548 606 607 549 608 ################## 550 609 # Multiple group # … … 567 626 568 627 def __init__(self, data=None, *args, **kwargs): 569 if data is None: data = {}570 else: data = data.copy()628 if not data: data = None 629 super(GroupFilter, self).__init__(data, *args, **kwargs) 571 630 active_pk = groups.models.GroupStatus.objects.get(slug='active').pk 572 data.setdefault('group_status', active_pk, ) 573 super(GroupFilter, self).__init__(data, *args, **kwargs) 631 self.form.initial['group_status'] = active_pk 574 632 575 633 … … 764 822 dest = reverse('groups:signatories') 765 823 print dest 766 elif 'group-info' in request.GET: 824 elif 'group-goto' in request.GET: 825 if len(groups_filterset.qs) == 1: 826 group = groups_filterset.qs[0] 827 return redirect(reverse('groups:group-detail', kwargs={'pk':group.pk})) 828 else: 829 dest = reverse('groups:list') 830 elif 'group-list' in request.GET: 767 831 dest = reverse('groups:list') 768 832 … … 807 871 808 872 809 class AccountLookupForm(forms.Form): 810 account_number = forms.IntegerField() 811 username = forms.CharField(help_text="Athena username of person to check") 812 813 def account_lookup(request, ): 814 msg = None 815 msg_type = "" 816 account_number = None 817 username = None 818 group = None 819 office_holders = [] 820 821 visible_roles = groups.models.OfficerRole.objects.filter(publicly_visible=True) 822 823 initial = {} 824 825 if 'search' in request.GET: # If the form has been submitted... 826 # A form bound to the POST data 827 form = AccountLookupForm(request.GET) 828 829 if form.is_valid(): # All validation rules pass 830 account_number = form.cleaned_data['account_number'] 831 username = form.cleaned_data['username'] 832 account_q = Q(main_account_id=account_number) | Q(funding_account_id=account_number) 833 try: 834 group = groups.models.Group.objects.get(account_q) 835 office_holders = group.officers(person=username) 836 office_holders = office_holders.filter(role__in=visible_roles) 837 except groups.models.Group.DoesNotExist: 838 msg = "Group not found" 839 msg_type = "error" 840 873 874 ####################### 875 # REPORTING COMPONENT # 876 ####################### 877 878 class ReportingForm(form_utils.forms.BetterForm): 879 basic_fields_choices = groups.models.Group.reporting_fields() 880 basic_fields_labels = dict(basic_fields_choices) # name -> verbose_name 881 basic_fields = forms.fields.MultipleChoiceField( 882 choices=basic_fields_choices, 883 widget=forms.CheckboxSelectMultiple, 884 initial = ['id', 'name'], 885 ) 886 887 people_fields = forms.models.ModelMultipleChoiceField( 888 queryset=groups.models.OfficerRole.objects.all(), 889 widget=forms.CheckboxSelectMultiple, 890 required=False, 891 ) 892 show_as_emails = forms.BooleanField( 893 help_text='Append "@mit.edu" to each value of people fields to allow use as email addresses?', 894 required=False, 895 ) 896 897 _format_choices = [ 898 ('html/inline', "Web (HTML)", ), 899 ('csv/inline', "Spreadsheet (CSV) --- in browser", ), 900 ('csv/download', "Spreadsheet (CSV) --- download", ), 901 ] 902 output_format = forms.fields.ChoiceField(choices=_format_choices, widget=forms.RadioSelect, initial='html/inline') 903 904 class Meta: 905 fieldsets = [ 906 ('filter', { 907 'legend': 'Filter Groups', 908 'fields': ['name', 'abbreviation', 'activity_category', 'group_class', 'group_status', 'group_funding', ], 909 }), 910 ('fields', { 911 'legend': 'Data to display', 912 'fields': ['basic_fields', 'people_fields', 'show_as_emails', ], 913 }), 914 ('final', { 915 'legend': 'Final options', 916 'fields': ['o', 'output_format', ], 917 }), 918 ] 919 920 class GroupReportingFilter(GroupFilter): 921 class Meta(GroupFilter.Meta): 922 form = ReportingForm 923 order_by = True # we customize the field, so the value needs to be true-like but doesn't matter otherwise 924 925 def get_ordering_field(self): 926 return forms.ChoiceField(label="Ordering", required=False, choices=ReportingForm.basic_fields_choices) 927 928 def __init__(self, data=None, *args, **kwargs): 929 super(GroupReportingFilter, self).__init__(data, *args, **kwargs) 930 931 def format_id(pk): 932 url = reverse('groups:group-detail', kwargs={'pk':pk}) 933 return mark_safe("<a href='%s'>%d</a>" % (url, pk)) 934 935 def format_url(url): 936 try: 937 urlvalidator(url) 938 except ValidationError: 939 return url 841 940 else: 842 form = AccountLookupForm() 843 941 escaped = html.escape(url) 942 return mark_safe("<a href='%s'>%s</a>" % (escaped, escaped)) 943 944 def format_email(email): 945 try: 946 emailvalidator(email) 947 except ValidationError: 948 return email 949 else: 950 escaped = html.escape(email) 951 return mark_safe("<a href='mailto:%s'>%s</a>" % (escaped, escaped)) 952 953 reporting_html_formatters = { 954 'id': format_id, 955 'website_url': format_url, 956 'constitution_url': format_url, 957 'group_email': format_email, 958 'officer_email': format_email, 959 } 960 961 @permission_required('groups.view_group_private_info') 962 def reporting(request, ): 963 the_groups = groups.models.Group.objects.all() 964 groups_filterset = GroupReportingFilter(request.GET, the_groups) 965 form = groups_filterset.form 966 967 col_labels = [] 968 report_groups = [] 969 run_report = 'go' in request.GET and form.is_valid() 970 if run_report: 971 basic_fields = form.cleaned_data['basic_fields'] 972 output_format, output_disposition = form.cleaned_data['output_format'].split('/') 973 col_labels = [form.basic_fields_labels[field] for field in basic_fields] 974 975 # Set up query 976 qs = groups_filterset.qs 977 # Prefetch foreign keys 978 prefetch_fields = groups.models.Group.reporting_prefetch() 979 prefetch_fields = prefetch_fields.intersection(basic_fields) 980 if prefetch_fields: 981 qs = qs.select_related(*list(prefetch_fields)) 982 983 # Set up people 984 people_fields = form.cleaned_data['people_fields'] 985 people_data = groups.models.OfficeHolder.current_holders.filter(group__in=qs, role__in=people_fields) 986 # Group.pk -> (OfficerRole.pk -> set(username)) 987 people_map = collections.defaultdict(lambda: collections.defaultdict(set)) 988 for holder in people_data: 989 people_map[holder.group_id][holder.role_id].add(holder.person) 990 for field in people_fields: 991 col_labels.append(field.display_name) 992 993 # Assemble data 994 if output_format == 'html': 995 formatters = reporting_html_formatters 996 else: 997 formatters = {} 998 show_as_emails = form.cleaned_data['show_as_emails'] 999 def fetch_item(group, field): 1000 val = getattr(group, field) 1001 if field in formatters: 1002 val = formatters[field](val) 1003 return val 1004 for group in qs: 1005 group_data = [fetch_item(group, field) for field in basic_fields] 1006 for field in people_fields: 1007 people = people_map[group.pk][field.pk] 1008 if show_as_emails: people = ["%s@mit.edu" % p for p in people] 1009 group_data.append(", ".join(people)) 1010 1011 report_groups.append(group_data) 1012 1013 # Handle output as CSV 1014 if output_format == 'csv': 1015 if output_disposition == 'download': 1016 mimetype = 'text/csv' 1017 else: 1018 # Firefox, at least, downloads text/csv regardless 1019 mimetype = 'text/plain' 1020 response = HttpResponse(mimetype=mimetype) 1021 if output_disposition == 'download': 1022 response['Content-Disposition'] = 'attachment; filename=asa-db-report.csv' 1023 writer = csv.writer(response) 1024 writer.writerow(col_labels) 1025 for row in report_groups: writer.writerow(row) 1026 return response 1027 1028 # Handle output as HTML 844 1029 context = { 845 'username': username, 846 'account_number': account_number, 847 'group': group, 848 'office_holders': office_holders, 849 'form': form, 850 'msg': msg, 851 'msg_type': msg_type, 852 'visible_roles': visible_roles, 1030 'form': form, 1031 'run_report': run_report, 1032 'column_labels': col_labels, 1033 'report_groups': report_groups, 1034 'pagename': 'groups', 853 1035 } 854 return render_to_response('groups/ account_lookup.html', context, context_instance=RequestContext(request), )1036 return render_to_response('groups/reporting.html', context, context_instance=RequestContext(request), )
Note: See TracChangeset
for help on using the changeset viewer.