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.
21 '"Sverre Rabbelier" <sverre@rabbelier.nl>',
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
68 DEF_FIELD_INIT_PARAMS
= ['required', 'widget', 'label', 'initial', 'help_text',
69 'error_messages', 'show_hidden_initial']
72 def constructParams(params
):
73 """Constructs a new params dictionary based on params.
76 The params dictionary is passed to getCreateForm and getEditForm,
77 see their docstring on how they use it.
79 rights: The rights value is merged with a default rights
80 dictionary and then used as rights value.
81 url_name: The url_name value is used in constructing several
82 redirects as the first part of the url.
83 module_name: The module_name value is used in constructing the
84 location of several templates. It is expected that it matches
85 the part after "/templates/soc/" for this View.
86 name_plural: The name_plural argument is provided to the
87 LIST_DESCRIPTION when constructing the list_description field.
88 extra_dynainclude: The extra_dynainclude value is used when
89 constructing the create_dynainclude value.
90 extra_dynaexclude: The extra_dynaexclude value is used when
91 constructing the create_dynaexclude value.
92 logic: The logic value is used as argument to save the scope_logic
93 and create a create form.
96 logic
= params
['logic']
98 rights
= access
.Checker(params
)
99 rights
['unspecified'] = []
100 rights
['any_access'] = ['checkIsLoggedIn']
101 rights
['show'] = ['checkIsUser']
102 rights
['create'] = ['checkIsDeveloper']
103 rights
['edit'] = ['checkIsDeveloper']
104 rights
['delete'] = ['checkIsDeveloper']
105 rights
['list'] = ['checkIsDeveloper']
106 rights
['pick'] = ['checkIsUser'] # TODO(SRabbelier): proper check
109 new_params
['scope_logic'] = logic
.getScopeLogic()
111 if 'name_short' not in params
:
112 params
['name_short'] = params
['name']
114 if 'name_plural' not in params
:
115 params
['name_plural'] = params
['name'] + 's'
117 if 'module_name' not in params
:
118 params
['module_name'] = params
['name_short'].replace(' ', '_').lower()
120 if 'url_name' not in params
:
121 params
['url_name'] = params
['module_name']
123 if 'document_prefix' not in params
:
124 params
['document_prefix'] = params
['url_name']
126 # Do not expand edit_redirect to allow it to be overwritten without suffix
127 new_params
['edit_redirect'] = '/%(url_name)s/edit/%(suffix)s'
128 new_params
['missing_redirect'] = '/%(url_name)s/create' % params
129 new_params
['delete_redirect'] = '/%(url_name)s/list' % params
130 new_params
['invite_redirect'] = '/request/list'
131 # new_params['cancel_redirect'] = '/%(url_name)s/list' % params
132 new_params
['public_redirect'] = None
134 new_params
['sidebar'] = None
135 new_params
['sidebar_grouping'] = 'main'
136 new_params
['sidebar_defaults'] = [
137 ('/%s/create', 'New %(name)s', 'create'),
138 ('/%s/list', 'List %(name_plural)s', 'list'),
140 new_params
['sidebar_additional'] = []
142 names_sans_link_id
= [i
for i
in logic
.getKeyFieldNames() if i
!= 'link_id']
143 sans_link_id_pattern
= getPattern(names_sans_link_id
,
144 linkable
.SCOPE_PATH_ARG_PATTERN
)
146 new_params
['link_id_arg_pattern'] = linkable
.LINK_ID_ARG_PATTERN
147 new_params
['link_id_pattern_core'] = linkable
.LINK_ID_PATTERN_CORE
148 new_params
['scope_path_pattern'] = getScopePattern(params
)
149 new_params
['sans_link_id_pattern'] = sans_link_id_pattern
151 new_params
['django_patterns'] = None
152 new_params
['extra_django_patterns'] = []
153 new_params
['django_patterns_defaults'] = []
155 if not params
.get('no_edit'):
156 new_params
['django_patterns_defaults'] += [
157 (r
'^%(url_name)s/(?P<access_type>edit)/%(key_fields)s$',
158 'soc.views.models.%(module_name)s.edit', 'Edit %(name_short)s')]
160 if not params
.get('no_delete'):
161 new_params
['django_patterns_defaults'] += [
162 (r
'^%(url_name)s/(?P<access_type>delete)/%(key_fields)s$',
163 'soc.views.models.%(module_name)s.delete', 'Delete %(name_short)s')]
165 if not params
.get('no_show'):
166 new_params
['django_patterns_defaults'] += [
167 (r
'^%(url_name)s/(?P<access_type>show)/%(key_fields)s$',
168 'soc.views.models.%(module_name)s.public', 'Show %(name_short)s')]
170 if not params
.get('no_admin'):
171 new_params
['django_patterns_defaults'] += [
172 (r
'^%(url_name)s/(?P<access_type>admin)/%(key_fields)s$',
173 'soc.views.models.%(module_name)s.admin',
174 'Show %(name_short)s (admin)')]
176 if not params
.get('no_create_raw'):
177 new_params
['django_patterns_defaults'] += [
178 (r
'^%(url_name)s/(?P<access_type>create)$',
179 'soc.views.models.%(module_name)s.create', 'Create %(name_short)s')]
181 if not params
.get('no_create_with_scope'):
182 new_params
['django_patterns_defaults'] += [
183 (r
'^%(url_name)s/(?P<access_type>create)/%(scope)s$',
184 'soc.views.models.%(module_name)s.create', 'Create %(name_short)s')]
186 if not params
.get('no_create_with_key_fields'):
187 new_params
['django_patterns_defaults'] += [
188 (r
'^%(url_name)s/(?P<access_type>create)/%(key_fields)s$',
189 'soc.views.models.%(module_name)s.create', 'Create %(name_short)s')]
191 if not params
.get('no_list_raw'):
192 new_params
['django_patterns_defaults'] += [
193 (r
'^%(url_name)s/(?P<access_type>list)$',
194 'soc.views.models.%(module_name)s.list', 'List %(name_plural)s')]
196 if params
.get('pickable'):
197 new_params
['django_patterns_defaults'] += [
198 (r
'^%(url_name)s/(?P<access_type>pick)$',
199 'soc.views.models.%(module_name)s.pick', 'Pick %(name_short)s')]
201 if params
.get('export_content_type'):
202 new_params
['django_patterns_defaults'] += [
203 (r
'^%(url_name)s/(?P<access_type>export)/%(key_fields)s$',
204 'soc.views.models.%(module_name)s.export', 'Export %(name_short)s')]
206 if params
.get('sans_link_id_create'):
207 new_params
['django_patterns_defaults'] += [
208 (r
'^%(url_name)s/(?P<access_type>create)/%(sans_link_id)s$',
209 'soc.views.models.%(module_name)s.create', 'Create %(name_short)s')]
211 if params
.get('sans_link_id_list'):
212 new_params
['django_patterns_defaults'] += [
213 (r
'^%(url_name)s/(?P<access_type>list)/%(sans_link_id)s$',
214 'soc.views.models.%(module_name)s.list', 'List %(name_plural)s')]
216 if params
.get('sans_link_id_public_list'):
217 new_params
['django_patterns_defaults'] += [
218 (r
'^%(url_name)s/(?P<access_type>list_public)/%(sans_link_id)s$',
219 'soc.views.models.%(module_name)s.list_public',
220 'List %(name_plural)s')]
222 new_params
['public_template'] = 'soc/%(module_name)s/public.html' % params
223 new_params
['export_template'] = 'soc/export.html' % params
224 new_params
['create_template'] = 'soc/models/edit.html'
225 new_params
['edit_template'] = 'soc/models/edit.html'
226 new_params
['admin_template'] = 'soc/models/admin.html'
227 new_params
['list_template'] = 'soc/models/list.html'
228 new_params
['invite_template'] = 'soc/models/invite.html'
230 new_params
['context'] = None
232 new_params
['cache_pick'] = False
234 new_params
['export_content_type'] = None
235 new_params
['export_extension'] = '.txt'
236 new_params
['csv_fieldnames'] = []
238 # TODO: Use only the js modules needed instead of js_uses_all
239 new_params
['js_uses_all'] = DEF_JS_USES_LIST
240 new_params
['js_uses_list'] = ['jq', 'menu']
241 new_params
['js_uses_show'] = ['jq', 'menu']
242 new_params
['js_uses_edit'] = ['jq', 'menu', 'tinymce', 'jq_purr',
243 'jq_spin', 'jq_autocomplete']
245 new_params
['error_public'] = 'soc/%(module_name)s/error.html' % params
246 new_params
['error_export'] = new_params
['error_public']
247 new_params
['error_edit'] = new_params
['error_public']
249 new_params
['list_main'] = 'soc/list/main.html'
250 new_params
['list_pagination'] = 'soc/list/pagination.html'
251 new_params
['list_row'] = 'soc/%(module_name)s/list/row.html' % params
252 new_params
['list_heading'] = 'soc/%(module_name)s/list/heading.html' % params
254 new_params
['list_action'] = (redirects
.getEditRedirect
, params
)
255 new_params
['list_params'] = {
256 'list_action': 'action',
257 'list_description': 'description',
259 'list_key_order': 'key_order',
261 'list_pagination': 'pagination',
263 'list_heading': 'heading',
266 new_params
['list_description'] = DEF_LIST_DESCRIPTION_FMT
% params
267 new_params
['no_lists_msg'] = ""
268 new_params
['save_message'] = [ugettext('%(name)s saved.' % params
),
269 ugettext('Cannot delete %(name)s.' % params
)]
270 new_params
['submit_msg_param_name'] = DEF_SUBMIT_MSG_PARAM_NAME
271 new_params
['edit_params'] = {
272 DEF_SUBMIT_MSG_PARAM_NAME
: DEF_SUBMIT_MSG_PROFILE_SAVED
,
275 new_params
['cannot_delete_params'] = {
276 DEF_SUBMIT_MSG_PARAM_NAME
: DEF_SUBMIT_MSG_CANNOT_DELETE_ENTITY
,
279 new_params
['dynabase'] = helper
.forms
.BaseForm
281 create_dynaproperties
= {
282 'clean_link_id': cleaning
.clean_link_id('link_id'),
283 'clean_feed_url': cleaning
.clean_feed_url
,
285 create_dynaproperties
.update(params
.get('create_extra_dynaproperties', {}))
287 # dynafields override any dynaproperties
288 create_dynafields
= getDynaFields(params
.get('create_dynafields', {}))
289 create_dynaproperties
= dicts
.merge(create_dynafields
, create_dynaproperties
)
291 new_params
['references'] = []
292 new_params
['create_dynainclude'] = [] + params
.get('extra_dynainclude', [])
293 new_params
['create_dynaexclude'] = ['scope', 'scope_path'] + \
294 params
.get('extra_dynaexclude', [])
295 new_params
['create_dynaproperties'] = create_dynaproperties
297 edit_dynaproperties
= {
298 'clean_link_id': cleaning
.clean_link_id('link_id'),
299 'link_id': forms
.CharField(widget
=helper
.widgets
.ReadOnlyInput()),
301 edit_dynaproperties
.update(params
.get('edit_extra_dynaproperties', {}))
303 # dynafields override any dynaproperties
304 edit_dynafields
= getDynaFields(params
.get('edit_dynafields', {}))
305 edit_dynaproperties
= dicts
.merge(edit_dynafields
, edit_dynaproperties
)
307 new_params
['edit_dynainclude'] = None
308 new_params
['edit_dynaexclude'] = None
309 new_params
['edit_dynaproperties'] = edit_dynaproperties
310 new_params
['list_msg'] = None
312 params
= dicts
.merge(params
, new_params
)
314 # These need to be constructed separately, because they require
315 # parameters that can be defined either in params, or new_params.
316 if not 'create_form' in params
:
317 params
['create_form'] = getCreateForm(params
, logic
.getModel())
319 if not 'edit_form' in params
:
320 params
['edit_form'] = getEditForm(params
, params
['create_form'])
322 if not 'admin_form' in params
:
323 params
['admin_form'] = getAdminForm(params
['edit_form'])
325 if not 'key_fields_pattern' in params
:
326 params
['key_fields_pattern'] = getKeyFieldsPattern(params
)
328 # merge already done by access.Checker
329 params
['rights'] = rights
334 def getDynaFields(fields
):
335 """Constructs a new DynaField using params.
338 params: the params dictionary used to extract the dyanfields
339 param_name: the name of the parameter to use
344 # generate the dynafields
346 base
= field
.pop('base')
347 name
= field
.pop('name')
348 passthrough
= field
.pop('passthrough', DEF_FIELD_INIT_PARAMS
)
350 dynafield
= dynaform
.newDynaField(field
, base
, passthrough
)
351 dynafields
[name
] = dynafield()
356 def getCreateForm(params
, model
):
357 """Constructs a new CreateForm using params.
360 dynabase: The dynabase value is used as the base argument to
361 dynaform.newDynaForm.
362 logic: The logic value is used to get the model argument to newDynaForm.
363 create_dynainclude: same as dynabase, but as dynainclude argument
364 create_dynaexclude: same as dynabase, but as dynaexclude argument
365 create_dynaproperties: same as dynabase, but as dynaproperties argument
368 create_form
= dynaform
.newDynaForm(
369 dynabase
= params
['dynabase'],
371 dynainclude
= params
['create_dynainclude'],
372 dynaexclude
= params
['create_dynaexclude'],
373 dynaproperties
= params
['create_dynaproperties'],
376 if 'extra_key_order' in params
:
377 for field
in params
['extra_key_order']:
378 if field
in create_form
.base_fields
.keyOrder
:
379 create_form
.base_fields
.keyOrder
.remove(field
)
380 create_form
.base_fields
.keyOrder
.extend(params
['extra_key_order'])
385 def getEditForm(params
, base_form
):
386 """Constructs a new EditForm using params.
389 create_form: The dynabase value is used as the dynaform argument
390 to dyanform.extendDynaForm.
391 edit_dynainclude: same as create_form, but as dynainclude argument
392 edit_dynaexclude: same as create_form, but as dynaexclude argument
393 edit_dynaproperties: same as create_form, but as dynaproperties argument
396 edit_form
= dynaform
.extendDynaForm(
397 dynaform
= base_form
,
398 dynainclude
= params
['edit_dynainclude'],
399 dynaexclude
= params
['edit_dynaexclude'],
400 dynaproperties
= params
['edit_dynaproperties'],
406 def getAdminForm(base_form
):
407 """Constructs a new AdminForm from base_form.
410 # extend _and_ deepcopy the base_fields to do a proper copy
411 admin_form
= dynaform
.extendDynaForm(dynaform
= base_form
)
412 admin_form
.base_fields
= copy
.deepcopy(admin_form
.base_fields
)
414 # replace all widgets with PTW's
415 for _
, value
in admin_form
.base_fields
.iteritems():
416 if not isinstance(value
, forms
.fields
.Field
):
419 value
.widget
= widgets
.PlainTextWidget()
424 def getKeyFieldsPattern(params
):
425 """Returns the Django pattern for this View's entity.
428 names
= params
['logic'].getKeyFieldNames()
429 scope_path_pattern
= params
['scope_path_pattern']
431 return getPattern(names
, scope_path_pattern
)
434 def getPattern(names
, scope_path_pattern
):
435 """Returns the Django patterns for the specified names.
438 names: the field names that should be included in the pattern
439 scope_path_pattern: the pattern to use if the name is 'scope_path'
445 if name
== 'scope_path':
446 pattern
= scope_path_pattern
448 pattern
= r
'(?P<%s>%s)' % (name
, linkable
.LINK_ID_PATTERN_CORE
)
449 patterns
.append(pattern
)
451 result
= '/'.join(patterns
)
455 def getScopePattern(params
):
456 """Returns the Scope pattern for this entity.
459 logic
= params
['logic']
460 depth
= logic
.getScopeDepth()
462 return linkable
.SCOPE_PATH_ARG_PATTERN
464 regexps
= [linkable
.LINK_ID_PATTERN_CORE
for _
in range(depth
)]
465 regexp
= '/'.join(regexps
)
466 return r
'(?P<scope_path>%s)' % regexp