modinfo in the translate toolkit is now a 2-tuple containing the mtime and
[pootle.git] / users.py
blob568c42076f3bac78982815006c4eebd956363a76
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3 #
4 # Copyright 2004-2006 Zuza Software Foundation
5 #
6 # This file is part of translate.
8 # translate is free software; you can redistribute it and/or modify
9 # it under the terms of the GNU General Public License as published by
10 # the Free Software Foundation; either version 2 of the License, or
11 # (at your option) any later version.
13 # translate is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 # GNU General Public License for more details.
18 # You should have received a copy of the GNU General Public License
19 # along with translate; if not, write to the Free Software
20 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 from jToolkit import web
23 from jToolkit.web import server
24 from jToolkit import mailer
25 from jToolkit import prefs
26 from Pootle import pagelayout
27 from translate.lang import data as langdata
28 from translate.lang import factory
29 from email.Header import Header
30 import locale
32 class RegistrationError(ValueError):
33 def __init__(self, message):
34 message = message.encode('utf-8')
35 ValueError.__init__(self, message)
37 # This mimimum passwordlength is mandated by the interface when registering or
38 # changing password
39 minpasswordlen = 6
41 def validatepassword(session, password, passwordconfirm):
42 if not password or len(password) < minpasswordlen:
43 raise RegistrationError(session.localize("You must supply a valid password of at least %d characters.", minpasswordlen))
44 if not password == passwordconfirm:
45 raise RegistrationError(session.localize("The password is not the same as the confirmation."))
47 def forcemessage(message):
48 """Tries to extract some kind of message and converts to unicode"""
49 if message and not isinstance(message, unicode):
50 return str(message).decode('utf-8')
51 else:
52 return message
54 class LoginPage(pagelayout.PootlePage):
55 """wraps the normal login page in a PootlePage layout"""
56 def __init__(self, session, languagenames=None, message=None):
57 self.localize = session.localize
58 self.tr_lang = session.tr_lang
59 self.languagenames = languagenames
60 pagetitle = self.localize("Login to Pootle")
61 templatename = "login"
62 message = forcemessage(message)
63 instancetitle = getattr(session.instance, "title", session.localize("Pootle Demo"))
64 sessionvars = {"status": session.status, "isopen": session.isopen, "issiteadmin": session.issiteadmin()}
65 templatevars = {"pagetitle": pagetitle, "introtext": message,
66 "username_title": self.localize("Username:"),
67 "username": getattr(session, 'username', ''),
68 "password_title": self.localize("Password:"),
69 "language_title": self.localize('Language:'),
70 "languages": self.getlanguageoptions(session),
71 "login_text": self.localize('Login'),
72 "session": sessionvars, "instancetitle": instancetitle}
73 pagelayout.PootlePage.__init__(self, templatename, templatevars, session)
75 def getlanguageoptions(self, session):
76 """returns the language selector..."""
77 tr_default = session.localize("Default")
78 if tr_default != "Default":
79 tr_default = u"%s | \u202dDefault" % tr_default
80 languageoptions = [('', tr_default)]
81 if isinstance(self.languagenames, dict):
82 languageoptions += self.languagenames.items()
83 else:
84 languageoptions += self.languagenames
85 if session.language in ["en", session.server.defaultlanguage]:
86 preferredlanguage = ""
87 else:
88 preferredlanguage = session.language
89 finallist = []
90 for key, value in languageoptions:
91 if key == 'templates':
92 continue
93 tr_name = session.tr_lang(value)
94 if tr_name != value:
95 # We have to use the LRO (left-to-right override) to ensure that
96 # brackets in the English part of the name is rendered correctly
97 # in an RTL layout like Arabic. We can't use markup because this
98 # is used inside an option tag.
99 value = u"%s | \u202d%s" % (tr_name, value)
100 selected = key==preferredlanguage or None
101 finallist.append({"code": key, "name": value, "selected": selected})
102 # rewritten for compatibility with Python 2.3
103 # finallist.sort(cmp=locale.strcoll, key=lambda dict: dict["name"])
104 finallist.sort(lambda x,y: locale.strcoll(x["name"], y["name"]))
105 return finallist
107 class RegisterPage(pagelayout.PootlePage):
108 """page for new registrations"""
109 def __init__(self, session, argdict, message=None):
110 self.localize = session.localize
111 if not message:
112 introtext = self.localize("Please enter your registration details")
113 else:
114 introtext = forcemessage(message)
115 pagetitle = self.localize("Pootle Registration")
116 self.argdict = argdict
117 templatename = "register"
118 instancetitle = getattr(session.instance, "title", session.localize("Pootle Demo"))
119 sessionvars = {"status": session.status, "isopen": session.isopen, "issiteadmin": session.issiteadmin()}
120 templatevars = {"pagetitle": pagetitle, "introtext": introtext,
121 "username_title": self.localize("Username"),
122 "username_tooltip": self.localize("Your requested username"),
123 "username": self.argdict.get("username", ""),
124 "email_title": self.localize("Email Address"),
125 "email_tooltip": self.localize("You must supply a valid email address"),
126 "email": self.argdict.get("email", ""),
127 "fullname_title": self.localize("Full Name"),
128 "fullname_tooltip": self.localize("Your full name"),
129 "fullname": self.argdict.get("name", ""),
130 "password_title": self.localize("Password"),
131 "password_tooltip": self.localize("Your desired password"),
132 "password": self.argdict.get("password", ""),
133 "passwordconfirm_title": self.localize("Confirm password"),
134 "passwordconfirm_tooltip": self.localize("Type your password again to ensure it is entered correctly"),
135 "passwordconfirm": self.argdict.get("passwordconfirm", ""),
136 "register_text": self.localize('Register Account'),
137 "session": sessionvars, "instancetitle": instancetitle}
138 pagelayout.PootlePage.__init__(self, templatename, templatevars, session)
140 class ActivatePage(pagelayout.PootlePage):
141 """page for new registrations"""
142 def __init__(self, session, argdict, title=None, message=None):
143 self.localize = session.localize
144 if not message:
145 introtext = self.localize("Please enter your activation details")
146 else:
147 introtext = forcemessage(message)
148 self.argdict = argdict
149 if title is None:
150 pagetitle = self.localize("Pootle Account Activation")
151 else:
152 pagetitle = title
153 templatename = "activate"
154 instancetitle = getattr(session.instance, "title", session.localize("Pootle Demo"))
155 sessionvars = {"status": session.status, "isopen": session.isopen, "issiteadmin": session.issiteadmin()}
156 templatevars = {"pagetitle": pagetitle, "introtext": introtext,
157 "username_title": self.localize("Username"),
158 "username_tooltip": self.localize("Your requested username"),
159 "username": self.argdict.get("username", ""),
160 "code_title": self.localize("Activation Code"),
161 "code_tooltip": self.localize("The activation code you received"),
162 "code": self.argdict.get("activationcode", ""),
163 "activate_text": self.localize('Activate Account'),
164 "session": sessionvars, "instancetitle": instancetitle}
165 pagelayout.PootlePage.__init__(self, templatename, templatevars, session)
167 class UserOptions(pagelayout.PootlePage):
168 """page for user to change their options"""
169 def __init__(self, potree, session, message=None):
170 self.potree = potree
171 self.session = session
172 self.localize = session.localize
173 self.tr_lang = session.tr_lang
174 message = forcemessage(message)
175 pagetitle = self.localize("Options for: %s", session.username)
176 templatename = "options"
177 instancetitle = getattr(session.instance, "title", session.localize("Pootle Demo"))
178 enablealtsrc = getattr(session.instance, "enablealtsrc", False)
179 sessionvars = {"status": session.status, "isopen": session.isopen, "issiteadmin": session.issiteadmin()}
180 templatevars = {"pagetitle": pagetitle, "introtext": message,
181 "detailstitle": self.localize("Personal Details"),
182 "option_heading": self.localize("Option"),
183 "value_heading": self.localize("Current value"),
184 "fullname_title": self.localize("Name"),
185 "fullname": self.session.prefs.name,
186 "email_title": self.localize("Email"),
187 "email": self.session.prefs.email,
188 "password_title": self.localize("Password"),
189 "passwordconfirm_title": self.localize("Confirm password"),
190 "interface_title": self.localize("Translation Interface Configuration"),
191 "uilanguage_heading": self.localize("User Interface language"),
192 "projects_title": self.localize("My Projects"),
193 "projects": self.getprojectoptions(),
194 "languages_title": self.localize("My Languages"),
195 "languages": self.getlanguageoptions(),
196 "home_link": self.localize("Home page"),
197 "submit_button": self.localize("Save changes"),
198 "session": sessionvars,
199 "instancetitle": instancetitle,
200 "enablealtsrc": enablealtsrc}
201 if enablealtsrc == 'True':
202 templatevars["altsrclanguage_title"] = self.localize("Alternative Source Language")
203 templatevars["altsrclanguages"] = self.getaltsrcoptions()
204 otheroptions = self.getotheroptions()
205 templatevars.update(otheroptions)
206 pagelayout.PootlePage.__init__(self, templatename, templatevars, session)
208 def getprojectoptions(self):
209 """gets the options box to change the user's projects"""
210 projectoptions = []
211 userprojects = self.session.getprojects()
212 for projectcode in self.potree.getprojectcodes():
213 projectname = self.potree.getprojectname(projectcode)
214 projectoptions.append({"code": projectcode, "name": projectname, "selected": projectcode in userprojects or None})
215 return projectoptions
217 def getlanguageoptions(self):
218 """returns options for languages"""
219 userlanguages = self.session.getlanguages()
220 languageoptions = self.potree.getlanguages()
221 languages = []
222 for language, name in languageoptions:
223 languages.append({"code": language, "name": self.tr_lang(name), "selected": language in userlanguages or None})
224 # rewritten for compatibility with Python 2.3
225 # languages.sort(cmp=locale.strcoll, key=lambda dict: dict["name"])
226 languages.sort(lambda x,y: locale.strcoll(x["name"], y["name"]))
227 return languages
229 def getaltsrcoptions(self):
230 """returns options for alternative source languages"""
231 useraltsrc = self.session.getaltsrclanguage()
232 languageoptions = self.potree.getlanguages()
233 altsrclanguages = []
234 for language, name in languageoptions:
235 altsrclanguages.append({"code": language, "name": self.tr_lang(name), "selected": language in useraltsrc and 'selected' or None})
236 # rewritten for compatibility with Python 2.3
237 # altsrclanguages.sort(cmp=locale.strcoll, key=lambda dict: dict["name"])
238 altsrclanguages.sort(lambda x,y: locale.strcoll(x["name"], y["name"]))
239 # l10n: 'None' is displayed as the first item in the alternative source languages list and disables the feature.
240 altsrclanguages.insert(0, {"code": '', "name": self.session.localize("None"), "selected": '' in useraltsrc and 'selected' or None})
241 return altsrclanguages
243 def getotheroptions(self):
244 uilanguage = getattr(self.session.prefs, "uilanguage", "")
245 if not uilanguage:
246 userlanguages = self.session.getlanguages()
247 if userlanguages:
248 uilanguage = userlanguages[0]
249 languageoptions = [{"code": '', "name": ''}]
250 for code, name in self.potree.getlanguages():
251 if code == "templates":
252 continue
253 languageoptions.append({"code": code, "name": self.tr_lang(name), "selected": uilanguage == code or None})
254 # rewritten for compatibility with Python 2.3
255 # languageoptions.sort(cmp=locale.strcoll, key=lambda dict: dict["name"])
256 languageoptions.sort(lambda x,y: locale.strcoll(x["name"], y["name"]))
257 options = {"inputheight": self.localize("Input Height (in lines)"),
258 "viewrows": self.localize("Number of rows in view mode"),
259 "translaterows": self.localize("Number of rows in translate mode")}
260 optionlist = []
261 for option, description in options.items():
262 optionvalue = getattr(self.session.prefs, option, "")
263 optionlist.append({"code": option, "description": description, "value": optionvalue})
264 return {"uilanguage": uilanguage, "uilanguage_options": languageoptions, "other_options": optionlist}
266 class OptionalLoginAppServer(server.LoginAppServer):
267 """a server that enables login but doesn't require it except for specified pages"""
268 def handle(self, req, pathwords, argdict):
269 """handles the request and returns a page object in response"""
270 session = None
271 try:
272 argdict = self.processargs(argdict)
273 session = self.getsession(req, argdict)
274 if session.isopen:
275 session.pagecount += 1
276 session.remote_ip = self.getremoteip(req)
277 else:
278 self.initlanguage(req, session)
279 page = self.getpage(pathwords, session, argdict)
280 except Exception, e:
281 # Because of the exception, 'session' might not be initialised. So let's
282 # play extra safe
283 if not session:
284 raise Exception("Could not initialise session.\nDetail:%s" % str(e))
286 exceptionstr = self.errorhandler.exception_str()
287 errormessage = str(e).decode("utf-8")
288 traceback = self.errorhandler.traceback_str().decode('utf-8')
289 browsertraceback = ""
290 options = getattr(self, "options", None)
291 # with unit tests we might not have self.options, therefore this test
292 if options:
293 if options.browsererrors == 'traceback':
294 browsertraceback = traceback
295 if options.logerrors == 'traceback':
296 self.errorhandler.logerror(traceback)
297 elif options.logerrors == 'exception':
298 self.errorhandler.logerror(exceptionstr)
299 elif options.logerrors == 'message':
300 self.errorhandler.logerror(errormessage)
301 else:
302 self.errorhandler.logerror(traceback)
304 refreshurl = req.headers_in.getheader('Referer') or "/"
305 templatename = "error"
306 templatevars = {
307 "pagetitle": session.localize("Error"),
308 "refresh": 30,
309 "refreshurl": refreshurl,
310 "message": errormessage,
311 "traceback": browsertraceback,
312 "back": session.localize("Back"),
314 pagelayout.completetemplatevars(templatevars, session)
315 page = server.Redirect(refreshurl, withtemplate=(templatename, templatevars))
316 return page
318 def initlanguage(self, req, session):
319 """Initialises the session language from the request"""
320 # This version doesn't know which languages we have, so we have to override
321 # in PootleServer.
322 session.setlanguage("en")
324 def hasuser(self, users, username):
325 """returns whether the user exists in users"""
326 return users.__hasattr__(username)
328 def getusernode(self, users, username):
329 """gets the node for the given user"""
330 if not self.hasuser(users, username):
331 usernode = prefs.PrefNode(users, username)
332 users.__setattr__(username, usernode)
333 else:
334 usernode = users.__getattr__(username)
335 return usernode
337 def adduser(self, users, username, fullname, email, password):
338 """adds the user with the given details"""
339 usernode = self.getusernode(users, username)
340 usernode.name = fullname
341 usernode.email = email
342 usernode.passwdhash = web.session.md5hexdigest(password)
344 def makeactivationcode(self, users, username):
345 """makes a new activation code for the user and returns it"""
346 usernode = self.getusernode(users, username)
347 usernode.activated = 0
348 activationcode = self.generateactivationcode()
349 usernode.activationcode = activationcode
350 return activationcode
352 def activate(self, users, username):
353 """sets the user as activated"""
354 self.getusernode(users, username).activated = 1
356 def changeusers(self, session, argdict):
357 """handles multiple changes from the site admin"""
358 if not session.issiteadmin():
359 raise ValueError(session.localize("You need to be siteadmin to change users"))
360 users = session.loginchecker.users
361 for key, value in argdict.iteritems():
362 if key.startswith("userremove-"):
363 usercode = key.replace("userremove-", "", 1)
364 if self.hasuser(users, usercode):
365 raise NotImplementedError("Can't remove users")
366 elif key.startswith("username-"):
367 username = key.replace("username-", "", 1)
368 if self.hasuser(users, username):
369 usernode = self.getusernode(users, username)
370 fullname = getattr(usernode, "name", None)
371 if fullname != value:
372 usernode.name = value
373 elif key.startswith("useremail-"):
374 username = key.replace("useremail-", "", 1)
375 if self.hasuser(users, username):
376 usernode = self.getusernode(users, username)
377 useremail = getattr(usernode, "email", None)
378 if useremail != value:
379 usernode.email = value
380 elif key.startswith("userpassword-"):
381 username = key.replace("userpassword-", "", 1)
382 if self.hasuser(users, username):
383 usernode = self.getusernode(users, username)
384 if value and value.strip():
385 usernode.passwdhash = web.session.md5hexdigest(value.strip())
386 elif key.startswith("useractivated-"):
387 username = key.replace("useractivated-", "", 1)
388 self.activate(users, username)
389 elif key == "newusername":
390 username = value.lower()
391 if not username:
392 continue
393 if not (username[:1].isalpha() and username.replace("_","").isalnum()):
394 raise ValueError("Login must be alphanumeric and start with an alphabetic character (got %r)" % username)
395 if username in ["nobody", "default"]:
396 raise ValueError('"%s" is a reserved username.' % username)
397 if self.hasuser(users, username):
398 raise ValueError("Already have user with the login: %s" % username)
399 userpassword = argdict.get("newuserpassword", None)
400 if userpassword is None or userpassword == session.localize("(add password here)"):
401 raise ValueError("You must specify a password")
402 userfullname = argdict.get("newuserfullname", None)
403 if userfullname == session.localize("(add full name here)"):
404 raise ValueError("Please set the users full name or leave it blank")
405 useremail = argdict.get("newuseremail", None)
406 if useremail == session.localize("(add email here)"):
407 raise ValueError("Please set the users email address or leave it blank")
408 useractivate = "newuseractivate" in argdict
409 self.adduser(users, username, userfullname, useremail, userpassword)
410 if useractivate:
411 self.activate(users, username)
412 else:
413 activationcode = self.makeactivationcode(users, username)
414 print "user activation code for %s is %s" % (username, activationcode)
415 session.saveprefs()
417 def handleregistration(self, session, argdict):
418 """handles the actual registration"""
419 #TODO: Fix layout, punctuation, spacing and correlation of messages
420 supportaddress = getattr(self.instance.registration, 'supportaddress', "")
421 username = argdict.get("username", "")
422 if not username or not username.isalnum() or not username[0].isalpha():
423 raise RegistrationError(session.localize("Username must be alphanumeric, and must start with an alphabetic character."))
424 fullname = argdict.get("name", "")
425 email = argdict.get("email", "")
426 password = argdict.get("password", "")
427 passwordconfirm = argdict.get("passwordconfirm", "")
428 if " " in email or not (email and "@" in email and "." in email):
429 raise RegistrationError(session.localize("You must supply a valid email address"))
430 userexists = session.loginchecker.userexists(username)
431 users = session.loginchecker.users
432 if userexists:
433 usernode = self.getusernode(users, username)
434 # use the email address on file
435 email = getattr(usernode, "email", email)
436 password = ""
437 # TODO: we can't figure out the password as we only store the md5sum. have a password reset mechanism
438 message = session.localize("You (or someone else) attempted to register an account with your username.\n")
439 message += session.localize("We don't store your actual password but only a hash of it.\n")
440 if supportaddress:
441 message += session.localize("If you have a problem with registration, please contact %s.\n", supportaddress)
442 else:
443 message += session.localize("If you have a problem with registration, please contact the site administrator.\n")
444 displaymessage = session.localize("That username already exists. An email will be sent to the registered email address.\n")
445 redirecturl = "login.html?username=%s" % username
446 displaymessage += session.localize("Proceeding to <a href='%s'>login</a>\n", redirecturl)
447 else:
448 validatepassword(session, password, passwordconfirm)
449 self.adduser(users, username, fullname, email, password)
450 activationcode = self.makeactivationcode(users, username)
451 activationlink = ""
452 message = session.localize("A Pootle account has been created for you using this email address.\n")
453 if session.instance.baseurl.startswith("http://"):
454 message += session.localize("To activate your account, follow this link:\n")
455 activationlink = session.instance.baseurl
456 if not activationlink.endswith("/"):
457 activationlink += "/"
458 activationlink += "activate.html?username=%s&activationcode=%s" % (username, activationcode)
459 message += " %s \n" % activationlink
460 message += session.localize("Your activation code is:\n%s\n", activationcode)
461 if activationlink:
462 message += session.localize("If you are unable to follow the link, please enter the above code at the activation page.\n")
463 message += session.localize("This message is sent to verify that the email address is in fact correct. If you did not want to register an account, you may simply ignore the message.\n")
464 redirecturl = "activate.html?username=%s" % username
465 displaymessage = session.localize("Account created. You will be emailed login details and an activation code. Please enter your activation code on the <a href='%s'>activation page</a>.", redirecturl)
466 if activationlink:
467 displaymessage += " " + session.localize("(Or simply click on the activation link in the email)")
468 session.saveprefs()
469 message += session.localize("Your user name is: %s\n", username)
470 if password.strip():
471 message += session.localize("Your password is: %s\n", password)
472 message += session.localize("Your registered email address is: %s\n", email)
473 smtpserver = self.instance.registration.smtpserver
474 fromaddress = self.instance.registration.fromaddress
475 subject = Header(session.localize("Pootle Registration"),
476 "utf-8").encode()
477 messagedict = {"from": fromaddress, "to": [email], "subject": subject, "body": message}
478 if supportaddress:
479 messagedict["reply-to"] = supportaddress
480 fullmessage = mailer.makemessage(messagedict)
481 if isinstance(fullmessage, unicode):
482 fullmessage = fullmessage.encode("utf-8")
483 errmsg = mailer.dosendmessage(fromemail=self.instance.registration.fromaddress, recipientemails=[email], message=fullmessage, smtpserver=smtpserver)
484 if errmsg:
485 raise RegistrationError("Error sending mail: %s" % errmsg)
486 return displaymessage, redirecturl
488 def registerpage(self, session, argdict):
489 """handle registration or return the Register page"""
490 if "username" in argdict:
491 try:
492 displaymessage, redirecturl = self.handleregistration(session, argdict)
493 except RegistrationError, message:
494 return RegisterPage(session, argdict, message)
495 redirectpage = pagelayout.PootlePage("Redirecting...", {}, session)
496 redirectpage.templatename = "redirect"
497 redirectpage.templatevars = {
498 # BUG: We won't redirect to registration page, we will go to
499 # activation or login
500 "pagetitle": session.localize("Redirecting to Registration Page..."),
501 "refresh": 10,
502 "refreshurl": redirecturl,
503 "message": displaymessage,
505 redirectpage.completevars()
506 return redirectpage
507 else:
508 return RegisterPage(session, argdict)
510 def activatepage(self, session, argdict):
511 """handle activation or return the Register page"""
512 if "username" in argdict and "activationcode" in argdict:
513 username = argdict["username"]
514 activationcode = argdict["activationcode"]
515 if self.hasuser(session.loginchecker.users, username):
516 usernode = self.getusernode(session.loginchecker.users, username)
517 correctcode = getattr(usernode, "activationcode", "")
518 if correctcode and correctcode.strip().lower() == activationcode.strip().lower():
519 setattr(usernode, "activated", 1)
520 session.saveprefs()
521 redirectpage = pagelayout.PootlePage("Redirecting to login...", {}, session)
522 redirectpage.templatename = "redirect"
523 redirectpage.templatevars = {
524 "pagetitle": session.localize("Redirecting to login Page..."),
525 "refresh": 10,
526 "refreshurl": "login.html?username=%s" % username,
527 "message": session.localize("Your account has been activated! Redirecting to login..."),
529 redirectpage.completevars()
530 return redirectpage
531 failedmessage = session.localize("The activation information was not valid.")
532 return ActivatePage(session, argdict, title=session.localize("Activation Failed"), message=failedmessage)
533 else:
534 return ActivatePage(session, argdict)
536 class PootleSession(web.session.LoginSession):
537 """a session object that knows about Pootle"""
538 def __init__(self, sessioncache, server, sessionstring = None, loginchecker = None):
539 """sets up the session and remembers the users prefs"""
540 super(PootleSession, self).__init__(sessioncache, server, sessionstring, loginchecker)
541 self.getprefs()
543 def getprefs(self):
544 """gets the users prefs into self.prefs"""
545 if self.isopen:
546 self.prefs = self.loginchecker.users.__getattr__(self.username)
547 if self.language_set:
548 self.setlanguage(self.language_set)
549 return
550 uilanguage = getattr(self.prefs, "uilanguage", None)
551 if uilanguage:
552 self.setlanguage(uilanguage)
553 else:
554 self.prefs = None
556 def saveprefs(self):
557 """saves changed preferences back to disk"""
558 # TODO: this is a hack, fix it up nicely :-)
559 prefsfile = self.loginchecker.users.__root__.__dict__["_setvalue"].im_self
560 prefsfile.savefile()
562 def open(self):
563 """opens the session, along with the users prefs"""
564 super(PootleSession, self).open()
565 self.getprefs()
566 return self.isopen
568 def close(self, req):
569 """opens the session, along with the users prefs"""
570 super(PootleSession, self).close(req)
571 self.getprefs()
573 def setlanguage(self, language):
574 """sets the language for the session"""
575 self.language_set = language or ""
576 if language:
577 self.language = language
578 elif not getattr(self, "language", None):
579 if self.isopen:
580 self.language = getattr(self.prefs, "uilanguage", "") or self.server.defaultlanguage
581 else:
582 self.language = self.server.defaultlanguage
583 if self.isopen:
584 if not getattr(self.prefs, "uilanguage", "") and self.language_set:
585 self.setinterfaceoptions({"option-uilanguage": self.language_set})
586 self.translation = self.server.gettranslation(self.language)
587 self.tr_lang = langdata.tr_lang(self.language)
588 try:
589 locale.setlocale(locale.LC_ALL, str(self.language))
590 except locale.Error:
591 # The system might not have the locale installed
592 pass
593 self.checkstatus(None, None)
594 if self.language:
595 self.lang = factory.getlanguage(self.language)
597 def validate(self):
598 """checks if this session is valid (which means the user must be activated)"""
599 if not super(PootleSession, self).validate():
600 return False
601 if self.loginchecker.users.__hasattr__(self.username):
602 usernode = self.loginchecker.users.__getattr__(self.username)
603 if getattr(usernode, "activated", 0):
604 return self.isvalid
605 self.isvalid = False
606 self.status = "username has not yet been activated"
607 return self.isvalid
609 def setoptions(self, argdict):
610 """sets the user options"""
611 userprojects = argdict.get("projects", [])
612 if isinstance(userprojects, (str, unicode)):
613 userprojects = [userprojects]
614 setattr(self.prefs, "projects", ",".join(userprojects))
615 userlanguages = argdict.get("languages", [])
616 if isinstance(userlanguages, (str, unicode)):
617 userlanguages = [userlanguages]
618 setattr(self.prefs, "languages", ",".join(userlanguages))
619 self.saveprefs()
621 def setpersonaloptions(self, argdict):
622 """sets the users personal details"""
623 name = argdict.get("option-name", "")
624 email = argdict.get("option-email", "")
625 password = argdict.get("option-password", "")
626 passwordconfirm = argdict.get("option-passwordconfirm", "")
628 if password or passwordconfirm:
629 validatepassword(self, password, passwordconfirm)
630 setattr(self.prefs, "name", name)
631 setattr(self.prefs, "email", email)
632 if password:
633 passwdhash = web.session.md5hexdigest(argdict.get("option-password", ""))
634 setattr(self.prefs, "passwdhash", passwdhash)
635 self.saveprefs()
637 def setinterfaceoptions(self, argdict):
638 """sets the users interface details"""
639 value = argdict.get("option-uilanguage", "")
640 if value:
641 self.prefs.uilanguage = value
642 self.setlanguage(value)
643 def setinterfacevalue(name, errormessage):
644 value = argdict.get("option-%s" % name, "")
645 if value != "":
646 if not value.isdigit():
647 raise ValueError(errormessage)
648 setattr(self.prefs, name, value)
649 setinterfacevalue("inputheight", self.localize("Input height must be numeric"))
650 setinterfacevalue("inputwidth", self.localize("Input width must be numeric"))
651 setinterfacevalue("viewrows", self.localize("The number of rows displayed in view mode must be numeric"))
652 setinterfacevalue("translaterows", self.localize("The number of rows displayed in translate mode must be numeric"))
653 useraltsrclanguage = argdict.get("altsrclanguage", "")
654 if isinstance(useraltsrclanguage, (str, unicode)):
655 setattr(self.prefs, "altsrclanguage", useraltsrclanguage)
656 self.saveprefs()
658 def getprojects(self):
659 """gets the user's projects"""
660 userprojects = getattr(self.prefs, "projects", "")
661 return [projectcode.strip() for projectcode in userprojects.split(',') if projectcode.strip()]
663 def getlanguages(self):
664 """gets the user's languages"""
665 userlanguages = getattr(self.prefs, "languages", "")
666 return [languagecode.strip() for languagecode in userlanguages.split(',') if languagecode.strip()]
668 def getaltsrclanguage(self):
669 """gets the user's alternative source language"""
670 useraltsrclanguage = getattr(self.prefs, "altsrclanguage", "")
671 return useraltsrclanguage.strip()
673 def getrights(self):
674 """gets the user's rights"""
675 return getattr(self.prefs, "rights", None)
677 def issiteadmin(self):
678 """returns whether the user can administer the site"""
679 return getattr(self.getrights(), "siteadmin", False)