modinfo in the translate toolkit is now a 2-tuple containing the mtime and
[pootle.git] / adminpages.py
blobaa27294aed3720521fce6ad65f268a684be4fbf3
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3 #
4 # Copyright 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 Pootle import pagelayout
23 from Pootle import projects
24 from translate.filters import checks
26 import locale
28 class AdminPage(pagelayout.PootlePage):
29 """page for administering pootle..."""
30 def __init__(self, potree, session, instance):
31 self.potree = potree
32 self.session = session
33 self.instance = instance
34 self.localize = session.localize
35 templatename = "adminindex"
36 sessionvars = {"status": self.session.status, "isopen": self.session.isopen, "issiteadmin": self.session.issiteadmin()}
37 instancetitle = getattr(self.instance, "title", session.localize("Pootle Demo"))
38 text = self.gettext(session)
39 templatevars = {"options": self.getoptions(), "session": sessionvars, "instancetitle": instancetitle, "text": text}
40 pagelayout.PootlePage.__init__(self, templatename, templatevars, session)
42 def gettext(self, session):
43 """Localize the text"""
44 text = {}
45 text["home"] = session.localize("Home")
46 text["users"] = session.localize("Users")
47 text["languages"] = session.localize("Languages")
48 text["projects"] = session.localize("Projects")
49 text["generaloptions"] = session.localize("General options")
50 text["option"] = session.localize("Option")
51 text["currentvalue"] = session.localize("Current value")
52 text["savechanges"] = session.localize("Save changes")
53 return text
55 def getoptions(self):
56 optiontitles = {"title": self.localize("Title"),
57 "description": self.localize("Description"),
58 "baseurl": self.localize("Base URL"),
59 "homepage": self.localize("Home Page")}
60 options = []
61 for optionname, optiontitle in optiontitles.items():
62 optionvalue = getattr(self.instance, optionname, "")
63 option = {"name": "option-%s" % optionname, "title": optiontitle, "value": optionvalue}
64 options.append(option)
65 return options
67 class LanguagesAdminPage(pagelayout.PootlePage):
68 """page for administering pootle..."""
69 def __init__(self, potree, session, instance):
70 self.potree = potree
71 self.session = session
72 self.instance = instance
73 self.localize = session.localize
74 templatename = "adminlanguages"
75 sessionvars = {"status": self.session.status, "isopen": self.session.isopen, "issiteadmin": self.session.issiteadmin()}
76 instancetitle = getattr(self.instance, "title", session.localize("Pootle Demo"))
77 text = self.gettext(session)
78 templatevars = {"languages": self.getlanguagesoptions(), "options": self.getoptions(), "session": sessionvars, "instancetitle": instancetitle, "text": text}
79 pagelayout.PootlePage.__init__(self, templatename, templatevars, session)
81 def gettext(self, session):
82 """Localize the text"""
83 text = {}
84 text["home"] = session.localize("Home")
85 text["admin"] = session.localize("Main admin page")
86 text["languages"] = session.localize("Languages")
87 text["savechanges"] = session.localize("Save changes")
88 return text
90 def getoptions(self):
91 options = [{"name": "code", "title": self.localize("ISO Code"), "size": 6, "newvalue": ""},
92 {"name": "name", "title": self.localize("Full Name"),
93 "newvalue": self.localize("(add language here)")},
94 {"name": "specialchars", "title": self.localize("Special Chars"), "newvalue": self.localize("(special characters)")},
95 {"name": "nplurals", "title": self.localize("Number of Plurals"), "newvalue": self.localize("(number of plurals)")},
96 {"name": "pluralequation", "title": self.localize("Plural Equation"), "newvalue": self.localize("(plural equation)")},
97 {"name": "remove", "title": self.localize("Remove Language")}]
98 for option in options:
99 if "newvalue" in option:
100 option["newname"] = "newlanguage" + option["name"]
101 return options
103 def getlanguagesoptions(self):
104 languages = []
105 for languagecode, languagename in self.potree.getlanguages():
106 languagespecialchars = self.potree.getlanguagespecialchars(languagecode)
107 languagenplurals = self.potree.getlanguagenplurals(languagecode)
108 languagepluralequation = self.potree.getlanguagepluralequation(languagecode)
109 languageremove = None
110 # TODO: make label work like this
111 # l10n: The parameter is a languagecode, projectcode or username
112 removelabel = self.localize("Remove %s", languagecode)
113 languageoptions = [{"name": "languagename-%s" % languagecode, "value": languagename, "type": "text"},
114 {"name": "languagespecialchars-%s" % languagecode, "value": languagespecialchars, "type": "text"},
115 {"name": "languagenplurals-%s" % languagecode, "value": languagenplurals, "type": "text"},
116 {"name": "languagepluralequation-%s" % languagecode, "value": languagepluralequation, "type": "text"},
117 {"name": "languageremove-%s" % languagecode, "value": languageremove, "type": "checkbox", "label": removelabel}]
118 languages.append({"code": languagecode, "options": languageoptions})
119 return languages
121 class ProjectsAdminPage(pagelayout.PootlePage):
122 """page for administering pootle..."""
123 def __init__(self, potree, session, instance):
124 self.potree = potree
125 self.session = session
126 self.instance = instance
127 self.localize = session.localize
128 templatename = "adminprojects"
129 projectfiletypes = ["po","xlf"]
130 self.allchecks = [{"value": check, "description": check} for check in checks.projectcheckers.keys()]
131 self.allchecks.insert(0, {"value": "", "description": self.localize("Standard")})
132 self.alltypes = [{"value": check, "description": check} for check in projectfiletypes]
133 sessionvars = {"status": self.session.status, "isopen": self.session.isopen, "issiteadmin": self.session.issiteadmin()}
134 instancetitle = getattr(self.instance, "title", session.localize("Pootle Demo"))
135 text = self.gettext(session)
136 templatevars = {"projects": self.getprojectsoptions(), "options": self.getoptions(), "session": sessionvars, "instancetitle": instancetitle, "text": text}
137 pagelayout.PootlePage.__init__(self, templatename, templatevars, session)
139 def gettext(self, session):
140 """Localize the text"""
141 text = {}
142 text["home"] = session.localize("Home")
143 text["admin"] = session.localize("Main admin page")
144 text["projects"] = session.localize("Projects")
145 text["savechanges"] = session.localize("Save changes")
146 return text
148 def getoptions(self):
149 options = [{"name": "code", "title": self.localize("Project Code"), "size": 6, "newvalue": ""},
150 {"name": "name", "title": self.localize("Full Name"),
151 "newvalue": self.localize("(add project here)")},
152 {"name": "description", "title": self.localize("Project Description"), "newvalue": self.localize("(project description)")},
153 {"name": "checkerstyle", "title": self.localize("Checker Style"), "selectoptions": self.allchecks, "newvalue": ""},
154 {"name": "filetype", "title": self.localize("File Type"), "selectoptions": self.alltypes, "newvalue": ""},
155 {"name": "createmofiles", "title": self.localize("Create MO Files"), "type": "checkbox", "newvalue": ""},
156 {"name": "remove", "title": self.localize("Remove Project")}]
157 for option in options:
158 if "newvalue" in option:
159 option["newname"] = "newproject" + option["name"]
160 if "type" not in option and "selectoptions" not in option:
161 option["type"] = "text"
162 return options
164 def getprojectsoptions(self):
165 projects = []
166 for projectcode in self.potree.getprojectcodes():
167 projectadminlink = "../projects/%s/admin.html" % projectcode
168 projectname = self.potree.getprojectname(projectcode)
169 projectdescription = self.potree.getprojectdescription(projectcode)
170 projectname = self.potree.getprojectname(projectcode)
171 projectcheckerstyle = self.potree.getprojectcheckerstyle(projectcode)
172 projectfiletype = self.potree.getprojectlocalfiletype(projectcode)
173 if self.potree.getprojectcreatemofiles(projectcode):
174 projectcreatemofiles = "checked"
175 else:
176 projectcreatemofiles = ""
177 projectremove = None
178 # l10n: The parameter is a languagecode, projectcode or username
179 removelabel = self.localize("Remove %s", projectcode)
180 projectoptions = [{"name": "projectname-%s" % projectcode, "value": projectname, "type": "text"},
181 {"name": "projectdescription-%s" % projectcode, "value": projectdescription, "type": "text"},
182 {"name": "projectcheckerstyle-%s" % projectcode, "value": projectcheckerstyle, "selectoptions": self.allchecks},
183 {"name": "projectfiletype-%s" % projectcode, "value": projectfiletype, "selectoptions": self.alltypes},
184 {"name": "projectcreatemofiles-%s" % projectcode, "value": projectcreatemofiles, "type": "checkbox", projectcreatemofiles: projectcreatemofiles},
185 {"name": "projectremove-%s" % projectcode, "value": projectremove, "type": "checkbox", "label": removelabel}]
186 projects.append({"code": projectcode, "adminlink": projectadminlink, "options": projectoptions})
187 return projects
189 class UsersAdminPage(pagelayout.PootlePage):
190 """page for administering pootle..."""
191 def __init__(self, server, users, session, instance):
192 self.server = server
193 self.users = users
194 self.session = session
195 self.instance = instance
196 self.localize = session.localize
197 templatename = "adminusers"
198 sessionvars = {"status": self.session.status, "isopen": self.session.isopen, "issiteadmin": self.session.issiteadmin()}
199 instancetitle = getattr(self.instance, "title", session.localize("Pootle Demo"))
200 text = self.gettext(session)
201 templatevars = {"users": self.getusersoptions(), "options": self.getoptions(), "session": sessionvars, "instancetitle": instancetitle, "text": text}
202 pagelayout.PootlePage.__init__(self, templatename, templatevars, session)
204 def gettext(self, session):
205 """Localize the text"""
206 text = {}
207 text["home"] = session.localize("Home")
208 text["admin"] = session.localize("Main admin page")
209 text["users"] = session.localize("Users")
210 text["savechanges"] = session.localize("Save changes")
211 return text
213 def getoptions(self):
214 options = [{"name": "name", "title": self.localize("Username"), "newvalue": "", "size": 6},
215 {"name": "fullname", "title": self.localize("Full Name"),
216 "newvalue": self.localize("(add full name here)")},
217 {"name": "email", "title": self.localize("Email Address"), "newvalue": self.localize("(add email here)")},
218 {"name": "password", "title": self.localize("Password"), "newvalue": self.localize("(add password here)")},
219 {"name": "activated", "title": self.localize("Activated"), "type": "checkbox", "checked": "true", "newvalue": "", "label": self.localize("Activate New User")},
220 {"name": "remove", "title": self.localize("Remove User"), "type": "checkbox"}]
221 for option in options:
222 if "newvalue" in option:
223 # TODO: rationalize this in the form processing
224 if option["name"] == "activated":
225 option["newname"] = "newuseractivate"
226 else:
227 option["newname"] = "newuser" + option["name"]
228 return options
230 def getusersoptions(self):
231 users = []
232 for usercode, usernode in self.users.iteritems(sorted=True):
233 fullname = getattr(usernode, "name", "")
234 email = getattr(usernode, "email", "")
235 activated = getattr(usernode, "activated", 0) == 1
236 if activated:
237 activatedattr = "checked"
238 else:
239 activatedattr = ""
240 userremove = None
241 # l10n: The parameter is a languagecode, projectcode or username
242 removelabel = self.localize("Remove %s", usercode)
243 useroptions = [{"name": "username-%s" % usercode, "value": fullname, "type": "text"},
244 {"name": "useremail-%s" % usercode, "value": email, "type": "text"},
245 {"name": "userpassword-%s" % usercode, "value": None, "type": "text"},
246 {"name": "useractivated-%s" % usercode, "type": "checkbox", activatedattr: activatedattr},
247 {"name": "userremove-%s" % usercode, "value": None, "type": "checkbox", "label": removelabel}]
248 users.append({"code": usercode, "options": useroptions})
249 return users
251 class ProjectAdminPage(pagelayout.PootlePage):
252 """list of languages belonging to a project"""
253 def __init__(self, potree, projectcode, session, argdict):
254 self.potree = potree
255 self.projectcode = projectcode
256 self.session = session
257 self.localize = session.localize
258 self.tr_lang = session.tr_lang
259 projectname = self.potree.getprojectname(self.projectcode)
260 if self.session.issiteadmin():
261 if "doaddlanguage" in argdict:
262 newlanguage = argdict.get("newlanguage", None)
263 if not newlanguage:
264 raise ValueError("You must select a new language")
265 self.potree.addtranslationproject(newlanguage, self.projectcode)
266 if "doupdatelanguage" in argdict:
267 languagecodes = argdict.get("updatelanguage", None)
268 if not languagecodes:
269 raise ValueError("No languagecode given in doupdatelanguage")
270 if isinstance(languagecodes, (str, unicode)):
271 languagecodes = [languagecodes]
272 for languagecode in languagecodes:
273 translationproject = self.potree.getproject(languagecode, self.projectcode)
274 translationproject.converttemplates(self.session)
275 main_link = self.localize("Back to main page")
276 existing_title = self.localize("Existing languages")
277 existing_languages = self.getexistinglanguages()
278 new_languages = self.getnewlanguages()
279 # l10n: This refers to updating the translation files from the templates like with .pot files
280 update_button = self.localize("Update Languages")
281 pagetitle = self.localize("Pootle Admin: %s", projectname)
282 norights_text = self.localize("You do not have the rights to administer this project.")
283 iso_code = self.localize("ISO Code")
284 full_name = self.localize("Full Name")
285 # l10n: This refers to updating the translation files from the templates like with .pot files
286 update_link = self.localize("Update from templates")
287 templatename = "projectadmin"
288 sessionvars = {"status": self.session.status, "isopen": self.session.isopen, "issiteadmin": self.session.issiteadmin()}
289 instancetitle = getattr(self.session.instance, "title", session.localize("Pootle Demo"))
290 templatevars = {"pagetitle": pagetitle, "norights_text": norights_text,
291 "project": {"code": projectcode, "name": projectname},
292 "iso_code": iso_code, "full_name": full_name,
293 "existing_title": existing_title, "existing_languages": existing_languages,
294 "new_languages": new_languages,
295 "update_button": update_button, "add_button": self.localize("Add Language"),
296 "main_link": main_link, "update_link": update_link,
297 "session": sessionvars, "instancetitle": instancetitle}
298 pagelayout.PootlePage.__init__(self, templatename, templatevars, session, bannerheight=80)
300 def getexistinglanguages(self):
301 """gets the info on existing languages"""
302 languages = self.potree.getlanguages(self.projectcode)
303 languageitems = [{"code": languagecode, "name": self.tr_lang(languagename)} for languagecode, languagename in languages]
304 # rewritten for compatibility with Python 2.3
305 # languageitems.sort(cmp=locale.strcoll, key=lambda dict: dict["name"])
306 languageitems.sort(lambda x,y: locale.strcoll(x["name"], y["name"]))
307 for n, item in enumerate(languageitems):
308 item["parity"] = ["even", "odd"][n % 2]
309 return languageitems
311 def getnewlanguages(self):
312 """returns a box that lets the user add new languages"""
313 existingcodes = self.potree.getlanguagecodes(self.projectcode)
314 allcodes = self.potree.getlanguagecodes()
315 newcodes = [code for code in allcodes if not (code in existingcodes or code == "templates")]
316 newoptions = [(self.potree.getlanguagename(code), code) for code in newcodes]
317 newoptions.sort()
318 newoptions = [{"code": code, "name": self.tr_lang(languagename)} for (languagename, code) in newoptions]
319 # rewritten for compatibility with Python 2.3
320 # newoptions.sort(cmp=locale.strcoll, key=lambda dict: dict["name"])
321 newoptions.sort(lambda x,y: locale.strcoll(x["name"], y["name"]))
322 return newoptions
324 class TranslationProjectAdminPage(pagelayout.PootlePage):
325 """admin page for a translation project (project+language)"""
326 def __init__(self, potree, project, session, argdict):
327 self.potree = potree
328 self.project = project
329 self.session = session
330 self.localize = session.localize
331 self.rightnames = self.project.getrightnames(session)
332 # l10n: This is the page title. The first parameter is the language name, the second parameter is the project name
333 pagetitle = self.localize("Pootle Admin: %s %s", self.project.languagename, self.project.projectname)
334 main_link = self.localize("Project home page")
335 if "admin" in self.project.getrights(self.session):
336 if "doupdaterights" in argdict:
337 for key, value in argdict.iteritems():
338 if isinstance(key, str):
339 key = key.decode("utf-8")
340 if key.startswith("rights-"):
341 username = key.replace("rights-", "", 1)
342 self.project.setrights(username, value)
343 if key.startswith("rightsremove-"):
344 username = key.replace("rightsremove-", "", 1)
345 self.project.delrights(self.session, username)
346 username = argdict.get("rightsnew-username", None)
347 if username:
348 username = username.strip()
349 if self.session.loginchecker.userexists(username):
350 self.project.setrights(username, argdict.get("rightsnew", ""))
351 else:
352 raise IndexError(self.localize("Cannot set rights for username %s - user does not exist", username))
353 norights_text = self.localize("You do not have the rights to administer this project.")
354 templatename = "projectlangadmin"
355 sessionvars = {"status": self.session.status, "isopen": self.session.isopen, "issiteadmin": self.session.issiteadmin()}
356 instancetitle = getattr(self.session.instance, "title", session.localize("Pootle Demo"))
357 templatevars = {"pagetitle": pagetitle, "norights_text": norights_text,
358 "project": {"code": self.project.projectcode, "name": self.project.projectname},
359 "language": {"code": self.project.languagecode, "name": self.project.languagename},
360 "main_link": main_link,
361 "session": sessionvars, "instancetitle": instancetitle}
362 templatevars.update(self.getoptions())
363 pagelayout.PootlePage.__init__(self, templatename, templatevars, session, bannerheight=80)
365 def getoptions(self):
366 """returns a box that describes the options"""
367 self.project.readprefs()
368 if self.project.filestyle == "gnu":
369 filestyle_text = self.localize("This is a GNU-style project (one directory, files named per language).")
370 else:
371 filestyle_text = self.localize("This is a standard style project (one directory per language).")
372 permissions_title = self.localize("User Permissions")
373 username_title = self.localize("Username")
374 adduser_text = self.localize("(select to add user)")
375 rights_title = self.localize("Rights")
376 remove_title = self.localize("Remove")
377 nobodyrights = self.project.getrights(username=None)
378 nobody_dict = self.getuserdict("nobody", delete=False)
379 defaultrights = self.project.getrights(username="default")
380 default_dict = self.getuserdict("default", delete=False)
381 users_with_rights = ["nobody", "default"]
382 rights = {"nobody": nobodyrights, "default": defaultrights}
383 for username in self.project.getuserswithrights():
384 if username in ("nobody", "default"): continue
385 users_with_rights.append(username)
386 rights[username] = self.project.getrights(username=username)
387 users = self.project.getuserswithinterest(self.session)
388 user_details = {"nobody": nobody_dict, "default": default_dict}
389 for username, usernode in users.iteritems():
390 if not isinstance(username, unicode):
391 username = username.decode("utf-8")
392 user_dict = self.getuserdict(username, usernode=usernode)
393 user_details[username] = user_dict
394 # We need to make sure that users_with_rights are also in user_details,
395 # since they might not be there yet or anymore
396 for username in users_with_rights:
397 if username in user_details:
398 continue
399 user_dict = self.getuserdict(username, usernode=None)
400 user_details[username] = user_dict
401 users_without_rights = [username for username in user_details if username not in users_with_rights]
402 newuser_dict = self.getuserdict(None, delete=False)
403 updaterights_text = self.localize("Update Rights")
404 return {"filestyle_text": filestyle_text,
405 "permissions_title": permissions_title,
406 "username_title": username_title,
407 "rights_title": rights_title,
408 "remove_title": remove_title,
409 "users_with_rights": users_with_rights,
410 "users_without_rights": users_without_rights,
411 "user_details": user_details,
412 "rights": rights,
413 "newuser": newuser_dict,
414 "updaterights_text": updaterights_text,
415 "rightnames": self.rightnames,
416 "adduser_text": adduser_text,
419 def getuserdict(self, username, delete=True, usernode=None):
420 """gets a dictionary for the given user given user's rights"""
421 # l10n: The parameter is a languagecode, projectcode or username
422 remove_text = self.localize("Remove %s", username)
423 description = getattr(usernode, "description", None) or username
424 userdict = {"username": username, "delete": delete or None, "remove_text": remove_text, "description": description}
425 return userdict