]> git.ipfire.org Git - people/shoehn/ipfire.org.git/blame - www/webapp/handlers.py
Merge branch 'planet' into next
[people/shoehn/ipfire.org.git] / www / webapp / handlers.py
CommitLineData
81675874 1#!/usr/bin/python
2
6b952290 3import datetime
81675874 4import httplib
6b952290 5import mimetypes
e2b0b0e4 6import operator
81675874 7import os
d0d074e0 8import re
81675874 9import simplejson
6b952290 10import stat
e2b0b0e4 11import sqlite3
81675874 12import time
d0d074e0 13import unicodedata
81675874 14import urlparse
15
d0d074e0 16import tornado.database
81675874 17import tornado.httpclient
18import tornado.locale
19import tornado.web
20
21from banners import banners
e48d9ae6 22from helpers import size, Item
d979645d 23from info import info
3add293a 24from mirrors import mirrors
81675874 25from news import news
26from releases import releases
43d991f6 27from torrent import tracker, bencode, bdecode, decode_hex
81675874 28
29import builds
5a1018ab 30import menu
81675874 31import cluster
d0d074e0 32import markdown
81675874 33#import uriel
34
35class BaseHandler(tornado.web.RequestHandler):
36 def get_user_locale(self):
37 uri = self.request.uri.split("/")
38 if len(uri) > 1:
39 for lang in tornado.locale.get_supported_locales(None):
40 if lang[:2] == uri[1]:
41 return tornado.locale.get(lang)
42
43 @property
44 def render_args(self):
45 return {
46 "banner" : banners.get(),
47 "lang" : self.locale.code[:2],
48 "langs" : [l[:2] for l in tornado.locale.get_supported_locales(None)],
49 "lang_link" : self.lang_link,
50 "link" : self.link,
51 "title" : "no title given",
52 "server" : self.request.host.replace("ipfire", "<span>ipfire</span>"),
53 "uri" : self.request.uri,
54 "year" : time.strftime("%Y"),
55 }
56
57 def render(self, *args, **kwargs):
58 nargs = self.render_args
59 nargs.update(kwargs)
53f812d2 60 nargs["hostname"] = self.request.host
81675874 61 tornado.web.RequestHandler.render(self, *args, **nargs)
62
63 def link(self, s):
64 return "/%s/%s" % (self.locale.code[:2], s)
65
66 def lang_link(self, lang):
67 return "/%s/%s" % (lang, self.request.uri[4:])
68
69 def get_error_html(self, status_code, **kwargs):
70 if status_code in (404, 500):
71 render_args = self.render_args
72 render_args.update({
73 "code" : status_code,
74 "exception" : kwargs.get("exception", None),
75 "message" : httplib.responses[status_code],
76 })
77 return self.render_string("error-%s.html" % status_code, **render_args)
78 else:
79 return tornado.web.RequestHandler.get_error_html(self, status_code, **kwargs)
80
4cb3de1c
MT
81 @property
82 def hash_db(self):
83 return self.application.hash_db
81675874 84
d0d074e0
MT
85 @property
86 def planet_db(self):
87 return self.application.planet_db
88
89 @property
90 def user_db(self):
91 return self.application.user_db
92
93
81675874 94class MainHandler(BaseHandler):
95 def get(self):
96 lang = self.locale.code[:2]
97 self.redirect("/%s/index" % (lang))
98
99
100class DownloadHandler(BaseHandler):
101 def get(self):
102 self.render("downloads.html", release=releases.latest)
103
104
105class DownloadAllHandler(BaseHandler):
106 def get(self):
107 self.render("downloads-all.html", releases=releases)
108
109
110class DownloadDevelopmentHandler(BaseHandler):
111 def get(self):
112 self.render("downloads-development.html", releases=releases)
113
114
115class DownloadTorrentHandler(BaseHandler):
116 tracker_url = "http://tracker.ipfire.org:6969/stats?format=txt&mode=tpbs"
117
118 @tornado.web.asynchronous
119 def get(self):
120 http = tornado.httpclient.AsyncHTTPClient()
121 http.fetch(self.tracker_url, callback=self.async_callback(self.on_response))
122
123 def on_response(self, response):
124 torrents = releases.torrents
125 hashes = {}
126 if response.code == 200:
127 for line in response.body.split("\n"):
128 if not line: continue
129 hash, seeds, peers = line.split(":")
130 hash.lower()
131 hashes[hash] = {
132 "peers" : peers,
133 "seeds" : seeds,
134 }
135
136 self.render("downloads-torrents.html",
137 hashes=hashes,
138 releases=torrents,
139 request_time=response.request_time,
140 tracker=urlparse.urlparse(response.request.url).netloc)
141
142
3add293a
MT
143class DownloadMirrorHandler(BaseHandler):
144 def get(self):
145 self.render("downloads-mirrors.html", mirrors=mirrors)
146
147
81675874 148class StaticHandler(BaseHandler):
149 @property
150 def static_path(self):
151 return os.path.join(self.application.settings["template_path"], "static")
152
153 @property
154 def static_files(self):
155 ret = []
156 for filename in os.listdir(self.static_path):
157 if filename.endswith(".html"):
158 ret.append(filename)
159 return ret
160
161 def get(self, name=None):
162 name = "%s.html" % name
163
164 if not name in self.static_files:
165 raise tornado.web.HTTPError(404)
166
167 self.render("static/%s" % name)
168
169
170class IndexHandler(BaseHandler):
171 def get(self):
172 self.render("index.html", news=news)
173
174
175class NewsHandler(BaseHandler):
176 def get(self):
177 self.render("news.html", news=news)
178
179
81675874 180class BuildHandler(BaseHandler):
181 def prepare(self):
182 self.builds = {
183 "<12h" : [],
184 ">12h" : [],
185 ">24h" : [],
186 }
187
188 for build in builds.find():
2e4c4605 189 if (time.time() - float(build.get("date"))) < 12*60*60:
81675874 190 self.builds["<12h"].append(build)
2e4c4605 191 elif (time.time() - float(build.get("date"))) < 24*60*60:
81675874 192 self.builds[">12h"].append(build)
193 else:
194 self.builds[">24h"].append(build)
195
196 for l in self.builds.values():
197 l.sort()
198
199 def get(self):
200 self.render("builds.html", builds=self.builds)
201
202
203class UrielBaseHandler(BaseHandler):
204 #db = uriel.Database()
205 pass
206
207class UrielHandler(UrielBaseHandler):
208 def get(self):
209 pass
210
211
e2b0b0e4 212class SourceHandler(BaseHandler):
e2b0b0e4
MT
213 def get(self):
214 source_path = "/srv/sources"
215 fileobjects = []
216
217 for dir, subdirs, files in os.walk(source_path):
218 if not files:
219 continue
220 for file in files:
221 if file in [f["name"] for f in fileobjects]:
222 continue
223
8ef0879a 224 hash = self.hash_db.get_hash(os.path.join(dir, file))
e2b0b0e4 225
4cb3de1c 226 if not hash:
e2b0b0e4
MT
227 hash = "0000000000000000000000000000000000000000"
228
229 fileobjects.append({
230 "dir" : dir[len(source_path)+1:],
231 "name" : file,
232 "hash" : hash,
233 "size" : size(os.path.getsize(os.path.join(source_path, dir, file))),
234 })
235
e2b0b0e4
MT
236 fileobjects.sort(key=operator.itemgetter("name"))
237
238 self.render("sources.html", files=fileobjects)
6b952290
MT
239
240
241class SourceDownloadHandler(BaseHandler):
6b952290
MT
242 def head(self, path):
243 self.get(path, include_body=False)
244
245 def get(self, path, include_body=True):
246 source_path = "/srv/sources"
247
248 path = os.path.abspath(os.path.join(source_path, path[1:]))
249
250 if not path.startswith(source_path):
251 raise tornado.web.HTTPError(403)
252 if not os.path.exists(path):
253 raise tornado.web.HTTPError(404)
254
255 stat_result = os.stat(path)
256 modified = datetime.datetime.fromtimestamp(stat_result[stat.ST_MTIME])
257
258 self.set_header("Last-Modified", modified)
259 self.set_header("Content-Length", stat_result[stat.ST_SIZE])
260
261 mime_type, encoding = mimetypes.guess_type(path)
262 if mime_type:
263 self.set_header("Content-Type", mime_type)
264
4cb3de1c 265 hash = self.hash_db.get_hash(path)
6b952290
MT
266 if hash:
267 self.set_header("X-Hash-Sha1", "%s" % hash)
268
269 if not include_body:
270 return
271 file = open(path, "r")
272 try:
273 self.write(file.read())
274 finally:
275 file.close()
3add293a
MT
276
277
278class DownloadFileHandler(BaseHandler):
279 def get(self, path):
280 for mirror in mirrors.with_file(path):
281 if not mirror.reachable:
282 continue
283
284 self.redirect(mirror.url + path)
285 return
286
287 raise tornado.web.HTTPError(404)
288
289 def get_error_html(self, status_code, **kwargs):
290 return tornado.web.RequestHandler.get_error_html(self, status_code, **kwargs)
e48d9ae6
MT
291
292
293class RSSHandler(BaseHandler):
294 def get(self, lang):
295 items = []
296 for item in news.get(15):
297 item = Item(**item.args.copy())
298 for attr in ("subject", "content"):
299 if type(item[attr]) == type({}):
300 item[attr] = item[attr][lang]
301 items.append(item)
302
303 self.set_header("Content-Type", "application/rss+xml")
304 self.render("rss.xml", items=items, lang=lang)
43d991f6
MT
305
306
01f86827 307<<<<<<< HEAD
43d991f6 308class TrackerBaseHandler(tornado.web.RequestHandler):
e2afbd6a 309 def get_hexencoded_argument(self, name, all=False):
43d991f6 310 try:
e2afbd6a 311 arguments = self.request.arguments[name]
43d991f6
MT
312 except KeyError:
313 return None
314
e2afbd6a
MT
315 arguments_new = []
316 for argument in arguments:
317 arguments_new.append(decode_hex(argument))
318
319 arguments = arguments_new
320
321 if all:
322 return arguments
323
324 return arguments[0]
43d991f6
MT
325
326 def send_tracker_error(self, error_message):
327 self.write(bencode({"failure reason" : error_message }))
328 self.finish()
329
330class TrackerAnnounceHandler(TrackerBaseHandler):
331 def get(self):
332 self.set_header("Content-Type", "text/plain")
333
334 info_hash = self.get_hexencoded_argument("info_hash")
335 if not info_hash:
336 self.send_tracker_error("Your client forgot to send your torrent's info_hash.")
337 return
338
43d991f6
MT
339 peer = {
340 "id" : self.get_hexencoded_argument("peer_id"),
341 "ip" : self.get_argument("ip", None),
342 "port" : self.get_argument("port", None),
343 "downloaded" : self.get_argument("downloaded", 0),
344 "uploaded" : self.get_argument("uploaded", 0),
345 "left" : self.get_argument("left", 0),
346 }
347
348 event = self.get_argument("event", "")
349 if not event in ("started", "stopped", "completed", ""):
350 self.send_tracker_error("Got unknown event")
351 return
352
353 if peer["ip"]:
354 if peer["ip"].startswith("10.") or \
355 peer["ip"].startswith("172.") or \
356 peer["ip"].startswith("192.168."):
357 peer["ip"] = self.request.remote_ip
358
359 if peer["port"]:
360 peer["port"] = int(peer["port"])
361
362 if peer["port"] < 0 or peer["port"] > 65535:
363 self.send_tracker_error("Port number is not in valid range")
364 return
365
366 eventhandlers = {
367 "started" : tracker.event_started,
368 "stopped" : tracker.event_stopped,
369 "completed" : tracker.event_completed,
370 }
371
372 if event:
373 eventhandlers[event](info_hash, peer["id"])
374
375 tracker.update(hash=info_hash, **peer)
376
e2afbd6a 377 no_peer_id = self.get_argument("no_peer_id", False)
43d991f6
MT
378 numwant = self.get_argument("numwant", tracker.numwant)
379
380 self.write(bencode({
381 "tracker id" : tracker.id,
382 "interval" : tracker.interval,
383 "min interval" : tracker.min_interval,
e2afbd6a
MT
384 "peers" : tracker.get_peers(info_hash, limit=numwant,
385 random=True, no_peer_id=no_peer_id),
43d991f6
MT
386 "complete" : tracker.complete(info_hash),
387 "incomplete" : tracker.incomplete(info_hash),
388 }))
389 self.finish()
e2afbd6a
MT
390
391
392class TrackerScrapeHandler(TrackerBaseHandler):
393 def get(self):
394 info_hashes = self.get_hexencoded_argument("info_hash", all=True)
395
396 self.write(bencode(tracker.scrape(hashes=info_hashes)))
397 self.finish()
01f86827 398=======
d0d074e0
MT
399class PlanetBaseHandler(BaseHandler):
400 @property
401 def db(self):
402 return self.application.planet_db
403
404
405class PlanetMainHandler(PlanetBaseHandler):
406 def get(self):
407 authors = self.db.query("SELECT DISTINCT author_id FROM entries")
408 authors = [a["author_id"] for a in authors]
409
410 users = []
411 for user in self.user_db.users:
412 if user.id in authors:
413 users.append(user)
414
415 entries = self.db.query("SELECT * FROM entries "
416 "ORDER BY published DESC LIMIT 3")
417
418 for entry in entries:
419 entry.author = self.user_db.get_user_by_id(entry.author_id)
420
421 self.render("planet-main.html", entries=entries, authors=users)
422
423
424class PlanetUserHandler(PlanetBaseHandler):
425 def get(self, user):
426 if not user in [u.name for u in self.user_db.users]:
427 raise tornado.web.HTTPError(404, "User is unknown")
428
429 user = self.user_db.get_user_by_name(user)
430
431 entries = self.db.query("SELECT * FROM entries "
432 "WHERE author_id = '%s' ORDER BY published DESC" % (user.id))
433
434 self.render("planet-user.html", entries=entries, user=user)
435
436
437class PlanetPostingHandler(PlanetBaseHandler):
438 def get(self, slug):
439 entry = self.db.get("SELECT * FROM entries WHERE slug = %s", slug)
440
441 if not entry:
442 raise tornado.web.HTTPError(404)
443
444 user = self.user_db.get_user_by_id(entry.author_id)
445 entry.author = user
446
447 self.render("planet-posting.html", entry=entry, user=user)
01f86827 448>>>>>>> planet