##// END OF EJS Templates
fixed problem with rawfile content_disposition attachment,...
marcink -
r1102:8d085837 beta
parent child Browse files
Show More
@@ -1,293 +1,293 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.controllers.files
3 rhodecode.controllers.files
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
5
5
6 Files controller for RhodeCode
6 Files controller for RhodeCode
7
7
8 :created_on: Apr 21, 2010
8 :created_on: Apr 21, 2010
9 :author: marcink
9 :author: marcink
10 :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
10 :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
11 :license: GPLv3, see COPYING for more details.
11 :license: GPLv3, see COPYING for more details.
12 """
12 """
13 # This program is free software; you can redistribute it and/or
13 # This program is free software; you can redistribute it and/or
14 # modify it under the terms of the GNU General Public License
14 # modify it under the terms of the GNU General Public License
15 # as published by the Free Software Foundation; version 2
15 # as published by the Free Software Foundation; version 2
16 # of the License or (at your opinion) any later version of the license.
16 # of the License or (at your opinion) any later version of the license.
17 #
17 #
18 # This program is distributed in the hope that it will be useful,
18 # This program is distributed in the hope that it will be useful,
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # GNU General Public License for more details.
21 # GNU General Public License for more details.
22 #
22 #
23 # You should have received a copy of the GNU General Public License
23 # You should have received a copy of the GNU General Public License
24 # along with this program; if not, write to the Free Software
24 # along with this program; if not, write to the Free Software
25 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
25 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
26 # MA 02110-1301, USA.
26 # MA 02110-1301, USA.
27 import logging
27 import logging
28 import rhodecode.lib.helpers as h
28 import rhodecode.lib.helpers as h
29
29
30 from pylons import request, response, session, tmpl_context as c, url
30 from pylons import request, response, session, tmpl_context as c, url
31 from pylons.i18n.translation import _
31 from pylons.i18n.translation import _
32 from pylons.controllers.util import redirect
32 from pylons.controllers.util import redirect
33
33
34 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
34 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
35 from rhodecode.lib.base import BaseRepoController, render
35 from rhodecode.lib.base import BaseRepoController, render
36 from rhodecode.lib.utils import EmptyChangeset
36 from rhodecode.lib.utils import EmptyChangeset
37 from rhodecode.model.repo import RepoModel
37 from rhodecode.model.repo import RepoModel
38
38
39 from vcs.backends import ARCHIVE_SPECS
39 from vcs.backends import ARCHIVE_SPECS
40 from vcs.exceptions import RepositoryError, ChangesetError, \
40 from vcs.exceptions import RepositoryError, ChangesetError, \
41 ChangesetDoesNotExistError, EmptyRepositoryError, ImproperArchiveTypeError, \
41 ChangesetDoesNotExistError, EmptyRepositoryError, ImproperArchiveTypeError, \
42 VCSError
42 VCSError
43 from vcs.nodes import FileNode, NodeKind
43 from vcs.nodes import FileNode, NodeKind
44 from vcs.utils import diffs as differ
44 from vcs.utils import diffs as differ
45
45
46 log = logging.getLogger(__name__)
46 log = logging.getLogger(__name__)
47
47
48 class FilesController(BaseRepoController):
48 class FilesController(BaseRepoController):
49
49
50 @LoginRequired()
50 @LoginRequired()
51 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
51 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
52 'repository.admin')
52 'repository.admin')
53 def __before__(self):
53 def __before__(self):
54 super(FilesController, self).__before__()
54 super(FilesController, self).__before__()
55 c.cut_off_limit = self.cut_off_limit
55 c.cut_off_limit = self.cut_off_limit
56
56
57 def __get_cs(self, rev, repo_name):
57 def __get_cs(self, rev, repo_name):
58 """
58 """
59 Safe way to get changeset if error ucure it redirects to given
59 Safe way to get changeset if error ucure it redirects to given
60 :param rev: revision to fetch
60 :param rev: revision to fetch
61 :param repo_name: repo name to redirect after
61 :param repo_name: repo name to redirect after
62 """
62 """
63
63
64 try:
64 try:
65 return c.rhodecode_repo.get_changeset(rev)
65 return c.rhodecode_repo.get_changeset(rev)
66 except EmptyRepositoryError, e:
66 except EmptyRepositoryError, e:
67 h.flash(_('There are no files yet'), category='warning')
67 h.flash(_('There are no files yet'), category='warning')
68 redirect(h.url('summary_home', repo_name=repo_name))
68 redirect(h.url('summary_home', repo_name=repo_name))
69
69
70 except RepositoryError, e:
70 except RepositoryError, e:
71 h.flash(str(e), category='warning')
71 h.flash(str(e), category='warning')
72 redirect(h.url('files_home', repo_name=repo_name, revision='tip'))
72 redirect(h.url('files_home', repo_name=repo_name, revision='tip'))
73
73
74 def index(self, repo_name, revision, f_path):
74 def index(self, repo_name, revision, f_path):
75
75
76 try:
76 try:
77 #reditect to given revision from form
77 #reditect to given revision from form
78 post_revision = request.POST.get('at_rev', None)
78 post_revision = request.POST.get('at_rev', None)
79 if post_revision:
79 if post_revision:
80 post_revision = c.rhodecode_repo.get_changeset(post_revision).raw_id
80 post_revision = c.rhodecode_repo.get_changeset(post_revision).raw_id
81 redirect(url('files_home', repo_name=c.repo_name,
81 redirect(url('files_home', repo_name=c.repo_name,
82 revision=post_revision, f_path=f_path))
82 revision=post_revision, f_path=f_path))
83
83
84 c.branch = request.GET.get('branch', None)
84 c.branch = request.GET.get('branch', None)
85
85
86 c.f_path = f_path
86 c.f_path = f_path
87
87
88 c.changeset = c.rhodecode_repo.get_changeset(revision)
88 c.changeset = c.rhodecode_repo.get_changeset(revision)
89 cur_rev = c.changeset.revision
89 cur_rev = c.changeset.revision
90
90
91 #prev link
91 #prev link
92 try:
92 try:
93 prev_rev = c.rhodecode_repo.get_changeset(cur_rev).prev(c.branch).raw_id
93 prev_rev = c.rhodecode_repo.get_changeset(cur_rev).prev(c.branch).raw_id
94 c.url_prev = url('files_home', repo_name=c.repo_name,
94 c.url_prev = url('files_home', repo_name=c.repo_name,
95 revision=prev_rev, f_path=f_path)
95 revision=prev_rev, f_path=f_path)
96 if c.branch:
96 if c.branch:
97 c.url_prev += '?branch=%s' % c.branch
97 c.url_prev += '?branch=%s' % c.branch
98 except (ChangesetDoesNotExistError, VCSError):
98 except (ChangesetDoesNotExistError, VCSError):
99 c.url_prev = '#'
99 c.url_prev = '#'
100
100
101 #next link
101 #next link
102 try:
102 try:
103 next_rev = c.rhodecode_repo.get_changeset(cur_rev).next(c.branch).raw_id
103 next_rev = c.rhodecode_repo.get_changeset(cur_rev).next(c.branch).raw_id
104 c.url_next = url('files_home', repo_name=c.repo_name,
104 c.url_next = url('files_home', repo_name=c.repo_name,
105 revision=next_rev, f_path=f_path)
105 revision=next_rev, f_path=f_path)
106 if c.branch:
106 if c.branch:
107 c.url_next += '?branch=%s' % c.branch
107 c.url_next += '?branch=%s' % c.branch
108 except (ChangesetDoesNotExistError, VCSError):
108 except (ChangesetDoesNotExistError, VCSError):
109 c.url_next = '#'
109 c.url_next = '#'
110
110
111 #files
111 #files
112 try:
112 try:
113 c.files_list = c.changeset.get_node(f_path)
113 c.files_list = c.changeset.get_node(f_path)
114 c.file_history = self._get_history(c.rhodecode_repo, c.files_list, f_path)
114 c.file_history = self._get_history(c.rhodecode_repo, c.files_list, f_path)
115 except RepositoryError, e:
115 except RepositoryError, e:
116 h.flash(str(e), category='warning')
116 h.flash(str(e), category='warning')
117 redirect(h.url('files_home', repo_name=repo_name, revision=revision))
117 redirect(h.url('files_home', repo_name=repo_name, revision=revision))
118
118
119 except EmptyRepositoryError, e:
119 except EmptyRepositoryError, e:
120 h.flash(_('There are no files yet'), category='warning')
120 h.flash(_('There are no files yet'), category='warning')
121 redirect(h.url('summary_home', repo_name=repo_name))
121 redirect(h.url('summary_home', repo_name=repo_name))
122
122
123 except RepositoryError, e:
123 except RepositoryError, e:
124 h.flash(str(e), category='warning')
124 h.flash(str(e), category='warning')
125 redirect(h.url('files_home', repo_name=repo_name, revision='tip'))
125 redirect(h.url('files_home', repo_name=repo_name, revision='tip'))
126
126
127
127
128
128
129 return render('files/files.html')
129 return render('files/files.html')
130
130
131 def rawfile(self, repo_name, revision, f_path):
131 def rawfile(self, repo_name, revision, f_path):
132 cs = self.__get_cs(revision, repo_name)
132 cs = self.__get_cs(revision, repo_name)
133 try:
133 try:
134 file_node = cs.get_node(f_path)
134 file_node = cs.get_node(f_path)
135 except RepositoryError, e:
135 except RepositoryError, e:
136 h.flash(str(e), category='warning')
136 h.flash(str(e), category='warning')
137 redirect(h.url('files_home', repo_name=repo_name, revision=cs.raw_id))
137 redirect(h.url('files_home', repo_name=repo_name, revision=cs.raw_id))
138
138
139 fname = f_path.split('/')[-1].encode('utf8', 'replace')
139 response.content_type = file_node.mimetype
140 response.content_type = file_node.mimetype
140 response.content_disposition = 'attachment; filename=%s' \
141 response.content_disposition = 'attachment; filename=%s' % fname
141 % f_path.split('/')[-1]
142 return file_node.content
142 return file_node.content
143
143
144 def raw(self, repo_name, revision, f_path):
144 def raw(self, repo_name, revision, f_path):
145 cs = self.__get_cs(revision, repo_name)
145 cs = self.__get_cs(revision, repo_name)
146 try:
146 try:
147 file_node = cs.get_node(f_path)
147 file_node = cs.get_node(f_path)
148 except RepositoryError, e:
148 except RepositoryError, e:
149 h.flash(str(e), category='warning')
149 h.flash(str(e), category='warning')
150 redirect(h.url('files_home', repo_name=repo_name, revision=cs.raw_id))
150 redirect(h.url('files_home', repo_name=repo_name, revision=cs.raw_id))
151
151
152 response.content_type = 'text/plain'
152 response.content_type = 'text/plain'
153
153
154 return file_node.content
154 return file_node.content
155
155
156 def annotate(self, repo_name, revision, f_path):
156 def annotate(self, repo_name, revision, f_path):
157 cs = self.__get_cs(revision, repo_name)
157 cs = self.__get_cs(revision, repo_name)
158 try:
158 try:
159 c.file = cs.get_node(f_path)
159 c.file = cs.get_node(f_path)
160 except RepositoryError, e:
160 except RepositoryError, e:
161 h.flash(str(e), category='warning')
161 h.flash(str(e), category='warning')
162 redirect(h.url('files_home', repo_name=repo_name, revision=cs.raw_id))
162 redirect(h.url('files_home', repo_name=repo_name, revision=cs.raw_id))
163
163
164 c.file_history = self._get_history(c.rhodecode_repo, c.file, f_path)
164 c.file_history = self._get_history(c.rhodecode_repo, c.file, f_path)
165 c.cs = cs
165 c.cs = cs
166 c.f_path = f_path
166 c.f_path = f_path
167
167
168 return render('files/files_annotate.html')
168 return render('files/files_annotate.html')
169
169
170 def archivefile(self, repo_name, fname):
170 def archivefile(self, repo_name, fname):
171
171
172 fileformat = None
172 fileformat = None
173 revision = None
173 revision = None
174 ext = None
174 ext = None
175
175
176 for a_type, ext_data in ARCHIVE_SPECS.items():
176 for a_type, ext_data in ARCHIVE_SPECS.items():
177 archive_spec = fname.split(ext_data[1])
177 archive_spec = fname.split(ext_data[1])
178 if len(archive_spec) == 2 and archive_spec[1] == '':
178 if len(archive_spec) == 2 and archive_spec[1] == '':
179 fileformat = a_type or ext_data[1]
179 fileformat = a_type or ext_data[1]
180 revision = archive_spec[0]
180 revision = archive_spec[0]
181 ext = ext_data[1]
181 ext = ext_data[1]
182
182
183 try:
183 try:
184 dbrepo = RepoModel().get_by_repo_name(repo_name)
184 dbrepo = RepoModel().get_by_repo_name(repo_name)
185 if dbrepo.enable_downloads is False:
185 if dbrepo.enable_downloads is False:
186 return _('downloads disabled')
186 return _('downloads disabled')
187
187
188 cs = c.rhodecode_repo.get_changeset(revision)
188 cs = c.rhodecode_repo.get_changeset(revision)
189 content_type = ARCHIVE_SPECS[fileformat][0]
189 content_type = ARCHIVE_SPECS[fileformat][0]
190 except ChangesetDoesNotExistError:
190 except ChangesetDoesNotExistError:
191 return _('Unknown revision %s') % revision
191 return _('Unknown revision %s') % revision
192 except EmptyRepositoryError:
192 except EmptyRepositoryError:
193 return _('Empty repository')
193 return _('Empty repository')
194 except (ImproperArchiveTypeError, KeyError):
194 except (ImproperArchiveTypeError, KeyError):
195 return _('Unknown archive type')
195 return _('Unknown archive type')
196
196
197 response.content_type = content_type
197 response.content_type = content_type
198 response.content_disposition = 'attachment; filename=%s-%s%s' \
198 response.content_disposition = 'attachment; filename=%s-%s%s' \
199 % (repo_name, revision, ext)
199 % (repo_name, revision, ext)
200
200
201 return cs.get_chunked_archive(kind=fileformat)
201 return cs.get_chunked_archive(kind=fileformat)
202
202
203
203
204 def diff(self, repo_name, f_path):
204 def diff(self, repo_name, f_path):
205 diff1 = request.GET.get('diff1')
205 diff1 = request.GET.get('diff1')
206 diff2 = request.GET.get('diff2')
206 diff2 = request.GET.get('diff2')
207 c.action = request.GET.get('diff')
207 c.action = request.GET.get('diff')
208 c.no_changes = diff1 == diff2
208 c.no_changes = diff1 == diff2
209 c.f_path = f_path
209 c.f_path = f_path
210
210
211 try:
211 try:
212 if diff1 not in ['', None, 'None', '0' * 12, '0' * 40]:
212 if diff1 not in ['', None, 'None', '0' * 12, '0' * 40]:
213 c.changeset_1 = c.rhodecode_repo.get_changeset(diff1)
213 c.changeset_1 = c.rhodecode_repo.get_changeset(diff1)
214 node1 = c.changeset_1.get_node(f_path)
214 node1 = c.changeset_1.get_node(f_path)
215 else:
215 else:
216 c.changeset_1 = EmptyChangeset()
216 c.changeset_1 = EmptyChangeset()
217 node1 = FileNode('.', '', changeset=c.changeset_1)
217 node1 = FileNode('.', '', changeset=c.changeset_1)
218
218
219 if diff2 not in ['', None, 'None', '0' * 12, '0' * 40]:
219 if diff2 not in ['', None, 'None', '0' * 12, '0' * 40]:
220 c.changeset_2 = c.rhodecode_repo.get_changeset(diff2)
220 c.changeset_2 = c.rhodecode_repo.get_changeset(diff2)
221 node2 = c.changeset_2.get_node(f_path)
221 node2 = c.changeset_2.get_node(f_path)
222 else:
222 else:
223 c.changeset_2 = EmptyChangeset()
223 c.changeset_2 = EmptyChangeset()
224 node2 = FileNode('.', '', changeset=c.changeset_2)
224 node2 = FileNode('.', '', changeset=c.changeset_2)
225 except RepositoryError:
225 except RepositoryError:
226 return redirect(url('files_home',
226 return redirect(url('files_home',
227 repo_name=c.repo_name, f_path=f_path))
227 repo_name=c.repo_name, f_path=f_path))
228
228
229
229
230 if c.action == 'download':
230 if c.action == 'download':
231 diff = differ.DiffProcessor(differ.get_gitdiff(node1, node2))
231 diff = differ.DiffProcessor(differ.get_gitdiff(node1, node2))
232
232
233 diff_name = '%s_vs_%s.diff' % (diff1, diff2)
233 diff_name = '%s_vs_%s.diff' % (diff1, diff2)
234 response.content_type = 'text/plain'
234 response.content_type = 'text/plain'
235 response.content_disposition = 'attachment; filename=%s' \
235 response.content_disposition = 'attachment; filename=%s' \
236 % diff_name
236 % diff_name
237 return diff.raw_diff()
237 return diff.raw_diff()
238
238
239 elif c.action == 'raw':
239 elif c.action == 'raw':
240 diff = differ.DiffProcessor(differ.get_gitdiff(node1, node2))
240 diff = differ.DiffProcessor(differ.get_gitdiff(node1, node2))
241 response.content_type = 'text/plain'
241 response.content_type = 'text/plain'
242 return diff.raw_diff()
242 return diff.raw_diff()
243
243
244 elif c.action == 'diff':
244 elif c.action == 'diff':
245 diff = differ.DiffProcessor(differ.get_udiff(node1, node2))
245 diff = differ.DiffProcessor(differ.get_udiff(node1, node2))
246
246
247 if node1.size > self.cut_off_limit or node2.size > self.cut_off_limit:
247 if node1.size > self.cut_off_limit or node2.size > self.cut_off_limit:
248 c.cur_diff = _('Diff is to big to display')
248 c.cur_diff = _('Diff is to big to display')
249 elif node1.is_binary or node2.is_binary:
249 elif node1.is_binary or node2.is_binary:
250 c.cur_diff = _('Binary file')
250 c.cur_diff = _('Binary file')
251 else:
251 else:
252 c.cur_diff = diff.as_html()
252 c.cur_diff = diff.as_html()
253 else:
253 else:
254 diff = differ.DiffProcessor(differ.get_udiff(node1, node2))
254 diff = differ.DiffProcessor(differ.get_udiff(node1, node2))
255 #default option
255 #default option
256 if node1.size > self.cut_off_limit or node2.size > self.cut_off_limit:
256 if node1.size > self.cut_off_limit or node2.size > self.cut_off_limit:
257 c.cur_diff = _('Diff is to big to display')
257 c.cur_diff = _('Diff is to big to display')
258 elif node1.is_binary or node2.is_binary:
258 elif node1.is_binary or node2.is_binary:
259 c.cur_diff = _('Binary file')
259 c.cur_diff = _('Binary file')
260 else:
260 else:
261 c.cur_diff = diff.as_html()
261 c.cur_diff = diff.as_html()
262
262
263 if not c.cur_diff: c.no_changes = True
263 if not c.cur_diff: c.no_changes = True
264 return render('files/file_diff.html')
264 return render('files/file_diff.html')
265
265
266 def _get_history(self, repo, node, f_path):
266 def _get_history(self, repo, node, f_path):
267 if not node.kind is NodeKind.FILE:
267 if not node.kind is NodeKind.FILE:
268 return []
268 return []
269 changesets = node.history
269 changesets = node.history
270 hist_l = []
270 hist_l = []
271
271
272 changesets_group = ([], _("Changesets"))
272 changesets_group = ([], _("Changesets"))
273 branches_group = ([], _("Branches"))
273 branches_group = ([], _("Branches"))
274 tags_group = ([], _("Tags"))
274 tags_group = ([], _("Tags"))
275
275
276 for chs in changesets:
276 for chs in changesets:
277 n_desc = 'r%s:%s' % (chs.revision, chs.short_id)
277 n_desc = 'r%s:%s' % (chs.revision, chs.short_id)
278 changesets_group[0].append((chs.raw_id, n_desc,))
278 changesets_group[0].append((chs.raw_id, n_desc,))
279
279
280 hist_l.append(changesets_group)
280 hist_l.append(changesets_group)
281
281
282 for name, chs in c.rhodecode_repo.branches.items():
282 for name, chs in c.rhodecode_repo.branches.items():
283 #chs = chs.split(':')[-1]
283 #chs = chs.split(':')[-1]
284 branches_group[0].append((chs, name),)
284 branches_group[0].append((chs, name),)
285 hist_l.append(branches_group)
285 hist_l.append(branches_group)
286
286
287 for name, chs in c.rhodecode_repo.tags.items():
287 for name, chs in c.rhodecode_repo.tags.items():
288 #chs = chs.split(':')[-1]
288 #chs = chs.split(':')[-1]
289 tags_group[0].append((chs, name),)
289 tags_group[0].append((chs, name),)
290 hist_l.append(tags_group)
290 hist_l.append(tags_group)
291
291
292 return hist_l
292 return hist_l
293
293
General Comments 0
You need to be logged in to leave comments. Login now