1
# -*- coding: iso-8859-1 -*-
3
MoinMoin - Preferences Form
5
@copyright: 2001-2004 Juergen Hermann <jh@web.de>,
6
2003-2007 MoinMoin:ThomasWaldmann
7
@license: GNU GPL, see COPYING for details.
11
from MoinMoin import user, util, wikiutil, events
12
from MoinMoin.widget import html
13
from MoinMoin.userprefs import UserPrefBase
16
#################################################################
17
# This is still a mess.
19
# The plan for refactoring would be:
20
# split the plugin into multiple preferences pages:
21
# - account details (name, email, timezone, ...)
22
# - wiki settings (editor, fancy diffs, theme, ...)
23
# - quick links (or leave in wiki settings?)
29
class Settings(UserPrefBase):
30
def __init__(self, request):
31
""" Initialize user settings form. """
32
UserPrefBase.__init__(self, request)
33
self.request = request
34
self._ = request.getText
35
self.cfg = request.cfg
37
self.title = _("Preferences")
40
def _decode_pagelist(self, key):
41
""" Decode list of pages from form input
43
Each line is a page name, empty lines ignored.
45
@param key: the form key to get
46
@rtype: list of unicode strings
47
@return: list of normalized names
49
text = self.request.form.get(key, [''])[0]
50
text = text.replace('\r', '')
52
for item in text.split('\n'):
59
def _save_user_prefs(self):
61
form = self.request.form
62
request = self.request
64
if request.request_method != 'POST':
67
if not 'name' in request.user.auth_attribs:
68
# Require non-empty name
69
new_name = form.get('name', [request.user.name])[0]
71
# Don't allow changing the name to an invalid one
72
if not user.isValidName(request, new_name):
73
return 'error', _("""Invalid user name {{{'%s'}}}.
74
Name may contain any Unicode alpha numeric character, with optional one
75
space between words. Group page name is not allowed.""", wiki=True) % wikiutil.escape(new_name)
77
# Is this an existing user trying to change information or a new user?
78
# Name required to be unique. Check if name belong to another user.
79
existing_id = user.getUserId(request, new_name)
80
if existing_id is not None and existing_id != request.user.id:
81
return 'error', _("This user name already belongs to somebody else.")
84
return 'error', _("Empty user name. Please enter a user name.")
86
# done sanity checking the name, set it
87
request.user.name = new_name
90
if not 'email' in request.user.auth_attribs:
91
# try to get the email
92
new_email = wikiutil.clean_input(form.get('email', [request.user.email])[0])
93
new_email = new_email.strip()
96
if not new_email and 'email' not in request.cfg.user_form_remove:
97
return 'error', _("Please provide your email address. If you lose your"
98
" login information, you can get it by email.")
100
# Email should be unique - see also MoinMoin/script/accounts/moin_usercheck.py
101
if new_email and request.cfg.user_email_unique:
102
other = user.get_by_email_address(request, new_email)
103
if other is not None and other.id != request.user.id:
104
return 'error', _("This email already belongs to somebody else.")
106
# done checking the email, set it
107
request.user.email = new_email
110
if not 'jid' in request.user.auth_attribs:
112
new_jid = wikiutil.clean_input(form.get('jid', [''])[0]).strip()
114
jid_changed = request.user.jid != new_jid
115
previous_jid = request.user.jid
117
if new_jid and request.cfg.user_jid_unique:
118
other = user.get_by_jabber_id(request, new_jid)
119
if other is not None and other.id != request.user.id:
120
return 'error', _("This jabber id already belongs to somebody else.")
123
set_event = events.JabberIDSetEvent(request, new_jid)
124
unset_event = events.JabberIDUnsetEvent(request, previous_jid)
125
events.send_event(unset_event)
126
events.send_event(set_event)
128
# done checking the JID, set it
129
request.user.jid = new_jid
132
if not 'aliasname' in request.user.auth_attribs:
134
request.user.aliasname = wikiutil.clean_input(form.get('aliasname', [''])[0])
137
request.user.edit_rows = util.web.getIntegerInput(request, 'edit_rows',
138
request.user.edit_rows, 10, 60)
140
# try to get the editor
141
request.user.editor_default = form.get('editor_default', [self.cfg.editor_default])[0]
142
request.user.editor_ui = form.get('editor_ui', [self.cfg.editor_ui])[0]
145
request.user.tz_offset = util.web.getIntegerInput(request, 'tz_offset',
146
request.user.tz_offset, -84600, 84600)
150
dt_d_combined = Settings._date_formats.get(form['datetime_fmt'][0], '')
151
request.user.datetime_fmt, request.user.date_fmt = dt_d_combined.split(' & ')
152
except (KeyError, ValueError):
153
request.user.datetime_fmt = '' # default
154
request.user.date_fmt = '' # default
156
# try to get the (optional) theme
157
theme_name = form.get('theme_name', [self.cfg.theme_default])[0]
158
if theme_name != request.user.theme_name:
159
# if the theme has changed, load the new theme
160
# so the user has a direct feedback
161
# WARNING: this should be refactored (i.e. theme load
162
# after userform handling), cause currently the
163
# already loaded theme is just replaced (works cause
164
# nothing has been emitted yet)
165
request.user.theme_name = theme_name
166
if request.loadTheme(theme_name) > 0:
167
theme_name = wikiutil.escape(theme_name)
168
return 'error', _("The theme '%(theme_name)s' could not be loaded!") % locals()
170
# try to get the (optional) preferred language
171
request.user.language = form.get('language', [''])[0]
172
if request.user.language == u'': # For language-statistics
173
from MoinMoin import i18n
174
request.user.real_language = i18n.get_browser_language(request)
176
request.user.real_language = ''
178
# I want to handle all inputs from user_form_fields, but
179
# don't want to handle the cases that have already been coded
181
# This is a horribly fragile kludge that's begging to break.
182
# Something that might work better would be to define a
183
# handler for each form field, instead of stuffing them all in
184
# one long and inextensible method. That would allow for
185
# plugins to provide methods to validate their fields as well.
186
already_handled = ['name', 'email',
187
'aliasname', 'edit_rows', 'editor_default',
188
'editor_ui', 'tz_offset', 'datetime_fmt',
189
'theme_name', 'language', 'real_language', 'jid']
190
for field in self.cfg.user_form_fields:
192
if ((key in self.cfg.user_form_disable)
193
or (key in already_handled)):
195
default = self.cfg.user_form_defaults[key]
196
value = form.get(key, [default])[0]
197
setattr(request.user, key, value)
200
for key, label in self.cfg.user_checkbox_fields:
201
if key not in self.cfg.user_checkbox_disable and key not in self.cfg.user_checkbox_remove:
202
value = form.get(key, ["0"])[0]
208
setattr(request.user, key, value)
210
# quicklinks for navibar
211
request.user.quicklinks = self._decode_pagelist('quicklinks')
215
if request.user.disabled:
216
# set valid to false so the current request won't
217
# show the user as logged-in any more
218
request.user.valid = False
220
result = _("User preferences saved!")
222
result = result + util.dumpFormData(form)
226
def handle_form(self):
228
form = self.request.form
230
if form.has_key('cancel'):
233
if form.has_key('save'): # Save user profile
234
return self._save_user_prefs()
236
# form generation part
238
_date_formats = { # datetime_fmt & date_fmt
239
'iso': '%Y-%m-%d %H:%M:%S & %Y-%m-%d',
240
'us': '%m/%d/%Y %I:%M:%S %p & %m/%d/%Y',
241
'euro': '%d.%m.%Y %H:%M:%S & %d.%m.%Y',
242
'rfc': '%a %b %d %H:%M:%S %Y & %a %b %d %Y',
245
def _tz_select(self):
246
""" Create time zone selection. """
248
if self.request.user.valid:
249
tz = int(self.request.user.tz_offset)
253
for halfhour in range(-47, 48):
254
offset = halfhour * 1800
260
time.strftime(self.cfg.datetime_fmt, util.timefuncs.tmtuple(t)),
262
"%02d" % (abs(offset) / 3600),
263
"%02d" % (abs(offset) % 3600 / 60),
267
return util.web.makeSelection('tz_offset', options, str(tz))
270
def _dtfmt_select(self):
271
""" Create date format selection. """
274
dt_d_combined = '%s & %s' % (self.request.user.datetime_fmt, self.request.user.date_fmt)
276
k for k, v in self._date_formats.items()
277
if v == dt_d_combined][0]
280
options = [('', _('Default'))] + self._date_formats.items()
282
return util.web.makeSelection('datetime_fmt', options, selected)
285
def _lang_select(self):
286
""" Create language selection. """
287
from MoinMoin import i18n
289
cur_lang = self.request.user.valid and self.request.user.language or ''
290
langs = i18n.wikiLanguages().items()
291
langs.sort(lambda x, y: cmp(x[1]['x-language'], y[1]['x-language']))
292
options = [('', _('<Browser setting>'))]
294
name = lang[1]['x-language']
295
options.append((lang[0], name))
297
return util.web.makeSelection('language', options, cur_lang)
299
def _theme_select(self):
300
""" Create theme selection. """
301
cur_theme = self.request.user.valid and self.request.user.theme_name or self.cfg.theme_default
302
options = [("<default>", "<%s>" % self._("Default"))]
303
for theme in wikiutil.getPlugins('theme', self.request.cfg):
304
options.append((theme, theme))
306
return util.web.makeSelection('theme_name', options, cur_theme)
308
def _editor_default_select(self):
309
""" Create editor selection. """
310
editor_default = self.request.user.valid and self.request.user.editor_default or self.cfg.editor_default
311
options = [("<default>", "<%s>" % self._("Default"))]
312
for editor in ['text', 'gui', ]:
313
options.append((editor, editor))
314
return util.web.makeSelection('editor_default', options, editor_default)
316
def _editor_ui_select(self):
317
""" Create editor selection. """
318
editor_ui = self.request.user.valid and self.request.user.editor_ui or self.cfg.editor_ui
319
options = [("<default>", "<%s>" % self._("Default")),
320
("theonepreferred", self._("the one preferred")),
321
("freechoice", self._("free choice")),
323
return util.web.makeSelection('editor_ui', options, editor_ui)
326
def create_form(self):
327
""" Create the complete HTML form code. """
329
request = self.request
330
self._form = self.make_form()
332
if request.user.valid:
333
buttons = [('save', _('Save')), ('cancel', _('Cancel')), ]
334
uf_remove = self.cfg.user_form_remove
335
uf_disable = self.cfg.user_form_disable
336
for attr in request.user.auth_attribs:
337
uf_disable.append(attr)
338
for key, label, type, length, textafter in self.cfg.user_form_fields:
339
default = self.cfg.user_form_defaults[key]
340
if not key in uf_remove:
341
if key in uf_disable:
342
self.make_row(_(label),
343
[html.INPUT(type=type, size=length, name=key, disabled="disabled",
344
value=getattr(request.user, key)), ' ', _(textafter), ])
346
self.make_row(_(label),
347
[html.INPUT(type=type, size=length, name=key, value=getattr(request.user, key)), ' ', _(textafter), ])
349
if not self.cfg.theme_force and not "theme_name" in self.cfg.user_form_remove:
350
self.make_row(_('Preferred theme'), [self._theme_select()])
352
if not self.cfg.editor_force:
353
if not "editor_default" in self.cfg.user_form_remove:
354
self.make_row(_('Editor Preference'), [self._editor_default_select()])
355
if not "editor_ui" in self.cfg.user_form_remove:
356
self.make_row(_('Editor shown on UI'), [self._editor_ui_select()])
358
if not "tz_offset" in self.cfg.user_form_remove:
359
self.make_row(_('Time zone'), [
360
_('Your time is'), ' ',
363
_('Server time is'), ' ',
364
time.strftime(self.cfg.datetime_fmt, util.timefuncs.tmtuple()),
368
if not "datetime_fmt" in self.cfg.user_form_remove:
369
self.make_row(_('Date format'), [self._dtfmt_select()])
371
if not "language" in self.cfg.user_form_remove:
372
self.make_row(_('Preferred language'), [self._lang_select()])
374
# boolean user options
376
checkbox_fields = self.cfg.user_checkbox_fields
377
checkbox_fields.sort(lambda a, b: cmp(a[1](_), b[1](_)))
378
for key, label in checkbox_fields:
379
if not key in self.cfg.user_checkbox_remove:
380
bool_options.extend([
381
html.INPUT(type="checkbox", name=key, value="1",
382
checked=getattr(request.user, key, 0),
383
disabled=key in self.cfg.user_checkbox_disable and True or None),
384
' ', label(_), html.BR(),
386
self.make_row(_('General options'), bool_options, valign="top")
388
self.make_row(_('Quick links'), [
389
html.TEXTAREA(name="quicklinks", rows="6", cols="50")
390
.append('\n'.join(request.user.getQuickLinks())),
393
self._form.append(html.INPUT(type="hidden", name="action", value="userprefs"))
394
self._form.append(html.INPUT(type="hidden", name="handler", value="prefs"))
398
for name, label in buttons:
399
if not name in self.cfg.user_form_remove:
401
html.INPUT(type="submit", name=name, value=label),
404
self.make_row('', button_cell)
406
return unicode(self._form)