]> git.ipfire.org Git - pbs.git/blame - src/web/__init__.py
Fix URL schema for builders
[pbs.git] / src / web / __init__.py
CommitLineData
9137135a 1#!/usr/bin/python
a90bd9b0 2# encoding: utf-8
9137135a
MT
3
4import logging
51db04b0 5import multiprocessing
9137135a
MT
6import os.path
7import tornado.httpserver
8import tornado.locale
9import tornado.options
10import tornado.web
11
57859ebc 12from .. import Backend
5b466834 13from ..constants import *
4b9167ef 14from ..decorators import *
57859ebc 15
fd902c1e 16# Import all handlers
b0e50a58 17from . import api
aa8d5ad3 18from . import auth
eab000f0 19from . import builders
98514762 20from . import builds
8111065a 21from . import distributions
5cf8c7ea 22from . import errors
8f6d6505 23from . import jobs
f44a3f0d 24from . import keys
5b466834 25from . import mirrors
e71f1b15 26from . import packages
b8b310ec 27from . import search
fd902c1e 28from . import updates
156b826e 29from . import users
fd902c1e
MT
30from .handlers import *
31
5b466834 32from . import ui_modules
16f90605 33
9137135a 34# Enable logging
97144eb5 35tornado.options.define("debug", default=False, help="Run in debug mode", type=bool)
9137135a
MT
36tornado.options.parse_command_line()
37
38class Application(tornado.web.Application):
754243af 39 def __init__(self, **_settings):
9137135a 40 settings = dict(
97144eb5 41 debug = tornado.options.options.debug,
2b229cb1 42 gzip = True,
9137135a 43 login_url = "/login",
027a662e
MT
44 template_path = TEMPLATESDIR,
45 static_path = STATICDIR,
9137135a 46 ui_modules = {
5b466834
MT
47 "Text" : ui_modules.TextModule,
48 "Modal" : ui_modules.ModalModule,
f6e6ff79 49
5b466834 50 "Footer" : ui_modules.FooterModule,
f6e6ff79
MT
51
52 # Logging
5b466834
MT
53 "Log" : ui_modules.LogModule,
54 "LogEntry" : ui_modules.LogEntryModule,
55 "LogEntryComment" : ui_modules.LogEntryCommentModule,
f6e6ff79 56
5b466834
MT
57 "BuildHeadline" : ui_modules.BuildHeadlineModule,
58 "BuildStateWarnings" : ui_modules.BuildStateWarningsModule,
d685bd2c 59 "BuildState" : ui_modules.BuildState,
f6e6ff79 60
5b466834
MT
61 "BugsTable" : ui_modules.BugsTableModule,
62 "BuildLog" : ui_modules.BuildLogModule,
63 "BuildOffset" : ui_modules.BuildOffsetModule,
64 "BuildTable" : ui_modules.BuildTableModule,
4b1e87c4
MT
65
66 # Changelog
5b466834
MT
67 "Changelog" : ui_modules.ChangelogModule,
68 "ChangelogEntry" : ui_modules.ChangelogEntryModule,
4b1e87c4 69
6e63ed49 70 # Jobs
5b466834
MT
71 "JobsList" : ui_modules.JobsListModule,
72 "JobsStatus" : ui_modules.JobsStatusModule,
6e63ed49 73
5669a87f 74 # Packages
5b466834
MT
75 "PackagesDependencyTable" : ui_modules.PackagesDependencyTableModule,
76
c6e799b4 77 "CommitMessage" : ui_modules.CommitMessageModule,
5b466834
MT
78 "CommitsTable" : ui_modules.CommitsTableModule,
79 "JobsBoxes" : ui_modules.JobsBoxesModule,
80 "JobState" : ui_modules.JobStateModule,
81 "JobsTable" : ui_modules.JobsTableModule,
82 "CommentsTable" : ui_modules.CommentsTableModule,
83 "FilesTable" : ui_modules.FilesTableModule,
8dc6f5a4 84 "LinkToUser" : ui_modules.LinkToUserModule,
5b466834
MT
85 "LogTable" : ui_modules.LogTableModule,
86 "LogFilesTable" : ui_modules.LogFilesTableModule,
5b466834
MT
87 "PackagesTable" : ui_modules.PackagesTableModule,
88 "PackageTable2" : ui_modules.PackageTable2Module,
89 "PackageHeader" : ui_modules.PackageHeaderModule,
90 "PackageFilesTable" : ui_modules.PackageFilesTableModule,
91 "RepositoryTable" : ui_modules.RepositoryTableModule,
92 "RepoActionsTable" : ui_modules.RepoActionsTableModule,
93 "SourceTable" : ui_modules.SourceTableModule,
94 "UpdatesTable" : ui_modules.UpdatesTableModule,
95 "UsersTable" : ui_modules.UsersTableModule,
96 "WatchersSidebarTable" : ui_modules.WatchersSidebarTableModule,
97
8b713cc7
MT
98 "HeadingDate" : ui_modules.HeadingDateModule,
99
5b466834
MT
100 "SelectLocale" : ui_modules.SelectLocaleModule,
101 "SelectTimezone" : ui_modules.SelectTimezoneModule,
9137135a 102 },
bc293d03
MT
103 ui_methods = {
104 "format_time" : self.format_time,
105 },
9137135a
MT
106 xsrf_cookies = True,
107 )
754243af 108 settings.update(_settings)
9137135a
MT
109
110 # Load translations.
2b5a3b4d 111 tornado.locale.load_gettext_translations(LOCALEDIR, PACKAGE_NAME)
9137135a 112
754243af 113 tornado.web.Application.__init__(self, [
9137135a
MT
114 # Entry site that lead the user to index
115 (r"/", IndexHandler),
116
117 # Handle all the users logins/logouts/registers and stuff.
aa8d5ad3
MT
118 (r"/login", auth.LoginHandler),
119 (r"/logout", auth.LogoutHandler),
120 (r"/register", auth.RegisterHandler),
121 (r"/password-recovery", auth.PasswordRecoveryHandler),
98b826d4 122 (r"/password-reset", auth.PasswordResetHandler),
f6e6ff79
MT
123
124 # User profiles
156b826e
MT
125 (r"/users", users.UsersHandler),
126 (r"/user/(\w+)/impersonate", users.UserImpersonateHandler),
127 (r"/user/(\w+)/passwd", users.UserPasswdHandler),
128 (r"/user/(\w+)/delete", users.UserDeleteHandler),
129 (r"/user/(\w+)/edit", users.UserEditHandler),
aa8d5ad3 130 (r"/user/(\w+)/activate", auth.ActivationHandler),
156b826e
MT
131 (r"/user/(\w+)", users.UserHandler),
132 (r"/profile", users.UserHandler),
133 (r"/profile/builds", users.UsersBuildsHandler),
9137135a
MT
134
135 # Packages
b5800237 136 (r"/packages", packages.IndexHandler),
e71f1b15
MT
137 (r"/package/([\w]{8}-[\w]{4}-[\w]{4}-[\w]{4}-[\w]{12})", packages.PackageDetailHandler),
138 (r"/package/([\w]{8}-[\w]{4}-[\w]{4}-[\w]{4}-[\w]{12})/download(.*)", packages.PackageFileDownloadHandler),
139 (r"/package/([\w]{8}-[\w]{4}-[\w]{4}-[\w]{4}-[\w]{12})/view(.*)", packages.PackageFileViewHandler),
140 (r"/package/([\w\-\+]+)", packages.PackageNameHandler),
141 (r"/package/([\w\-\+]+)/builds/scratch", packages.PackageScratchBuildsHandler),
142 (r"/package/([\w\-\+]+)/builds/times", packages.PackageBuildsTimesHandler),
143 (r"/package/([\w\-\+]+)/changelog", packages.PackageChangelogHandler),
144 (r"/package/([\w\-\+]+)/properties", packages.PackagePropertiesHandler),
9137135a
MT
145
146 # Files
147 (r"/file/([\w]{8}-[\w]{4}-[\w]{4}-[\w]{4}-[\w]{12})", FileDetailHandler),
148
149 # Builds
98514762 150 (r"/builds", builds.BuildsHandler),
98514762
MT
151 (r"/builds/queue", builds.BuildQueueHandler),
152 (r"/builds/comments", builds.BuildsCommentsHandler),
153 (r"/builds/comments/(\w+)", builds.BuildsCommentsHandler),
154 (r"/build/([\w]{8}-[\w]{4}-[\w]{4}-[\w]{4}-[\w]{12})", builds.BuildDetailHandler),
155 (r"/build/([\w]{8}-[\w]{4}-[\w]{4}-[\w]{4}-[\w]{12})/bugs", builds.BuildBugsHandler),
156 (r"/build/([\w]{8}-[\w]{4}-[\w]{4}-[\w]{4}-[\w]{12})/manage", builds.BuildManageHandler),
157 (r"/build/([\w]{8}-[\w]{4}-[\w]{4}-[\w]{4}-[\w]{12})/comment", builds.BuildDetailCommentHandler),
158 (r"/build/([\w]{8}-[\w]{4}-[\w]{4}-[\w]{4}-[\w]{12})/priority", builds.BuildPriorityHandler),
159 (r"/build/([\w]{8}-[\w]{4}-[\w]{4}-[\w]{4}-[\w]{12})/state", builds.BuildStateHandler),
160 (r"/build/([\w]{8}-[\w]{4}-[\w]{4}-[\w]{4}-[\w]{12})/watch", builds.BuildWatchersAddHandler),
161 (r"/build/([\w]{8}-[\w]{4}-[\w]{4}-[\w]{4}-[\w]{12})/watchers", builds.BuildWatchersHandler),
162 (r"/build/([\w]{8}-[\w]{4}-[\w]{4}-[\w]{4}-[\w]{12})/delete", builds.BuildDeleteHandler),
f6e6ff79 163
fe9b927c
MT
164 (r"/queue", jobs.ShowQueueHandler),
165 (r"/queue/([\w_]+)", jobs.ShowQueueHandler),
166
f6e6ff79 167 # Jobs
8f6d6505
MT
168 (r"/job/([\w]{8}-[\w]{4}-[\w]{4}-[\w]{4}-[\w]{12})", jobs.JobDetailHandler),
169 (r"/job/([\w]{8}-[\w]{4}-[\w]{4}-[\w]{4}-[\w]{12})/abort", jobs.JobAbortHandler),
170 (r"/job/([\w]{8}-[\w]{4}-[\w]{4}-[\w]{4}-[\w]{12})/buildroot", jobs.JobBuildrootHandler),
171 (r"/job/([\w]{8}-[\w]{4}-[\w]{4}-[\w]{4}-[\w]{12})/schedule", jobs.JobScheduleHandler),
9137135a
MT
172
173 # Builders
eab000f0 174 (r"/builders", builders.BuilderListHandler),
1ca1e588
MT
175 (r"/builders/new", builders.BuilderNewHandler),
176 (r"/builders/([A-Za-z0-9\-\.]+)/enable", builders.BuilderEnableHander),
177 (r"/builders/([A-Za-z0-9\-\.]+)/disable", builders.BuilderDisableHander),
178 (r"/builders/([A-Za-z0-9\-\.]+)/delete", builders.BuilderDeleteHandler),
179 (r"/builders/([A-Za-z0-9\-\.]+)/edit", builders.BuilderEditHandler),
180 (r"/builders/([A-Za-z0-9\-\.]+)/renew", builders.BuilderRenewPassphraseHandler),
181 (r"/builders/([A-Za-z0-9\-\.]+)", builders.BuilderDetailHandler),
182 (r"/builder/([A-Za-z0-9\-\.]+)", builders.RedirectHandler),
9137135a 183
9137135a 184 # Distributions
8111065a
MT
185 (r"/distros", distributions.DistributionListHandler),
186 (r"/distro/([A-Za-z0-9\-\.]+)", distributions.DistributionDetailHandler),
f6e6ff79
MT
187
188 # XXX THOSE URLS ARE DEPRECATED
8111065a
MT
189 (r"/distribution/delete/([A-Za-z0-9\-\.]+)", distributions.DistributionDetailHandler),
190 (r"/distribution/edit/([A-Za-z0-9\-\.]+)", distributions.DistributionEditHandler),
f6e6ff79
MT
191
192 (r"/distro/([A-Za-z0-9\-\.]+)/repo/([A-Za-z0-9\-]+)",
193 RepositoryDetailHandler),
194 (r"/distro/([A-Za-z0-9\-\.]+)/repo/([A-Za-z0-9\-]+)\.repo",
195 RepositoryConfHandler),
196 (r"/distro/([A-Za-z0-9\-\.]+)/repo/([A-Za-z0-9\-]+)/mirrorlist",
197 RepositoryMirrorlistHandler),
198 (r"/distro/([A-Za-z0-9\-\.]+)/repo/([A-Za-z0-9\-]+)/edit",
199 RepositoryEditHandler),
200
201 (r"/distro/([A-Za-z0-9\-\.]+)/source/([A-Za-z0-9\-\.]+)",
8111065a 202 distributions.DistroSourceDetailHandler),
f6e6ff79 203 (r"/distro/([A-Za-z0-9\-\.]+)/source/([A-Za-z0-9\-\.]+)/commits",
8111065a 204 distributions.DistroSourceCommitsHandler),
f6e6ff79 205 (r"/distro/([A-Za-z0-9\-\.]+)/source/([A-Za-z0-9\-\.]+)/([\w]{40})",
8111065a 206 distributions.DistroSourceCommitDetailHandler),
f6e6ff79 207 (r"/distro/([A-Za-z0-9\-\.]+)/source/([A-Za-z0-9\-\.]+)/([\w]{40})/reset",
8111065a 208 distributions.DistroSourceCommitResetHandler),
f6e6ff79
MT
209
210 (r"/distro/([A-Za-z0-9\-\.]+)/update/create",
8111065a 211 distributions.DistroUpdateCreateHandler),
f6e6ff79 212 (r"/distro/([A-Za-z0-9\-\.]+)/update/(\d+)/(\d+)",
8111065a 213 distributions.DistroUpdateDetailHandler),
f6e6ff79
MT
214
215 # Updates
156b826e 216 (r"/updates", updates.UpdatesHandler),
f6e6ff79
MT
217
218 # Mirrors
16f90605
MT
219 (r"/mirrors", mirrors.MirrorListHandler),
220 (r"/mirror/new", mirrors.MirrorNewHandler),
221 (r"/mirror/([\w\-\.]+)/delete", mirrors.MirrorDeleteHandler),
222 (r"/mirror/([\w\-\.]+)/edit", mirrors.MirrorEditHandler),
223 (r"/mirror/([\w\-\.]+)", mirrors.MirrorDetailHandler),
f6e6ff79
MT
224
225 # Key management
f44a3f0d
MT
226 (r"/keys", keys.KeysListHandler),
227 (r"/key/import", keys.KeysImportHandler),
228 (r"/key/([A-Z0-9]+)", keys.KeysDownloadHandler),
229 (r"/key/([A-Z0-9]+)/delete", keys.KeysDeleteHandler),
f6e6ff79 230
9137135a 231 # Search
b8b310ec 232 (r"/search", search.SearchHandler),
9137135a 233
f6e6ff79
MT
234 # Uploads
235 (r"/uploads", UploadsHandler),
9137135a
MT
236
237 # Log
238 (r"/log", LogHandler),
9137135a 239
20d7f5eb
MT
240 # Sessions
241 (r"/sessions", SessionsHandler),
242
35c46db4 243 # API handlers
b0e50a58 244 (r"/api/packages/autocomplete", api.ApiPackagesAutocomplete),
5cf8c7ea 245 ], default_handler_class=errors.Error404Handler, **settings)
9137135a
MT
246
247 logging.info("Successfully initialied application")
248
4b9167ef
MT
249 @lazy_property
250 def backend(self):
251 """
252 Backend connection
253 """
254 return Backend()
f6e6ff79 255
9137135a
MT
256 def __del__(self):
257 logging.info("Shutting down application")
258
259 @property
260 def ioloop(self):
261 return tornado.ioloop.IOLoop.instance()
262
263 def shutdown(self, *args):
264 logging.debug("Caught shutdown signal")
265 self.ioloop.stop()
266
51db04b0 267 def run(self, port=7001):
9137135a
MT
268 logging.debug("Going to background")
269
9137135a
MT
270 http_server = tornado.httpserver.HTTPServer(self, xheaders=True)
271
272 # If we are not running in debug mode, we can actually run multiple
273 # frontends to get best performance out of our service.
51db04b0 274 if self.settings.get("debug", False):
9137135a 275 http_server.listen(port)
51db04b0
MT
276 else:
277 cpu_count = multiprocessing.cpu_count()
278
279 http_server.bind(port)
280 http_server.start(num_processes=cpu_count)
9137135a 281
f6e6ff79
MT
282 # All requests should be done after 60 seconds or they will be killed.
283 self.ioloop.set_blocking_log_threshold(60)
284
9137135a
MT
285 self.ioloop.start()
286
287 def reload(self):
288 logging.debug("Caught reload signal")
bc293d03
MT
289
290 ## UI methods
291
7514d7dc 292 def format_time(self, handler, s, shorter=False):
bc293d03
MT
293 _ = handler.locale.translate
294
295 hrs, s = divmod(s, 3600)
296 min, s = divmod(s, 60)
297
298 if s >= 30:
299 min += 1
300
7514d7dc
MT
301 if shorter and not hrs:
302 return _("%(min)d min") % { "min" : min }
303
bc293d03 304 return _("%(hrs)d:%(min)02d hrs") % {"hrs" : hrs, "min" : min}
a90bd9b0
MT
305
306 def format_time_short(self, handler, s):
307 _ = handler.locale.translate
308
309 hrs = s / 3600
310 if hrs >= 1:
311 return _("%dh") % hrs
312
313 min = s / 60
314 if min >= 1:
315 return _("%dm") % min
316
317 return _("%ds") % s