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.
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.
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.
55 params: a dict with params for this View
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(),
67 #set the extra_django_patterns and include the one from params
68 patterns
= params
.get('extra_django_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
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().
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.
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
)
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.
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.
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
)
208 self
._applicantPost
(request
, context
, fields
)
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.
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']:
236 # If this entity is unscoped, do not try to retrieve a scope
237 if 'scope_path' not in fields
:
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.
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
271 'scope': group_entity
,
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
289 'scope': group_entity
,
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
307 'scope': group_entity
,
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.
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
)
352 'scope' : group_entity
,
356 role_views
= params
['role_views']
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
]
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.
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.
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
,
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
)
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
428 # create a description of this role
429 role_description
= {'roles': {role_name
: role
},
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()
440 # for each role description in our collection
441 for role_description
in role_descriptions
.itervalues():
442 #start with an empty 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
,
456 # get the group specific items
457 group_items
= self
._getExtraMenuItems
(role_description
, params
)
458 group_items
= sidebar
.getSidebarMenu(id, user
, group_items
,
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
470 def _getExtraMenuItems(self
, role_description
, params
=None):
471 """Used to implement group instance specific needs for the side menu.
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
478 params: a dict with params for this View.