]> git.ipfire.org Git - pbs.git/blob - src/web/packages.py
Stop crawlers from indexing package content
[pbs.git] / src / web / packages.py
1 #!/usr/bin/python
2
3 import mimetypes
4 import os.path
5 import tornado.web
6
7 from . import base
8
9 from ..constants import BUFFER_SIZE
10
11 class IndexHandler(base.BaseHandler):
12 def get(self):
13 # Sort all packages in an array like "<first char>" --> [packages, ...]
14 # to print them in a table for each letter of the alphabet.
15 packages = {}
16
17 for pkg in self.backend.packages.get_list():
18 c = pkg.name[0].lower()
19
20 try:
21 packages[c].append(pkg)
22 except KeyError:
23 packages[c] = [pkg]
24
25 self.render("packages/index.html", packages=packages)
26
27
28 class PackageIDDetailHandler(base.BaseHandler):
29 def get(self, id):
30 package = self.packages.get_by_id(id)
31 if not package:
32 return tornado.web.HTTPError(404, "Package not found: %s" % id)
33
34 self.render("package-detail.html", package=package)
35
36
37 class PackageNameHandler(base.BaseHandler):
38 def get(self, name):
39 builds = self.backend.builds.get_active_builds(name)
40 if not builds:
41 raise tornado.web.HTTPError(404, "Package '%s' was not found" % name)
42
43 # Get the latest build to show the package meta information.
44 latest_build = builds[0]
45
46 # Get the latest bugs from bugzilla.
47 bugs = self.backend.bugzilla.get_bugs_from_component(name)
48
49 self.render("package-detail-list.html", name=name, builds=builds,
50 latest_build=latest_build, pkg=latest_build.pkg, bugs=bugs)
51
52
53 class PackageScratchBuildsHandler(base.BaseHandler):
54 def get(self, name):
55 offset = self.get_argument("offset", 0)
56 limit = self.get_argument("limit", 10)
57
58 scratch_builds = self.backend.builds.get_by_name(name, type="scratch",
59 limit=limit, offset=offset)
60
61 if scratch_builds:
62 latest_build = scratch_builds[0]
63 else:
64 release_builds = self.backend.builds.get_by_name(name, type="release", limit=1)
65 if not release_builds:
66 raise tornado.web.HTTPError(404, "Could not find any build with this name: %s" % name)
67
68 latest_build = release_builds[0]
69
70 self.render("packages/builds/scratch.html", builds=scratch_builds,
71 pkg=latest_build.pkg)
72
73
74 class PackageChangelogHandler(base.BaseHandler):
75 def get(self, name):
76 limit = self.get_argument("limit", 10)
77 try:
78 limit = int(limit)
79
80 except ValueError:
81 limit = 10
82
83 offset = self.get_argument("offset", 0)
84 try:
85 offset = int(offset)
86 except ValueError:
87 offset = 0
88
89 # Get one more build than requested to find out if there are more items
90 # to display (next button).
91 builds = self.backend.builds.get_changelog(name, limit=limit + 1, offset=offset)
92
93 if len(builds) >= limit:
94 have_next = True
95 else:
96 have_next = False
97
98 if offset < limit:
99 have_prev = False
100 else:
101 have_prev = True
102
103 # Clip list to limit.
104 builds = builds[:limit]
105
106 self.render("packages/changelog.html", name=name, builds=builds,
107 limit=limit, offset=offset, have_prev=have_prev, have_next=have_next)
108
109
110 class PackageDetailHandler(base.BaseHandler):
111 def get(self, uuid):
112 pkg = self.backend.packages.get_by_uuid(uuid)
113 if not pkg:
114 raise tornado.web.HTTPError(404, "Package not found: %s" % uuid)
115
116 self.render("package-detail.html", pkg=pkg)
117
118 @tornado.web.authenticated
119 def post(self, name, epoch, version, release):
120 pkg = self.backend.packages.get_by_tuple(name, epoch, version, release)
121
122 action = self.get_argument("action", None)
123
124 if action == "comment":
125 pkg.comment(self.current_user.id, self.get_argument("text"),
126 self.get_argument("vote", None) or "none")
127
128 self.render("package-detail.html", pkg=pkg)
129
130
131 class PackagePropertiesHandler(base.BaseHandler):
132 @tornado.web.authenticated
133 def get(self, name):
134 build = self.backend.builds.get_latest_by_name(name)
135
136 if not build:
137 raise tornado.web.HTTPError(404, "Package '%s' was not found" % name)
138
139 # Check if the user has sufficient permissions.
140 if not build.has_perm(self.current_user):
141 raise tornado.web.HTTPError(403, "User %s is not allowed to manage build %s" \
142 % (self.current_user, build))
143
144 self.render("package-properties.html", build=build,
145 pkg=build.pkg, properties=build.pkg.properties)
146
147 @tornado.web.authenticated
148 def post(self, name):
149 build = self.backend.builds.get_latest_by_name(name)
150
151 if not build:
152 raise tornado.web.HTTPError(404, "Package '%s' was not found" % name)
153
154 # Check if the user has sufficient permissions.
155 if not build.has_perm(self.current_user):
156 raise tornado.web.HTTPError(403, "User %s is not allowed to manage build %s" \
157 % (self.current_user, build))
158
159 critical_path = self.get_argument("critical_path", False)
160 if critical_path:
161 critical_path = True
162 else:
163 critical_path = False
164 build.pkg.update_property("critical_path", critical_path)
165
166
167 class PackageFileDownloadHandler(base.BaseHandler):
168 def get_file(self, pkg_uuid, filename):
169 # Fetch package.
170 pkg = self.backend.packages.get_by_uuid(pkg_uuid)
171 if not pkg:
172 raise tornado.web.HTTPError(404, "Package not found: %s" % pkg_uuid)
173
174 # Check if the package has got a file with the given name.
175 file = pkg.get_file(filename)
176 if not file:
177 raise tornado.web.HTTPError(404, "Package %s does not contain file %s" % (pkg, filename))
178
179 # Open the package in the filesystem.
180 pkg_file = pkg.open()
181 if not pkg_file:
182 raise tornado.web.HTTPError(404, "Could not open package %s" % pkg.path)
183
184 # Open the file to transfer it to the client.
185 f = pkg_file.open_file(filename)
186 if not f:
187 raise tornado.web.HTTPError(404, "Package %s does not contain file %s" % (pkg_file, filename))
188
189 # Guess the MIME type of the file.
190 (type, encoding) = mimetypes.guess_type(filename)
191 if not type:
192 type = "text/plain"
193
194 return (pkg, f, type)
195
196 def get(self, pkg_uuid, filename):
197 pkg, f, mimetype = self.get_file(pkg_uuid, filename)
198
199 # Send the filename and mimetype in header.
200 self.set_header("Content-Disposition", "attachment; filename=%s" % os.path.basename(filename))
201 self.set_header("Content-Type", mimetype)
202
203 # These pages should not be indexed
204 self.add_header("X-Robots-Tag", "noindex")
205
206 # Transfer the content chunk by chunk.
207 while True:
208 buf = f.read(BUFFER_SIZE)
209 if not buf:
210 break
211
212 self.write(buf)
213
214 f.close()
215
216 # Done.
217 self.finish()
218
219
220 class PackageFileViewHandler(PackageFileDownloadHandler):
221 def get(self, pkg_uuid, filename):
222 pkg, f, mimetype = self.get_file(pkg_uuid, filename)
223
224 # Read in the data.
225 content = f.read()
226 f.close()
227
228 # These pages should not be indexed
229 self.add_header("X-Robots-Tag", "noindex")
230
231 self.render("packages/view-file.html", pkg=pkg, filename=filename,
232 mimetype=mimetype, content=content, filesize=f.size)
233
234
235 class PackageBuildsTimesHandler(base.BaseHandler):
236 def get(self, name):
237 latest_build = self.backend.builds.get_latest_by_name(name)
238
239 # If no build with this name was found, we cannot go on.
240 if not latest_build:
241 raise tornado.web.HTTPError(404)
242
243 # Get the summary stats.
244 build_times_summary = self.backend.builds.get_build_times_summary(name)
245
246 self.render("packages/builds/times.html", pkg=latest_build.pkg,
247 build_times_summary=build_times_summary)