Fix too long lines in soc.views.helper.params module.
[Melange.git] / app / soc / views / helper / params.py
blob4f8e8db91d2272883d456f85d796336b5828bc7d
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 """Params related methods.
18 """
20 __authors__ = [
21 '"Sverre Rabbelier" <sverre@rabbelier.nl>',
25 import copy
27 from django import forms
28 from django.utils.translation import ugettext
30 from soc.logic import cleaning
31 from soc.logic import dicts
32 from soc.models import linkable
33 from soc.views import helper
34 from soc.views.helper import access
35 from soc.views.helper import dynaform
36 from soc.views.helper import redirects
37 from soc.views.helper import widgets
40 DEF_LIST_DESCRIPTION_FMT = ugettext(
41 'List of %(name_plural)s.')
43 DEF_CREATE_INSTRUCTION_MSG_FMT = ugettext(
44 'Please use this form to select a %(name).')
46 DEF_SUBMIT_MSG_PARAM_NAME = 's'
47 DEF_SUBMIT_MSG_PROFILE_SAVED = 0
48 DEF_SUBMIT_MSG_CANNOT_DELETE_ENTITY = 1
51 # list with all js scripts used for documentary purposes
52 DEF_JS_USES_LIST = [
53 'jq',
54 'jq_ajaqQueue',
55 'jq_autocomplete',
56 'jq_bgiframe',
57 'jq_bt',
58 'jq_datetimepicker',
59 'jq_progressbar',
60 'jq_thickbox',
61 'jq_ui_core',
62 'menu',
63 'bulk_review',
64 'tinymce',
67 DEF_FIELD_INIT_PARAMS = ['required', 'widget', 'label', 'initial', 'help_text',
68 'error_messages', 'show_hidden_initial']
71 def constructParams(params):
72 """Constructs a new params dictionary based on params.
74 Params usage:
75 The params dictionary is passed to getCreateForm and getEditForm,
76 see their docstring on how they use it.
78 rights: The rights value is merged with a default rights
79 dictionary and then used as rights value.
80 url_name: The url_name value is used in constructing several
81 redirects as the first part of the url.
82 module_name: The module_name value is used in constructing the
83 location of several templates. It is expected that it matches
84 the part after "/templates/soc/" for this View.
85 name_plural: The name_plural argument is provided to the
86 LIST_DESCRIPTION when constructing the list_description field.
87 extra_dynainclude: The extra_dynainclude value is used when
88 constructing the create_dynainclude value.
89 extra_dynaexclude: The extra_dynaexclude value is used when
90 constructing the create_dynaexclude value.
91 logic: The logic value is used as argument to save the scope_logic
92 and create a create form.
93 """
95 logic = params['logic']
97 rights = access.Checker(params)
98 rights['unspecified'] = []
99 rights['any_access'] = ['checkIsLoggedIn']
100 rights['show'] = ['checkIsUser']
101 rights['create'] = ['checkIsDeveloper']
102 rights['edit'] = ['checkIsDeveloper']
103 rights['delete'] = ['checkIsDeveloper']
104 rights['list'] = ['checkIsDeveloper']
105 rights['pick'] = ['checkIsUser'] # TODO(SRabbelier): proper check
107 new_params = {}
108 new_params['scope_logic'] = logic.getScopeLogic()
110 if 'name_short' not in params:
111 params['name_short'] = params['name']
113 if 'name_plural' not in params:
114 params['name_plural'] = params['name'] + 's'
116 if 'module_name' not in params:
117 params['module_name'] = params['name_short'].replace(' ', '_').lower()
119 if 'url_name' not in params:
120 params['url_name'] = params['module_name']
122 if 'document_prefix' not in params:
123 params['document_prefix'] = params['url_name']
125 # Do not expand edit_redirect to allow it to be overwritten without suffix
126 new_params['edit_redirect'] = '/%(url_name)s/edit/%(suffix)s'
127 new_params['missing_redirect'] = '/%(url_name)s/create' % params
128 new_params['delete_redirect'] = '/%(url_name)s/list' % params
129 new_params['invite_redirect'] = '/request/list'
130 new_params['edit_cancel_redirect'] = '/%(url_name)s/list' % params
132 new_params['sidebar'] = None
133 new_params['sidebar_grouping'] = 'main'
134 new_params['sidebar_defaults'] = [
135 ('/%s/create', 'New %(name)s', 'create'),
136 ('/%s/list', 'List %(name_plural)s', 'list'),
138 new_params['sidebar_additional'] = []
140 names_sans_link_id = [i for i in logic.getKeyFieldNames() if i != 'link_id']
141 sans_link_id_pattern = getPattern(names_sans_link_id,
142 linkable.SCOPE_PATH_ARG_PATTERN)
144 new_params['link_id_arg_pattern'] = linkable.LINK_ID_ARG_PATTERN
145 new_params['link_id_pattern_core'] = linkable.LINK_ID_PATTERN_CORE
146 new_params['scope_path_pattern'] = getScopePattern(params)
147 new_params['sans_link_id_pattern'] = sans_link_id_pattern
149 new_params['django_patterns'] = None
150 new_params['extra_django_patterns'] = []
151 new_params['django_patterns_defaults'] = []
153 if not params.get('no_edit'):
154 new_params['django_patterns_defaults'] += [
155 (r'^%(url_name)s/(?P<access_type>edit)/%(key_fields)s$',
156 'soc.views.models.%(module_name)s.edit', 'Edit %(name_short)s')]
158 if not params.get('no_delete'):
159 new_params['django_patterns_defaults'] += [
160 (r'^%(url_name)s/(?P<access_type>delete)/%(key_fields)s$',
161 'soc.views.models.%(module_name)s.delete', 'Delete %(name_short)s')]
163 if not params.get('no_show'):
164 new_params['django_patterns_defaults'] += [
165 (r'^%(url_name)s/(?P<access_type>show)/%(key_fields)s$',
166 'soc.views.models.%(module_name)s.public', 'Show %(name_short)s')]
168 if not params.get('no_admin'):
169 new_params['django_patterns_defaults'] += [
170 (r'^%(url_name)s/(?P<access_type>admin)/%(key_fields)s$',
171 'soc.views.models.%(module_name)s.admin',
172 'Show %(name_short)s (admin)')]
174 if not params.get('no_create_raw'):
175 new_params['django_patterns_defaults'] += [
176 (r'^%(url_name)s/(?P<access_type>create)$',
177 'soc.views.models.%(module_name)s.create', 'Create %(name_short)s')]
179 if not params.get('no_create_with_scope'):
180 new_params['django_patterns_defaults'] += [
181 (r'^%(url_name)s/(?P<access_type>create)/%(scope)s$',
182 'soc.views.models.%(module_name)s.create', 'Create %(name_short)s')]
184 if not params.get('no_create_with_key_fields'):
185 new_params['django_patterns_defaults'] += [
186 (r'^%(url_name)s/(?P<access_type>create)/%(key_fields)s$',
187 'soc.views.models.%(module_name)s.create', 'Create %(name_short)s')]
189 if not params.get('no_list_raw'):
190 new_params['django_patterns_defaults'] += [
191 (r'^%(url_name)s/(?P<access_type>list)$',
192 'soc.views.models.%(module_name)s.list', 'List %(name_plural)s')]
194 if params.get('pickable'):
195 new_params['django_patterns_defaults'] += [
196 (r'^%(url_name)s/(?P<access_type>pick)$',
197 'soc.views.models.%(module_name)s.pick', 'Pick %(name_short)s')]
199 if params.get('export_content_type'):
200 new_params['django_patterns_defaults'] += [
201 (r'^%(url_name)s/(?P<access_type>export)/%(key_fields)s$',
202 'soc.views.models.%(module_name)s.export', 'Export %(name_short)s')]
204 if params.get('sans_link_id_create'):
205 new_params['django_patterns_defaults'] += [
206 (r'^%(url_name)s/(?P<access_type>create)/%(sans_link_id)s$',
207 'soc.views.models.%(module_name)s.create', 'Create %(name_short)s')]
209 if params.get('sans_link_id_list'):
210 new_params['django_patterns_defaults'] += [
211 (r'^%(url_name)s/(?P<access_type>list)/%(sans_link_id)s$',
212 'soc.views.models.%(module_name)s.list', 'List %(name_plural)s')]
214 if params.get('sans_link_id_public_list'):
215 new_params['django_patterns_defaults'] += [
216 (r'^%(url_name)s/(?P<access_type>list_public)/%(sans_link_id)s$',
217 'soc.views.models.%(module_name)s.list_public',
218 'List %(name_plural)s')]
220 new_params['public_template'] = 'soc/%(module_name)s/public.html' % params
221 new_params['export_template'] = 'soc/%(module_name)s/export.html' % params
222 new_params['create_template'] = 'soc/models/edit.html'
223 new_params['edit_template'] = 'soc/models/edit.html'
224 new_params['admin_template'] = 'soc/models/admin.html'
225 new_params['list_template'] = 'soc/models/list.html'
226 new_params['invite_template'] = 'soc/models/invite.html'
228 new_params['export_content_type'] = None
229 new_params['export_extension'] = '.txt'
231 # TODO: Use only the js modules needed instead of js_uses_all
232 new_params['js_uses_all'] = DEF_JS_USES_LIST
233 new_params['js_uses_list'] = ['jq', 'menu']
234 new_params['js_uses_show'] = ['jq', 'menu']
235 new_params['js_uses_edit'] = ['jq', 'menu', 'tinymce', 'jq_bt',
236 'jq_autocomplete']
238 new_params['error_public'] = 'soc/%(module_name)s/error.html' % params
239 new_params['error_export'] = new_params['error_public']
240 new_params['error_edit'] = new_params['error_public']
242 new_params['list_main'] = 'soc/list/main.html'
243 new_params['list_pagination'] = 'soc/list/pagination.html'
244 new_params['list_row'] = 'soc/%(module_name)s/list/row.html' % params
245 new_params['list_heading'] = 'soc/%(module_name)s/list/heading.html' % params
247 new_params['list_action'] = (redirects.getEditRedirect, params)
248 new_params['list_params'] = {
249 'list_action': 'action',
250 'list_description': 'description',
251 'list_main': 'main',
252 'list_pagination': 'pagination',
253 'list_row': 'row',
254 'list_heading': 'heading',
257 new_params['list_description'] = DEF_LIST_DESCRIPTION_FMT % params
258 new_params['no_lists_msg'] = ""
259 new_params['save_message'] = [ugettext('%(name)s saved.' % params),
260 ugettext('Cannot delete %(name)s.' % params)]
261 new_params['submit_msg_param_name'] = DEF_SUBMIT_MSG_PARAM_NAME
262 new_params['edit_params'] = {
263 DEF_SUBMIT_MSG_PARAM_NAME: DEF_SUBMIT_MSG_PROFILE_SAVED,
266 new_params['cannot_delete_params'] = {
267 DEF_SUBMIT_MSG_PARAM_NAME: DEF_SUBMIT_MSG_CANNOT_DELETE_ENTITY,
270 new_params['dynabase'] = helper.forms.BaseForm
272 create_dynaproperties = {
273 'clean_link_id': cleaning.clean_link_id('link_id'),
274 'clean_feed_url': cleaning.clean_feed_url,
276 create_dynaproperties.update(params.get('create_extra_dynaproperties', {}))
278 # dynafields override any dynaproperties
279 create_dynafields = getDynaFields(params.get('create_dynafields', {}))
280 create_dynaproperties = dicts.merge(create_dynafields, create_dynaproperties)
282 new_params['references'] = []
283 new_params['create_dynainclude'] = [] + params.get('extra_dynainclude', [])
284 new_params['create_dynaexclude'] = ['scope', 'scope_path'] + \
285 params.get('extra_dynaexclude', [])
286 new_params['create_dynaproperties'] = create_dynaproperties
288 edit_dynaproperties = {
289 'clean_link_id': cleaning.clean_link_id('link_id'),
290 'link_id': forms.CharField(widget=helper.widgets.ReadOnlyInput()),
292 edit_dynaproperties.update(params.get('edit_extra_dynaproperties', {}))
294 # dynafields override any dynaproperties
295 edit_dynafields = getDynaFields(params.get('edit_dynafields', {}))
296 edit_dynaproperties = dicts.merge(edit_dynafields, edit_dynaproperties)
298 new_params['edit_dynainclude'] = None
299 new_params['edit_dynaexclude'] = None
300 new_params['edit_dynaproperties'] = edit_dynaproperties
302 params = dicts.merge(params, new_params)
304 # These need to be constructed separately, because they require
305 # parameters that can be defined either in params, or new_params.
306 if not 'create_form' in params:
307 params['create_form'] = getCreateForm(params, logic.getModel())
309 if not 'edit_form' in params:
310 params['edit_form'] = getEditForm(params, params['create_form'])
312 if not 'admin_form' in params:
313 params['admin_form'] = getAdminForm(params['edit_form'])
315 if not 'key_fields_pattern' in params:
316 params['key_fields_pattern'] = getKeyFieldsPattern(params)
318 # merge already done by access.Checker
319 params['rights'] = rights
321 return params
324 def getDynaFields(fields):
325 """Constructs a new DynaField using params.
327 Args:
328 params: the params dictionary used to extract the dyanfields
329 param_name: the name of the parameter to use
332 dynafields = {}
334 # generate the dynafields
335 for field in fields:
336 base = field.pop('base')
337 name = field.pop('name')
338 passthrough = field.pop('passthrough', DEF_FIELD_INIT_PARAMS)
340 dynafield = dynaform.newDynaField(field, base, passthrough)
341 dynafields[name] = dynafield()
343 return dynafields
346 def getCreateForm(params, model):
347 """Constructs a new CreateForm using params.
349 Params usage:
350 dynabase: The dynabase value is used as the base argument to
351 dynaform.newDynaForm.
352 logic: The logic value is used to get the model argument to newDynaForm.
353 create_dynainclude: same as dynabase, but as dynainclude argument
354 create_dynaexclude: same as dynabase, but as dynaexclude argument
355 create_dynaproperties: same as dynabase, but as dynaproperties argument
358 create_form = dynaform.newDynaForm(
359 dynabase = params['dynabase'],
360 dynamodel = model,
361 dynainclude = params['create_dynainclude'],
362 dynaexclude = params['create_dynaexclude'],
363 dynaproperties = params['create_dynaproperties'],
366 if 'extra_key_order' in params:
367 for field in params['extra_key_order']:
368 if field in create_form.base_fields.keyOrder:
369 create_form.base_fields.keyOrder.remove(field)
370 create_form.base_fields.keyOrder.extend(params['extra_key_order'])
372 return create_form
375 def getEditForm(params, base_form):
376 """Constructs a new EditForm using params.
378 Params usage:
379 create_form: The dynabase value is used as the dynaform argument
380 to dyanform.extendDynaForm.
381 edit_dynainclude: same as create_form, but as dynainclude argument
382 edit_dynaexclude: same as create_form, but as dynaexclude argument
383 edit_dynaproperties: same as create_form, but as dynaproperties argument
386 edit_form = dynaform.extendDynaForm(
387 dynaform = base_form,
388 dynainclude = params['edit_dynainclude'],
389 dynaexclude = params['edit_dynaexclude'],
390 dynaproperties = params['edit_dynaproperties'],
393 return edit_form
396 def getAdminForm(base_form):
397 """Constructs a new AdminForm from base_form.
400 # extend _and_ deepcopy the base_fields to do a proper copy
401 admin_form = dynaform.extendDynaForm(dynaform = base_form)
402 admin_form.base_fields = copy.deepcopy(admin_form.base_fields)
404 # replace all widgets with PTW's
405 for key, value in admin_form.base_fields.iteritems():
406 if not isinstance(value, forms.fields.Field):
407 continue
409 value.widget = widgets.PlainTextWidget()
411 return admin_form
414 def getKeyFieldsPattern(params):
415 """Returns the Django pattern for this View's entity.
418 names = params['logic'].getKeyFieldNames()
419 scope_path_pattern = params['scope_path_pattern']
421 return getPattern(names, scope_path_pattern)
424 def getPattern(names, scope_path_pattern):
425 """Returns the Django patterns for the specified names.
427 Args:
428 names: the field names that should be included in the pattern
429 scope_path_pattern: the pattern to use if the name is 'scope_path'
432 patterns = []
434 for name in names:
435 if name == 'scope_path':
436 pattern = scope_path_pattern
437 else:
438 pattern = r'(?P<%s>%s)' % (name, linkable.LINK_ID_PATTERN_CORE)
439 patterns.append(pattern)
441 result = '/'.join(patterns)
442 return result
445 def getScopePattern(params):
446 """Returns the Scope pattern for this entity.
449 logic = params['logic']
450 depth = logic.getScopeDepth()
451 if depth is None:
452 return linkable.SCOPE_PATH_ARG_PATTERN
454 regexps = [linkable.LINK_ID_PATTERN_CORE for i in range(depth)]
455 regexp = '/'.join(regexps)
456 return r'(?P<scope_path>%s)' % regexp