Mercurial > kallithea
comparison rhodecode/controllers/files.py @ 1305:166317d464f3 beta
Added server side file editing with commit
author | Marcin Kuzminski <marcin@python-works.com> |
---|---|
date | Tue, 03 May 2011 14:13:37 +0200 |
parents | 64cb9612f9aa |
children | 6e1d24503383 |
comparison
equal
deleted
inserted
replaced
1304:5a96551ee9c0 | 1305:166317d464f3 |
---|---|
24 # along with this program. If not, see <http://www.gnu.org/licenses/>. | 24 # along with this program. If not, see <http://www.gnu.org/licenses/>. |
25 | 25 |
26 import os | 26 import os |
27 import logging | 27 import logging |
28 import mimetypes | 28 import mimetypes |
29 import rhodecode.lib.helpers as h | 29 import traceback |
30 | 30 |
31 from pylons import request, response, session, tmpl_context as c, url | 31 from pylons import request, response, session, tmpl_context as c, url |
32 from pylons.i18n.translation import _ | 32 from pylons.i18n.translation import _ |
33 from pylons.controllers.util import redirect | 33 from pylons.controllers.util import redirect |
34 | |
35 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator | |
36 from rhodecode.lib.base import BaseRepoController, render | |
37 from rhodecode.lib.utils import EmptyChangeset | |
38 from rhodecode.model.repo import RepoModel | |
39 | 34 |
40 from vcs.backends import ARCHIVE_SPECS | 35 from vcs.backends import ARCHIVE_SPECS |
41 from vcs.exceptions import RepositoryError, ChangesetDoesNotExistError, \ | 36 from vcs.exceptions import RepositoryError, ChangesetDoesNotExistError, \ |
42 EmptyRepositoryError, ImproperArchiveTypeError, VCSError | 37 EmptyRepositoryError, ImproperArchiveTypeError, VCSError |
43 from vcs.nodes import FileNode, NodeKind | 38 from vcs.nodes import FileNode, NodeKind |
44 from vcs.utils import diffs as differ | 39 from vcs.utils import diffs as differ |
45 | 40 |
41 from rhodecode.lib import convert_line_endings, detect_mode | |
42 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator | |
43 from rhodecode.lib.base import BaseRepoController, render | |
44 from rhodecode.lib.utils import EmptyChangeset | |
45 import rhodecode.lib.helpers as h | |
46 from rhodecode.model.repo import RepoModel | |
47 | |
46 log = logging.getLogger(__name__) | 48 log = logging.getLogger(__name__) |
47 | 49 |
48 | 50 |
49 class FilesController(BaseRepoController): | 51 class FilesController(BaseRepoController): |
50 | 52 |
51 @LoginRequired() | 53 @LoginRequired() |
52 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', | |
53 'repository.admin') | |
54 def __before__(self): | 54 def __before__(self): |
55 super(FilesController, self).__before__() | 55 super(FilesController, self).__before__() |
56 c.cut_off_limit = self.cut_off_limit | 56 c.cut_off_limit = self.cut_off_limit |
57 | 57 |
58 def __get_cs_or_redirect(self, rev, repo_name): | 58 def __get_cs_or_redirect(self, rev, repo_name): |
93 redirect(h.url('files_home', repo_name=repo_name, | 93 redirect(h.url('files_home', repo_name=repo_name, |
94 revision=cs.raw_id)) | 94 revision=cs.raw_id)) |
95 | 95 |
96 return file_node | 96 return file_node |
97 | 97 |
98 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', | |
99 'repository.admin') | |
98 def index(self, repo_name, revision, f_path): | 100 def index(self, repo_name, revision, f_path): |
99 #reditect to given revision from form if given | 101 #reditect to given revision from form if given |
100 post_revision = request.POST.get('at_rev', None) | 102 post_revision = request.POST.get('at_rev', None) |
101 if post_revision: | 103 if post_revision: |
102 cs = self.__get_cs_or_redirect(post_revision, repo_name) | 104 cs = self.__get_cs_or_redirect(post_revision, repo_name) |
142 redirect(h.url('files_home', repo_name=repo_name, | 144 redirect(h.url('files_home', repo_name=repo_name, |
143 revision=revision)) | 145 revision=revision)) |
144 | 146 |
145 return render('files/files.html') | 147 return render('files/files.html') |
146 | 148 |
149 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', | |
150 'repository.admin') | |
147 def rawfile(self, repo_name, revision, f_path): | 151 def rawfile(self, repo_name, revision, f_path): |
148 cs = self.__get_cs_or_redirect(revision, repo_name) | 152 cs = self.__get_cs_or_redirect(revision, repo_name) |
149 file_node = self.__get_filenode_or_redirect(repo_name, cs, f_path) | 153 file_node = self.__get_filenode_or_redirect(repo_name, cs, f_path) |
150 | 154 |
151 response.content_disposition = 'attachment; filename=%s' % \ | 155 response.content_disposition = 'attachment; filename=%s' % \ |
152 f_path.split(os.sep)[-1].encode('utf8', 'replace') | 156 f_path.split(os.sep)[-1].encode('utf8', 'replace') |
153 | 157 |
154 response.content_type = file_node.mimetype | 158 response.content_type = file_node.mimetype |
155 return file_node.content | 159 return file_node.content |
156 | 160 |
161 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', | |
162 'repository.admin') | |
157 def raw(self, repo_name, revision, f_path): | 163 def raw(self, repo_name, revision, f_path): |
158 cs = self.__get_cs_or_redirect(revision, repo_name) | 164 cs = self.__get_cs_or_redirect(revision, repo_name) |
159 file_node = self.__get_filenode_or_redirect(repo_name, cs, f_path) | 165 file_node = self.__get_filenode_or_redirect(repo_name, cs, f_path) |
160 | 166 |
161 raw_mimetype_mapping = { | 167 raw_mimetype_mapping = { |
196 | 202 |
197 response.content_disposition = dispo | 203 response.content_disposition = dispo |
198 response.content_type = mimetype | 204 response.content_type = mimetype |
199 return file_node.content | 205 return file_node.content |
200 | 206 |
207 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', | |
208 'repository.admin') | |
201 def annotate(self, repo_name, revision, f_path): | 209 def annotate(self, repo_name, revision, f_path): |
202 c.cs = self.__get_cs_or_redirect(revision, repo_name) | 210 c.cs = self.__get_cs_or_redirect(revision, repo_name) |
203 c.file = self.__get_filenode_or_redirect(repo_name, c.cs, f_path) | 211 c.file = self.__get_filenode_or_redirect(repo_name, c.cs, f_path) |
204 | 212 |
205 c.file_history = self._get_node_history(c.cs, f_path) | 213 c.file_history = self._get_node_history(c.cs, f_path) |
206 c.f_path = f_path | 214 c.f_path = f_path |
207 return render('files/files_annotate.html') | 215 return render('files/files_annotate.html') |
208 | 216 |
217 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin') | |
218 def edit(self, repo_name, revision, f_path): | |
219 r_post = request.POST | |
220 | |
221 if c.rhodecode_repo.alias == 'hg': | |
222 from vcs.backends.hg import MercurialInMemoryChangeset as IMC | |
223 elif c.rhodecode_repo.alias == 'git': | |
224 from vcs.backends.git import GitInMemoryChangeset as IMC | |
225 | |
226 c.cs = self.__get_cs_or_redirect(revision, repo_name) | |
227 c.file = self.__get_filenode_or_redirect(repo_name, c.cs, f_path) | |
228 | |
229 c.file_history = self._get_node_history(c.cs, f_path) | |
230 c.f_path = f_path | |
231 | |
232 if r_post: | |
233 | |
234 old_content = c.file.content | |
235 # modes: 0 - Unix, 1 - Mac, 2 - DOS | |
236 mode = detect_mode(old_content.splitlines(1)[0], 0) | |
237 content = convert_line_endings(r_post.get('content'), mode) | |
238 message = r_post.get('message') or (_('Edited %s via RhodeCode') | |
239 % (f_path)) | |
240 | |
241 if content == old_content: | |
242 h.flash(_('No changes'), | |
243 category='warning') | |
244 return redirect(url('changeset_home', | |
245 repo_name=c.repo_name, revision='tip')) | |
246 try: | |
247 new_node = FileNode(f_path, content) | |
248 m = IMC(c.rhodecode_repo) | |
249 m.change(new_node) | |
250 m.commit(message=message, | |
251 author=self.rhodecode_user.full_contact, | |
252 parents=[c.cs], branch=c.cs.branch) | |
253 h.flash(_('Successfully committed to %s' % f_path), | |
254 category='success') | |
255 except Exception, e: | |
256 log.error(traceback.format_exc()) | |
257 h.flash(_('Error occurred during commit'), category='error') | |
258 return redirect(url('changeset_home', | |
259 repo_name=c.repo_name, revision='tip')) | |
260 | |
261 return render('files/files_edit.html') | |
262 | |
263 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', | |
264 'repository.admin') | |
209 def archivefile(self, repo_name, fname): | 265 def archivefile(self, repo_name, fname): |
210 | 266 |
211 fileformat = None | 267 fileformat = None |
212 revision = None | 268 revision = None |
213 ext = None | 269 ext = None |
237 response.content_disposition = 'attachment; filename=%s-%s%s' \ | 293 response.content_disposition = 'attachment; filename=%s-%s%s' \ |
238 % (repo_name, revision, ext) | 294 % (repo_name, revision, ext) |
239 | 295 |
240 return cs.get_chunked_archive(stream=None, kind=fileformat) | 296 return cs.get_chunked_archive(stream=None, kind=fileformat) |
241 | 297 |
298 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', | |
299 'repository.admin') | |
242 def diff(self, repo_name, f_path): | 300 def diff(self, repo_name, f_path): |
243 diff1 = request.GET.get('diff1') | 301 diff1 = request.GET.get('diff1') |
244 diff2 = request.GET.get('diff2') | 302 diff2 = request.GET.get('diff2') |
245 c.action = request.GET.get('diff') | 303 c.action = request.GET.get('diff') |
246 c.no_changes = diff1 == diff2 | 304 c.no_changes = diff1 == diff2 |
280 format='gitdiff') | 338 format='gitdiff') |
281 response.content_type = 'text/plain' | 339 response.content_type = 'text/plain' |
282 return diff.raw_diff() | 340 return diff.raw_diff() |
283 | 341 |
284 elif c.action == 'diff': | 342 elif c.action == 'diff': |
285 | |
286 if node1.is_binary or node2.is_binary: | 343 if node1.is_binary or node2.is_binary: |
287 c.cur_diff = _('Binary file') | 344 c.cur_diff = _('Binary file') |
288 elif node1.size > self.cut_off_limit or \ | 345 elif node1.size > self.cut_off_limit or \ |
289 node2.size > self.cut_off_limit: | 346 node2.size > self.cut_off_limit: |
290 c.cur_diff = '' | 347 c.cur_diff = '' |