]> git.ipfire.org Git - people/jschlag/pbs.git/blame - web/ui_modules.py
builders progress: Round shown value to natural figures.
[people/jschlag/pbs.git] / web / ui_modules.py
CommitLineData
f6e6ff79 1#!/usr/bin/python
9137135a 2
5669a87f
MT
3from __future__ import division
4
5import math
cd870d0a 6import pytz
f6e6ff79
MT
7import re
8import string
e434b018 9import textile
f6e6ff79 10import tornado.escape
9137135a
MT
11import tornado.web
12
f6e6ff79 13import backend.users
9137135a
MT
14from backend.constants import *
15
16class UIModule(tornado.web.UIModule):
17 @property
18 def pakfire(self):
19 return self.handler.application.pakfire
20
f6e6ff79
MT
21 @property
22 def settings(self):
23 return self.pakfire.settings
24
25
26class TextModule(UIModule):
c764ce43 27 __cache = {}
f6e6ff79 28
c764ce43 29 LINK = """<a href="%s" target="_blank">%s</a>"""
f6e6ff79 30
c764ce43
MT
31 @property
32 def bugzilla_url(self):
33 return self.settings.get("bugzilla_url", "")
f6e6ff79 34
c764ce43
MT
35 @property
36 def bugzilla_pattern(self):
37 if not self.__cache.has_key("bugzilla_pattern"):
38 self.__cache["bugzilla_pattern"] = re.compile(BUGZILLA_PATTERN)
39
40 return self.__cache["bugzilla_pattern"]
41
42 @property
43 def bugzilla_repl(self):
44 return self.LINK % (self.bugzilla_url % { "bugid" : r"\2" }, r"\1\2")
45
46 @property
47 def cve_url(self):
48 return self.settings.get("cve_url", "")
49
50 @property
51 def cve_pattern(self):
52 if not self.__cache.has_key("cve_pattern"):
53 self.__cache["cve_pattern"] = re.compile(CVE_PATTERN)
54
55 return self.__cache["cve_pattern"]
56
57 @property
58 def cve_repl(self):
59 return self.LINK % (self.cve_url % r"\3", r"\1\2\3")
c21cb4ec 60
c764ce43
MT
61 def render(self, text, pre=False, remove_linebreaks=True):
62 link = """<a href="%s" target="_blank">%s</a>"""
f6e6ff79 63
c764ce43
MT
64 if remove_linebreaks:
65 text = text.replace("\n", " ")
f6e6ff79 66
c764ce43
MT
67 # Escape the text and create make urls clickable.
68 text = tornado.escape.xhtml_escape(text)
69 text = tornado.escape.linkify(text, shorten=True,
70 extra_params='target="_blank"')
f6e6ff79 71
c764ce43
MT
72 # Search for bug ids that need to be linked to bugzilla.
73 if self.bugzilla_url:
74 text = re.sub(self.bugzilla_pattern, self.bugzilla_repl, text, re.I|re.U)
f6e6ff79 75
c764ce43
MT
76 # Search for CVE numbers and create hyperlinks.
77 if self.cve_url:
78 text = re.sub(self.cve_pattern, self.cve_repl, text, re.I|re.U)
f6e6ff79
MT
79
80 if pre:
c764ce43 81 return "<pre>%s</pre>" % text
f6e6ff79 82
c764ce43 83 return textile.textile(text)
f6e6ff79
MT
84
85
86class ModalModule(UIModule):
87 def render(self, what, **kwargs):
88 what = "modules/modal-%s.html" % what
9137135a 89
f6e6ff79
MT
90 return self.render_string(what, **kwargs)
91
92
93class BuildHeadlineModule(UIModule):
94 def render(self, prefix, build, short=False, shorter=False):
95 if shorter:
96 short = True
97
98 return self.render_string("modules/build-headline.html",
99 prefix=prefix, build=build, pkg=build.pkg, short=short, shorter=shorter)
100
101
f96eb5ed
MT
102class BuildersLoadModule(UIModule):
103 def render(self):
104 load = self.pakfire.builders.get_load()
105
106 return self.render_string("modules/builders/load.html", load=load)
107
108
f6e6ff79
MT
109class BugsTableModule(UIModule):
110 def render(self, pkg, bugs):
111 return self.render_string("modules/bugs-table.html",
112 pkg=pkg, bugs=bugs)
113
114
4b1e87c4
MT
115class ChangelogModule(UIModule):
116 def render(self, name=None, builds=None, *args, **kwargs):
117 if not builds:
118 builds = self.pakfire.builds.get_changelog(name, *args, **kwargs)
119
120 return self.render_string("modules/changelog/index.html", builds=builds)
121
122
123class ChangelogEntryModule(UIModule):
124 def render(self, build):
125 return self.render_string("modules/changelog/entry.html", build=build)
126
127
f6e6ff79
MT
128class CommitsTableModule(UIModule):
129 def render(self, distro, source, commits, full_format=True):
130 return self.render_string("modules/commits-table.html",
131 distro=distro, source=source, commits=commits,
132 full_format=full_format)
133
134
135class FooterModule(UIModule):
136 def render(self):
137 return self.render_string("modules/footer.html")
138
139
140class PackagesTableModule(UIModule):
141 def render(self, job, packages):
142 return self.render_string("modules/packages-table.html", job=job,
143 packages=packages)
9137135a
MT
144
145
5669a87f
MT
146class PackagesDependencyTableModule(UIModule):
147 def render(self, pkg):
148 if pkg.type == "source":
149 all_deps = [
150 (None, pkg.requires),
151 ]
152 else:
153 all_deps = [
154 ("provides", pkg.provides),
155 ("requires", pkg.requires),
156 ("prerequires", pkg.prerequires),
157 ("conflicts", pkg.conflicts),
158 ("obsoletes", pkg.obsoletes),
159 ("recommends", pkg.recommends),
160 ("suggests", pkg.suggests),
161 ]
162
163 has_deps = []
164 for name, deps in all_deps:
165 if deps:
166 has_deps.append((name, deps))
167
168 if len(has_deps):
169 span = math.floor(12 / len(has_deps))
170
171 if span > 3:
172 span = 3
173 else:
174 span = 12
175
176 return self.render_string("modules/packages/dependency-table.html",
177 pkg=pkg, dependencies=has_deps, span=span)
178
179
9137135a
MT
180class PackageTable2Module(UIModule):
181 def render(self, packages):
182 return self.render_string("modules/package-table-detail.html",
183 packages=packages)
184
185
186class FilesTableModule(UIModule):
187 def render(self, files):
188 return self.render_string("modules/files-table.html", files=files)
189
190
f6e6ff79
MT
191class LogFilesTableModule(UIModule):
192 def render(self, job, files):
193 return self.render_string("modules/log-files-table.html", job=job,
194 files=files)
195
196
197class PackageHeaderModule(UIModule):
198 def render(self, pkg):
199 return self.render_string("modules/package-header.html", pkg=pkg)
200
201
9137135a 202class PackageFilesTableModule(UIModule):
f6e6ff79
MT
203 def render(self, pkg, filelist):
204 return self.render_string("modules/packages-files-table.html",
205 pkg=pkg, filelist=filelist)
9137135a
MT
206
207
208class BuildTableModule(UIModule):
f6e6ff79
MT
209 def render(self, builds, **kwargs):
210 settings = dict(
211 show_user = False,
212 show_repo = False,
213 show_repo_time = False,
214 show_can_move_forward = False,
215 show_when = True,
216 )
217 settings.update(kwargs)
218
219 return self.render_string("modules/build-table.html",
220 builds=builds, **settings)
221
222
223class BuildStateWarningsModule(UIModule):
224 def render(self, build):
225 return self.render_string("modules/build-state-warnings.html", build=build)
226
227
3c7e0537
MT
228class JobsBoxesModule(UIModule):
229 def render(self, build, jobs=None):
230 if jobs is None:
231 jobs = build.jobs
232
233 return self.render_string("modules/jobs/boxes.html",
234 build=build, jobs=jobs)
235
236
237class JobStateModule(UIModule):
238 def render(self, job, cls=None):
239 state = job.state
240
241 _ = self.locale.translate
242 classes = []
243
244 if state == "aborted":
245 text = _("Aborted")
246 classes.append("muted")
247
248 elif state == "dependency_error":
249 text = _("Dependency problem")
250 classes.append("text-warning")
251
252 elif state == "dispatching":
253 text = _("Dispatching")
254 classes.append("text-info")
255
256 elif state == "failed":
257 text = _("Failed")
258 classes.append("text-error")
259
260 elif state == "finished":
261 text = _("Finished")
262 classes.append("text-success")
263
264 elif state == "new":
265 text = _("New")
266 classes.append("muted")
267
268 elif state == "pending":
269 text = _("Pending")
270 classes.append("muted")
271
272 elif state == "running":
273 text = _("Running")
274 classes.append("text-info")
275
276 # Return just the string, is state is unknown.
277 else:
278 text = _("Unknown: %s") % state
279 classes.append("muted")
280
281 if cls:
282 classes.append(cls)
283
284 return """<p class="%s">%s</p>""" % (" ".join(classes), text)
285
286
f6e6ff79
MT
287class JobsTableModule(UIModule):
288 def render(self, build, jobs=None, type="release"):
289 if jobs is None:
290 jobs = build.jobs
291
292 return self.render_string("modules/jobs-table.html", build=build,
293 jobs=jobs, type=type)
294
295
296class JobsListModule(UIModule):
297 def render(self, jobs, show_builder=False):
298 return self.render_string("modules/jobs-list.html", jobs=jobs,
299 show_builder=show_builder)
9137135a
MT
300
301
302class RepositoryTableModule(UIModule):
303 def render(self, distro, repos):
304 return self.render_string("modules/repository-table.html",
305 distro=distro, repos=repos)
306
307
308class SourceTableModule(UIModule):
309 def render(self, distro, sources):
310 return self.render_string("modules/source-table.html",
311 distro=distro, sources=sources)
312
313
314class CommentsTableModule(UIModule):
315 def render(self, comments, show_package=False, show_user=True):
316 pkgs, users = {}, {}
317 for comment in comments:
318 if show_package:
319 try:
320 pkg = pkgs[comment.pkg_id]
321 except KeyError:
322 pkg = pkgs[comment.pkg_id] = \
323 self.pakfire.packages.get_by_id(comment.pkg_id)
324
325 comment["pkg"] = pkg
326
327 if show_user:
328 try:
329 user = users[comment.user_id]
330 except KeyError:
331 user = users[comment.user_id] = \
332 self.pakfire.users.get_by_id(comment.user_id)
333
334 comment["user"] = user
335
336 return self.render_string("modules/comments-table.html",
337 comments=comments, show_package=show_package, show_user=show_user)
338
339
f6e6ff79
MT
340class LogModule(UIModule):
341 def render(self, entries, **args):
342 return self.render_string("modules/log.html",
343 entries=entries, args=args)
344
345
346class LogEntryModule(UIModule):
e434b018 347 def render(self, entry, small=None, **args):
7d0635e2 348 if small or not entry.user:
e434b018
MT
349 template = "modules/log-entry-small.html"
350 else:
351 template = "modules/log-entry.html"
352
353 return self.render_string(template, entry=entry, u=entry.user, **args)
f6e6ff79
MT
354
355
356class LogEntryCommentModule(LogEntryModule):
357 def render(self, entry, **args):
358 return self.render_string("modules/log-entry-comment.html",
e434b018 359 entry=entry, u=entry.user, **args)
f6e6ff79
MT
360
361
362class MaintainerModule(UIModule):
363 def render(self, maintainer):
364 if isinstance(maintainer, backend.users.User):
365 type = "user"
366 else:
367 type = "string"
368
369 return self.render_string("modules/maintainer.html",
370 type=type, maintainer=maintainer)
371
372
9137135a
MT
373class BuildLogModule(UIModule):
374 # XXX deprecated
375 def render(self, messages):
376 _ = self.locale.translate
377
378 for message in messages:
379 try:
380 msg = LOG2MSG[message.message]
381 message["message"] = _(msg)
382 except KeyError:
383 pass
384
385 return self.render_string("modules/build-log.html", messages=messages)
386
387
388class LogTableModule(UIModule):
389 def render(self, messages, links=["pkg",]):
390 for message in messages:
391 try:
392 message["message"] = LOG2MSG[message.message]
393 except KeyError:
394 pass
395
396 if message.build_id:
397 message["build"] = self.pakfire.builds.get_by_id(message.build_id)
398
399 elif message.pkg_id:
400 message["pkg"] = self.pakfire.packages.get_by_id(message.pkg_id)
401
402 return self.render_string("modules/log-table.html",
403 messages=messages, links=links)
404
405
406class UsersTableModule(UIModule):
407 def render(self, users):
408 return self.render_string("modules/user-table.html", users=users)
409
410
411class BuildOffsetModule(UIModule):
412 def render(self):
413 return self.render_string("modules/build-offset.html")
414
415
416class RepoActionsTableModule(UIModule):
417 def render(self, repo):
418 actions = repo.get_actions()
419
420 return self.render_string("modules/repo-actions-table.html",
421 repo=repo, actions=actions)
f6e6ff79
MT
422
423
424class UpdatesTableModule(UIModule):
425 def render(self, updates):
426 return self.render_string("modules/updates-table.html", updates=updates)
427
428
429class WatchersSidebarTableModule(UIModule):
430 def css_files(self):
431 return "css/watchers-sidebar-table.css"
432
433 def render(self, build, watchers, limit=5):
434 # Sort the watchers by their realname.
435 watchers.sort(key=lambda watcher: watcher.realname)
436
437 return self.render_string("modules/watchers-sidebar-table.html",
438 build=build, watchers=watchers, limit=limit)
cd870d0a
MT
439
440
441class SelectLocaleModule(UIModule):
442 LOCALE_NAMES = (
443 # local code, English name, name
444 ("ca_ES", u"Catalan", "Catal\xc3\xa0"),
445 ("da_DK", u"Danish", u"Dansk"),
446 ("de_DE", u"German", u"Deutsch"),
447 ("en_GB", u"English (UK)", u"English (UK)"),
448 ("en_US", u"English (US)", u"English (US)"),
449 ("es_ES", u"Spanish (Spain)", u"Espa\xf1ol (Espa\xf1a)"),
450 ("es_LA", u"Spanish", u"Espa\xf1ol"),
451 ("fr_CA", u"French (Canada)", u"Fran\xe7ais (Canada)"),
452 ("fr_FR", u"French", u"Fran\xe7ais"),
453 ("it_IT", u"Italian", u"Italiano"),
454 ("km_KH", u"Khmer", u"\u1797\u17b6\u179f\u17b6\u1781\u17d2\u1798\u17c2\u179a"),
455 ("pt_BR", u"Portuguese (Brazil)", u"Portugu\xeas (Brasil)"),
456 ("pt_PT", u"Portuguese (Portugal)", u"Portugu\xeas (Portugal)"),
457 ("ru_RU", u"Russian", u"\u0440\u0443\u0441\u0441\u043a\u0438\u0439"),
458 )
459
460 def render(self, name=None, id=None, preselect=None):
461 return self.render_string("modules/select/locale.html",
462 name=name, id=id, preselect=preselect, supported_locales=self.LOCALE_NAMES)
463
464
465class SelectTimezoneModule(UIModule):
466 def render(self, name=None, id=None, preselect=None):
467 return self.render_string("modules/select/timezone.html",
468 name=name, id=id, preselect=preselect,
469 supported_timezones=pytz.common_timezones)