Style fixes and removal of unused imports in soc.views.models.
[Melange.git] / app / soc / views / models / group.py
blobe3bc87a2e55358cea7c38262bb59f3b3d6c6fc82
1 #!/usr/bin/python2.5
3 # Copyright 2008 the Melange authors.
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
9 # http://www.apache.org/licenses/LICENSE-2.0
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
17 """Views for Groups.
18 """
20 __authors__ = [
21 '"Sverre Rabbelier" <sverre@rabbelier.nl>',
22 '"Lennard de Rijk" <ljvderijk@gmail.com>',
26 from django import forms
27 from django import http
28 from django.utils.translation import ugettext
30 from soc.logic import cleaning
31 from soc.logic import dicts
32 from soc.logic.models import user as user_logic
33 from soc.views.helper import decorators
34 from soc.views.helper import lists as list_helper
35 from soc.views.helper import redirects
36 from soc.views.helper import responses
37 from soc.views.helper import widgets
38 from soc.views.models import presence
39 from soc.views.models import document as document_view
40 from soc.views.models.request import view as request_view
41 from soc.views.sitemap import sidebar
43 import soc.views.helper
45 class View(presence.View):
46 """View methods for the Group model.
47 """
50 def __init__(self, params=None):
51 """Defines the fields and methods required for the base View class
52 to provide the user with list, public, create, edit and delete views.
54 Params:
55 params: a dict with params for this View
56 """
58 new_params = {}
60 new_params['extra_dynaexclude'] = ['founder', 'home', 'tos',
61 'member_template', 'status']
62 new_params['edit_extra_dynaproperties'] = {
63 'founded_by': forms.CharField(widget=widgets.ReadOnlyInput(),
64 required=False),
67 #set the extra_django_patterns and include the one from params
68 patterns = params.get('extra_django_patterns', [])
70 patterns += [
71 (r'^%(url_name)s/(?P<access_type>list_requests)/%(key_fields)s$',
72 'soc.views.models.%(module_name)s.list_requests',
73 'List of requests for %(name)s'),
74 (r'^%(url_name)s/(?P<access_type>list_roles)/%(key_fields)s$',
75 'soc.views.models.%(module_name)s.list_roles',
76 'List of roles for %(name)s')]
78 if params.get('group_applicant_url'):
79 # add the applicant pattern
80 patterns += [
81 (r'^%(url_name)s/(?P<access_type>applicant)/%(key_fields)s$',
82 'soc.views.models.%(module_name)s.applicant',
83 "%(name)s Creation via Accepted Application"),]
85 new_params['extra_django_patterns'] = patterns
87 # TODO(tlarsen): Add support for Django style template lookup
88 new_params['public_template'] = 'soc/group/public.html'
90 new_params['list_row'] = 'soc/group/list/row.html'
91 new_params['list_heading'] = 'soc/group/list/heading.html'
93 new_params['create_extra_dynaproperties'] = {
94 'clean_phone': cleaning.clean_phone_number('phone'),
95 'clean_contact_street': cleaning.clean_ascii_only('contact_street'),
96 'clean_contact_city': cleaning.clean_ascii_only('contact_city'),
97 'clean_contact_state': cleaning.clean_ascii_only('contact_state'),
98 'clean_contact_postalcode': cleaning.clean_ascii_only(
99 'contact_postalcode'),
100 'clean_shipping_street': cleaning.clean_ascii_only('shipping_street'),
101 'clean_shipping_city': cleaning.clean_ascii_only('shipping_city'),
102 'clean_shipping_state': cleaning.clean_ascii_only('shipping_state'),
103 'clean_shipping_postalcode': cleaning.clean_ascii_only(
104 'shipping_postalcode'),
108 new_params['role_views'] = {}
110 params = dicts.merge(params, new_params, sub_merge=True)
112 super(View, self).__init__(params=params)
114 def _editGet(self, request, entity, form):
115 """See base.View._editGet().
118 # fill in the founded_by with data from the entity
119 form.fields['founded_by'].initial = entity.founder.name
120 super(View, self)._editGet(request, entity, form)
122 def _editPost(self, request, entity, fields):
123 """See base.View._editPost().
126 if not entity:
127 # only if we are creating a new entity we should fill in founder
128 user = user_logic.logic.getForCurrentAccount()
129 fields['founder'] = user
131 super(View, self)._editPost(request, entity, fields)
134 @decorators.merge_params
135 @decorators.check_access
136 def applicant(self, request, access_type,
137 page_name=None, params=None, **kwargs):
138 """Handles the creation of a group via an approved group application.
140 Args:
141 request: the standard Django HTTP request object
142 access_type : the name of the access type which should be checked
143 page_name: the page name displayed in templates as page and header title
144 params: a dict with params for this View
145 kwargs: the Key Fields for the specified entity
148 # get the context for this webpage
149 context = responses.getUniversalContext(request)
150 responses.useJavaScript(context, params['js_uses_all'])
151 context['page_name'] = page_name
153 if request.method == 'POST':
154 return self.applicantPost(request, context, params, **kwargs)
155 else:
156 # request.method == 'GET'
157 return self.applicantGet(request, context, params, **kwargs)
159 def applicantGet(self, request, context, params, **kwargs):
160 """Handles the GET request concerning the creation of a group via an
161 approved group application.
163 Args:
164 request: the standard Django HTTP request object
165 context: dictionary containing the context for this view
166 params: a dict with params for this View
167 kwargs: the Key Fields for the specified entity
170 # find the application
171 application_logic = params['application_logic']
172 application = application_logic.logic.getFromKeyFields(kwargs)
174 # extract the application fields
175 field_names = application.properties().keys()
176 fields = dict( [(i, getattr(application, i)) for i in field_names] )
178 # create the form using the fields from the application as the initial value
179 form = params['applicant_create_form'](initial=fields)
181 # construct the appropriate response
182 return super(View, self)._constructResponse(request, entity=None,
183 context=context, form=form, params=params)
185 def applicantPost(self, request, context, params, **kwargs):
186 """Handles the POST request concerning the creation of a group via an
187 approved group application.
189 Args:
190 request: the standard Django HTTP request object
191 context: dictionary containing the context for this view
192 params: a dict with params for this View
193 kwargs: the Key Fields for the specified entity
196 # populate the form using the POST data
197 form = params['applicant_create_form'](request.POST)
199 if not form.is_valid():
200 # return the invalid form response
201 return self._constructResponse(request, entity=None, context=context,
202 form=form, params=params)
204 # collect the cleaned data from the valid form
205 key_name, fields = soc.views.helper.forms.collectCleanedFields(form)
207 # do post processing
208 self._applicantPost(request, context, fields)
210 if not key_name:
211 key_name = self._logic.getKeyNameFromFields(fields)
213 # create the group entity
214 self._logic.updateOrCreateFromKeyName(fields, key_name)
216 # redirect to notifications list to see the admin invite
217 return http.HttpResponseRedirect('/notification/list')
219 def _applicantPost(self, request, context, fields):
220 """Performs any required processing on the entity to post its edit page.
222 Args:
223 request: the django request object
224 context: the context for the webpage
225 fields: the new field values
228 # fill in the founder of the group
229 user = user_logic.logic.getForCurrentAccount()
230 fields['founder'] = user
232 # If scope_logic is not defined, this entity has no scope
233 if not self._params['scope_logic']:
234 return
236 # If this entity is unscoped, do not try to retrieve a scope
237 if 'scope_path' not in fields:
238 return
240 scope = self._params['scope_logic'].logic.getFromKeyName(
241 fields['scope_path'])
242 fields['scope'] = scope
245 @decorators.merge_params
246 @decorators.check_access
247 def listRequests(self, request, access_type,
248 page_name=None, params=None, **kwargs):
249 """Gives an overview of all the requests for a specific group.
251 Args:
252 request: the standard Django HTTP request object
253 access_type : the name of the access type which should be checked
254 page_name: the page name displayed in templates as page and header title
255 params: a dict with params for this View
256 kwargs: the Key Fields for the specified entity
259 # set the pagename to include the link_id
260 page_name = '%s %s' % (page_name, kwargs['link_id'])
262 # get the group from the request
263 group_logic = params['logic']
265 group_entity = group_logic.getFromKeyFields(kwargs)
267 role_names = params['role_views'].keys()
269 # list all incoming requests
270 filter = {
271 'scope': group_entity,
272 'role': role_names,
273 'status': 'new'
276 # create the list parameters
277 inc_req_params = request_view.getParams()
279 # define the list redirect action to the request processing page
280 inc_req_params['list_action'] = (redirects.getProcessRequestRedirect, None)
281 inc_req_params['list_description'] = ugettext(
282 "An overview of the %(name)s's incoming requests." % params)
284 inc_req_content = list_helper.getListContent(
285 request, inc_req_params, filter, idx=0)
287 # list all outstanding invites
288 filter = {
289 'scope': group_entity,
290 'role': role_names,
291 'status': 'group_accepted'
294 # create the list parameters
295 out_inv_params = request_view.getParams()
297 # define the list redirect action to the request processing page
298 out_inv_params['list_action'] = (redirects.getProcessRequestRedirect, None)
299 out_inv_params['list_description'] = ugettext(
300 "An overview of the %(name)s's outstanding invites." % params)
302 out_inv_content = list_helper.getListContent(
303 request, out_inv_params, filter, idx=1)
305 # list all ignored requests
306 filter = {
307 'scope': group_entity,
308 'role': role_names,
309 'status': 'ignored'
312 # create the list parameters
313 ignored_params = request_view.getParams()
315 # define the list redirect action to the request processing page
316 ignored_params['list_action'] = (redirects.getProcessRequestRedirect, None)
317 ignored_params['list_description'] = ugettext(
318 "An overview of the %(name)s's ignored requests." % params)
320 ignored_content = list_helper.getListContent(
321 request, ignored_params, filter, idx=2)
323 contents = [inc_req_content, out_inv_content, ignored_content]
325 return self._list(request, params, contents, page_name)
328 @decorators.merge_params
329 @decorators.check_access
330 def listRoles(self, request, access_type,
331 page_name=None, params=None, **kwargs):
332 """Gives an overview of all the roles in a specific group.
334 Args:
335 request: the standard Django HTTP request object
336 access_type : the name of the access type which should be checked
337 page_name: the page name displayed in templates as page and header title
338 params: a dict with params for this View
339 kwargs: the Key Fields for the specified entity
342 # set the pagename to include the link_id
343 page_name = '%s %s' % (page_name, kwargs['link_id'])
345 # get the group from the request
346 group_logic = params['logic']
348 group_entity = group_logic.getFromKeyFields(kwargs)
350 # create the filter
351 filter = {
352 'scope' : group_entity,
353 'status': 'active'
356 role_views = params['role_views']
357 contents = []
358 index = 0
360 # for each role we create a separate list
361 for role_name in role_views.keys():
362 # create the list parameters
363 list_params = role_views[role_name].getParams().copy()
365 list_params['list_action'] = (redirects.getManageRedirect, list_params)
366 list_params['list_description'] = ugettext(
367 "An overview of the %s for this %s." % (
368 list_params['name_plural'], params['name']))
370 new_list_content = list_helper.getListContent(
371 request, list_params, filter, idx=index)
373 contents += [new_list_content]
375 index += 1
377 # call the _list method from base.View to show the list
378 return self._list(request, params, contents, page_name)
380 def registerRole(self, role_name, role_view):
381 """Adds a role to the role_views param.
383 Args:
384 role_name: The name of the role that needs to be added
385 role_view: The view that needs to be added to role_views.
388 role_views = self._params['role_views']
389 role_views[role_name] = role_view
391 def getExtraMenus(self, id, user, params=None):
392 """Returns the extra menu's for this view.
394 A menu item is generated for each group that the user has an active
395 role for. The public page for each group is added as menu item,
396 as well as all public documents for that group.
398 Args:
399 params: a dict with params for this View.
402 params = dicts.merge(params, self._params)
404 # set fields to match every active role this user has
405 fields = {'user': user,
406 'status': 'active'}
408 # get the role views and start filling group_entities
409 role_views = self._params['role_views']
410 role_descriptions = {}
412 for role_name in role_views.keys():
413 role_view = role_views[role_name]
414 role_view_params = role_view.getParams()
415 role_logic = role_view_params['logic']
417 roles = role_logic.getForFields(fields)
419 for role in roles:
420 group_key_name = role.scope.key().name()
421 existing_role_descriptions = role_descriptions.get(group_key_name)
423 if existing_role_descriptions:
424 # add this description to existing roles
425 existing_roles = existing_role_descriptions['roles']
426 existing_roles[role_name] = role
427 else:
428 # create a description of this role
429 role_description = {'roles': {role_name: role},
430 'group': role.scope}
432 # add the new entry to our dictionary
433 role_descriptions[group_key_name] = role_description
435 # get the document view params to add the group's documents to the menu
436 doc_params = document_view.view.getParams()
438 menus = []
440 # for each role description in our collection
441 for role_description in role_descriptions.itervalues():
442 #start with an empty menu
443 menu = {}
445 # get the group for this role description
446 group_entity = role_description['group']
448 # set the menu header name
449 menu['heading'] = group_entity.short_name
451 # get the documents for this group entity
452 doc_items = document_view.view.getMenusForScope(group_entity, params)
453 doc_items = sidebar.getSidebarMenu(id, user, doc_items,
454 params=doc_params)
456 # get the group specific items
457 group_items = self._getExtraMenuItems(role_description, params)
458 group_items = sidebar.getSidebarMenu(id, user, group_items,
459 params=self._params)
461 # add the items together
462 menu['items'] = doc_items + group_items
463 menu['group'] = params['name_plural']
465 # append this as a new menu
466 menus.append(menu)
468 return menus
470 def _getExtraMenuItems(self, role_description, params=None):
471 """Used to implement group instance specific needs for the side menu.
473 Args:
474 role_description : dict containing all the roles which is a dict of
475 name and the role entity to which it belongs. Also
476 group contains the group entity to which these roles
477 belong.
478 params: a dict with params for this View.
480 return []