##// END OF EJS Templates
unified annotation view with file source view
marcink -
r2177:ee07357d beta
parent child Browse files
Show More
@@ -1,507 +1,507 b''
1 """
1 """
2 Routes configuration
2 Routes configuration
3
3
4 The more specific and detailed routes should be defined first so they
4 The more specific and detailed routes should be defined first so they
5 may take precedent over the more generic routes. For more information
5 may take precedent over the more generic routes. For more information
6 refer to the routes manual at http://routes.groovie.org/docs/
6 refer to the routes manual at http://routes.groovie.org/docs/
7 """
7 """
8 from __future__ import with_statement
8 from __future__ import with_statement
9 from routes import Mapper
9 from routes import Mapper
10
10
11 # prefix for non repository related links needs to be prefixed with `/`
11 # prefix for non repository related links needs to be prefixed with `/`
12 ADMIN_PREFIX = '/_admin'
12 ADMIN_PREFIX = '/_admin'
13
13
14
14
15 def make_map(config):
15 def make_map(config):
16 """Create, configure and return the routes Mapper"""
16 """Create, configure and return the routes Mapper"""
17 rmap = Mapper(directory=config['pylons.paths']['controllers'],
17 rmap = Mapper(directory=config['pylons.paths']['controllers'],
18 always_scan=config['debug'])
18 always_scan=config['debug'])
19 rmap.minimization = False
19 rmap.minimization = False
20 rmap.explicit = False
20 rmap.explicit = False
21
21
22 from rhodecode.lib.utils import is_valid_repo
22 from rhodecode.lib.utils import is_valid_repo
23 from rhodecode.lib.utils import is_valid_repos_group
23 from rhodecode.lib.utils import is_valid_repos_group
24
24
25 def check_repo(environ, match_dict):
25 def check_repo(environ, match_dict):
26 """
26 """
27 check for valid repository for proper 404 handling
27 check for valid repository for proper 404 handling
28
28
29 :param environ:
29 :param environ:
30 :param match_dict:
30 :param match_dict:
31 """
31 """
32 from rhodecode.model.db import Repository
32 from rhodecode.model.db import Repository
33 repo_name = match_dict.get('repo_name')
33 repo_name = match_dict.get('repo_name')
34
34
35 try:
35 try:
36 by_id = repo_name.split('_')
36 by_id = repo_name.split('_')
37 if len(by_id) == 2 and by_id[1].isdigit():
37 if len(by_id) == 2 and by_id[1].isdigit():
38 repo_name = Repository.get(by_id[1]).repo_name
38 repo_name = Repository.get(by_id[1]).repo_name
39 match_dict['repo_name'] = repo_name
39 match_dict['repo_name'] = repo_name
40 except:
40 except:
41 pass
41 pass
42
42
43 return is_valid_repo(repo_name, config['base_path'])
43 return is_valid_repo(repo_name, config['base_path'])
44
44
45 def check_group(environ, match_dict):
45 def check_group(environ, match_dict):
46 """
46 """
47 check for valid repositories group for proper 404 handling
47 check for valid repositories group for proper 404 handling
48
48
49 :param environ:
49 :param environ:
50 :param match_dict:
50 :param match_dict:
51 """
51 """
52 repos_group_name = match_dict.get('group_name')
52 repos_group_name = match_dict.get('group_name')
53
53
54 return is_valid_repos_group(repos_group_name, config['base_path'])
54 return is_valid_repos_group(repos_group_name, config['base_path'])
55
55
56 def check_int(environ, match_dict):
56 def check_int(environ, match_dict):
57 return match_dict.get('id').isdigit()
57 return match_dict.get('id').isdigit()
58
58
59 # The ErrorController route (handles 404/500 error pages); it should
59 # The ErrorController route (handles 404/500 error pages); it should
60 # likely stay at the top, ensuring it can always be resolved
60 # likely stay at the top, ensuring it can always be resolved
61 rmap.connect('/error/{action}', controller='error')
61 rmap.connect('/error/{action}', controller='error')
62 rmap.connect('/error/{action}/{id}', controller='error')
62 rmap.connect('/error/{action}/{id}', controller='error')
63
63
64 #==========================================================================
64 #==========================================================================
65 # CUSTOM ROUTES HERE
65 # CUSTOM ROUTES HERE
66 #==========================================================================
66 #==========================================================================
67
67
68 #MAIN PAGE
68 #MAIN PAGE
69 rmap.connect('home', '/', controller='home', action='index')
69 rmap.connect('home', '/', controller='home', action='index')
70 rmap.connect('repo_switcher', '/repos', controller='home',
70 rmap.connect('repo_switcher', '/repos', controller='home',
71 action='repo_switcher')
71 action='repo_switcher')
72 rmap.connect('branch_tag_switcher', '/branches-tags/{repo_name:.*}',
72 rmap.connect('branch_tag_switcher', '/branches-tags/{repo_name:.*}',
73 controller='home', action='branch_tag_switcher')
73 controller='home', action='branch_tag_switcher')
74 rmap.connect('bugtracker',
74 rmap.connect('bugtracker',
75 "http://bitbucket.org/marcinkuzminski/rhodecode/issues",
75 "http://bitbucket.org/marcinkuzminski/rhodecode/issues",
76 _static=True)
76 _static=True)
77 rmap.connect('rst_help',
77 rmap.connect('rst_help',
78 "http://docutils.sourceforge.net/docs/user/rst/quickref.html",
78 "http://docutils.sourceforge.net/docs/user/rst/quickref.html",
79 _static=True)
79 _static=True)
80 rmap.connect('rhodecode_official', "http://rhodecode.org", _static=True)
80 rmap.connect('rhodecode_official', "http://rhodecode.org", _static=True)
81
81
82 #ADMIN REPOSITORY REST ROUTES
82 #ADMIN REPOSITORY REST ROUTES
83 with rmap.submapper(path_prefix=ADMIN_PREFIX,
83 with rmap.submapper(path_prefix=ADMIN_PREFIX,
84 controller='admin/repos') as m:
84 controller='admin/repos') as m:
85 m.connect("repos", "/repos",
85 m.connect("repos", "/repos",
86 action="create", conditions=dict(method=["POST"]))
86 action="create", conditions=dict(method=["POST"]))
87 m.connect("repos", "/repos",
87 m.connect("repos", "/repos",
88 action="index", conditions=dict(method=["GET"]))
88 action="index", conditions=dict(method=["GET"]))
89 m.connect("formatted_repos", "/repos.{format}",
89 m.connect("formatted_repos", "/repos.{format}",
90 action="index",
90 action="index",
91 conditions=dict(method=["GET"]))
91 conditions=dict(method=["GET"]))
92 m.connect("new_repo", "/repos/new",
92 m.connect("new_repo", "/repos/new",
93 action="new", conditions=dict(method=["GET"]))
93 action="new", conditions=dict(method=["GET"]))
94 m.connect("formatted_new_repo", "/repos/new.{format}",
94 m.connect("formatted_new_repo", "/repos/new.{format}",
95 action="new", conditions=dict(method=["GET"]))
95 action="new", conditions=dict(method=["GET"]))
96 m.connect("/repos/{repo_name:.*}",
96 m.connect("/repos/{repo_name:.*}",
97 action="update", conditions=dict(method=["PUT"],
97 action="update", conditions=dict(method=["PUT"],
98 function=check_repo))
98 function=check_repo))
99 m.connect("/repos/{repo_name:.*}",
99 m.connect("/repos/{repo_name:.*}",
100 action="delete", conditions=dict(method=["DELETE"],
100 action="delete", conditions=dict(method=["DELETE"],
101 function=check_repo))
101 function=check_repo))
102 m.connect("edit_repo", "/repos/{repo_name:.*}/edit",
102 m.connect("edit_repo", "/repos/{repo_name:.*}/edit",
103 action="edit", conditions=dict(method=["GET"],
103 action="edit", conditions=dict(method=["GET"],
104 function=check_repo))
104 function=check_repo))
105 m.connect("formatted_edit_repo", "/repos/{repo_name:.*}.{format}/edit",
105 m.connect("formatted_edit_repo", "/repos/{repo_name:.*}.{format}/edit",
106 action="edit", conditions=dict(method=["GET"],
106 action="edit", conditions=dict(method=["GET"],
107 function=check_repo))
107 function=check_repo))
108 m.connect("repo", "/repos/{repo_name:.*}",
108 m.connect("repo", "/repos/{repo_name:.*}",
109 action="show", conditions=dict(method=["GET"],
109 action="show", conditions=dict(method=["GET"],
110 function=check_repo))
110 function=check_repo))
111 m.connect("formatted_repo", "/repos/{repo_name:.*}.{format}",
111 m.connect("formatted_repo", "/repos/{repo_name:.*}.{format}",
112 action="show", conditions=dict(method=["GET"],
112 action="show", conditions=dict(method=["GET"],
113 function=check_repo))
113 function=check_repo))
114 #ajax delete repo perm user
114 #ajax delete repo perm user
115 m.connect('delete_repo_user', "/repos_delete_user/{repo_name:.*}",
115 m.connect('delete_repo_user', "/repos_delete_user/{repo_name:.*}",
116 action="delete_perm_user",
116 action="delete_perm_user",
117 conditions=dict(method=["DELETE"], function=check_repo))
117 conditions=dict(method=["DELETE"], function=check_repo))
118
118
119 #ajax delete repo perm users_group
119 #ajax delete repo perm users_group
120 m.connect('delete_repo_users_group',
120 m.connect('delete_repo_users_group',
121 "/repos_delete_users_group/{repo_name:.*}",
121 "/repos_delete_users_group/{repo_name:.*}",
122 action="delete_perm_users_group",
122 action="delete_perm_users_group",
123 conditions=dict(method=["DELETE"], function=check_repo))
123 conditions=dict(method=["DELETE"], function=check_repo))
124
124
125 #settings actions
125 #settings actions
126 m.connect('repo_stats', "/repos_stats/{repo_name:.*}",
126 m.connect('repo_stats', "/repos_stats/{repo_name:.*}",
127 action="repo_stats", conditions=dict(method=["DELETE"],
127 action="repo_stats", conditions=dict(method=["DELETE"],
128 function=check_repo))
128 function=check_repo))
129 m.connect('repo_cache', "/repos_cache/{repo_name:.*}",
129 m.connect('repo_cache', "/repos_cache/{repo_name:.*}",
130 action="repo_cache", conditions=dict(method=["DELETE"],
130 action="repo_cache", conditions=dict(method=["DELETE"],
131 function=check_repo))
131 function=check_repo))
132 m.connect('repo_public_journal', "/repos_public_journal/{repo_name:.*}",
132 m.connect('repo_public_journal', "/repos_public_journal/{repo_name:.*}",
133 action="repo_public_journal", conditions=dict(method=["PUT"],
133 action="repo_public_journal", conditions=dict(method=["PUT"],
134 function=check_repo))
134 function=check_repo))
135 m.connect('repo_pull', "/repo_pull/{repo_name:.*}",
135 m.connect('repo_pull', "/repo_pull/{repo_name:.*}",
136 action="repo_pull", conditions=dict(method=["PUT"],
136 action="repo_pull", conditions=dict(method=["PUT"],
137 function=check_repo))
137 function=check_repo))
138 m.connect('repo_as_fork', "/repo_as_fork/{repo_name:.*}",
138 m.connect('repo_as_fork', "/repo_as_fork/{repo_name:.*}",
139 action="repo_as_fork", conditions=dict(method=["PUT"],
139 action="repo_as_fork", conditions=dict(method=["PUT"],
140 function=check_repo))
140 function=check_repo))
141
141
142 with rmap.submapper(path_prefix=ADMIN_PREFIX,
142 with rmap.submapper(path_prefix=ADMIN_PREFIX,
143 controller='admin/repos_groups') as m:
143 controller='admin/repos_groups') as m:
144 m.connect("repos_groups", "/repos_groups",
144 m.connect("repos_groups", "/repos_groups",
145 action="create", conditions=dict(method=["POST"]))
145 action="create", conditions=dict(method=["POST"]))
146 m.connect("repos_groups", "/repos_groups",
146 m.connect("repos_groups", "/repos_groups",
147 action="index", conditions=dict(method=["GET"]))
147 action="index", conditions=dict(method=["GET"]))
148 m.connect("formatted_repos_groups", "/repos_groups.{format}",
148 m.connect("formatted_repos_groups", "/repos_groups.{format}",
149 action="index", conditions=dict(method=["GET"]))
149 action="index", conditions=dict(method=["GET"]))
150 m.connect("new_repos_group", "/repos_groups/new",
150 m.connect("new_repos_group", "/repos_groups/new",
151 action="new", conditions=dict(method=["GET"]))
151 action="new", conditions=dict(method=["GET"]))
152 m.connect("formatted_new_repos_group", "/repos_groups/new.{format}",
152 m.connect("formatted_new_repos_group", "/repos_groups/new.{format}",
153 action="new", conditions=dict(method=["GET"]))
153 action="new", conditions=dict(method=["GET"]))
154 m.connect("update_repos_group", "/repos_groups/{id}",
154 m.connect("update_repos_group", "/repos_groups/{id}",
155 action="update", conditions=dict(method=["PUT"],
155 action="update", conditions=dict(method=["PUT"],
156 function=check_int))
156 function=check_int))
157 m.connect("delete_repos_group", "/repos_groups/{id}",
157 m.connect("delete_repos_group", "/repos_groups/{id}",
158 action="delete", conditions=dict(method=["DELETE"],
158 action="delete", conditions=dict(method=["DELETE"],
159 function=check_int))
159 function=check_int))
160 m.connect("edit_repos_group", "/repos_groups/{id}/edit",
160 m.connect("edit_repos_group", "/repos_groups/{id}/edit",
161 action="edit", conditions=dict(method=["GET"],
161 action="edit", conditions=dict(method=["GET"],
162 function=check_int))
162 function=check_int))
163 m.connect("formatted_edit_repos_group",
163 m.connect("formatted_edit_repos_group",
164 "/repos_groups/{id}.{format}/edit",
164 "/repos_groups/{id}.{format}/edit",
165 action="edit", conditions=dict(method=["GET"],
165 action="edit", conditions=dict(method=["GET"],
166 function=check_int))
166 function=check_int))
167 m.connect("repos_group", "/repos_groups/{id}",
167 m.connect("repos_group", "/repos_groups/{id}",
168 action="show", conditions=dict(method=["GET"],
168 action="show", conditions=dict(method=["GET"],
169 function=check_int))
169 function=check_int))
170 m.connect("formatted_repos_group", "/repos_groups/{id}.{format}",
170 m.connect("formatted_repos_group", "/repos_groups/{id}.{format}",
171 action="show", conditions=dict(method=["GET"],
171 action="show", conditions=dict(method=["GET"],
172 function=check_int))
172 function=check_int))
173 # ajax delete repos group perm user
173 # ajax delete repos group perm user
174 m.connect('delete_repos_group_user_perm',
174 m.connect('delete_repos_group_user_perm',
175 "/delete_repos_group_user_perm/{group_name:.*}",
175 "/delete_repos_group_user_perm/{group_name:.*}",
176 action="delete_repos_group_user_perm",
176 action="delete_repos_group_user_perm",
177 conditions=dict(method=["DELETE"], function=check_group))
177 conditions=dict(method=["DELETE"], function=check_group))
178
178
179 # ajax delete repos group perm users_group
179 # ajax delete repos group perm users_group
180 m.connect('delete_repos_group_users_group_perm',
180 m.connect('delete_repos_group_users_group_perm',
181 "/delete_repos_group_users_group_perm/{group_name:.*}",
181 "/delete_repos_group_users_group_perm/{group_name:.*}",
182 action="delete_repos_group_users_group_perm",
182 action="delete_repos_group_users_group_perm",
183 conditions=dict(method=["DELETE"], function=check_group))
183 conditions=dict(method=["DELETE"], function=check_group))
184
184
185 #ADMIN USER REST ROUTES
185 #ADMIN USER REST ROUTES
186 with rmap.submapper(path_prefix=ADMIN_PREFIX,
186 with rmap.submapper(path_prefix=ADMIN_PREFIX,
187 controller='admin/users') as m:
187 controller='admin/users') as m:
188 m.connect("users", "/users",
188 m.connect("users", "/users",
189 action="create", conditions=dict(method=["POST"]))
189 action="create", conditions=dict(method=["POST"]))
190 m.connect("users", "/users",
190 m.connect("users", "/users",
191 action="index", conditions=dict(method=["GET"]))
191 action="index", conditions=dict(method=["GET"]))
192 m.connect("formatted_users", "/users.{format}",
192 m.connect("formatted_users", "/users.{format}",
193 action="index", conditions=dict(method=["GET"]))
193 action="index", conditions=dict(method=["GET"]))
194 m.connect("new_user", "/users/new",
194 m.connect("new_user", "/users/new",
195 action="new", conditions=dict(method=["GET"]))
195 action="new", conditions=dict(method=["GET"]))
196 m.connect("formatted_new_user", "/users/new.{format}",
196 m.connect("formatted_new_user", "/users/new.{format}",
197 action="new", conditions=dict(method=["GET"]))
197 action="new", conditions=dict(method=["GET"]))
198 m.connect("update_user", "/users/{id}",
198 m.connect("update_user", "/users/{id}",
199 action="update", conditions=dict(method=["PUT"]))
199 action="update", conditions=dict(method=["PUT"]))
200 m.connect("delete_user", "/users/{id}",
200 m.connect("delete_user", "/users/{id}",
201 action="delete", conditions=dict(method=["DELETE"]))
201 action="delete", conditions=dict(method=["DELETE"]))
202 m.connect("edit_user", "/users/{id}/edit",
202 m.connect("edit_user", "/users/{id}/edit",
203 action="edit", conditions=dict(method=["GET"]))
203 action="edit", conditions=dict(method=["GET"]))
204 m.connect("formatted_edit_user",
204 m.connect("formatted_edit_user",
205 "/users/{id}.{format}/edit",
205 "/users/{id}.{format}/edit",
206 action="edit", conditions=dict(method=["GET"]))
206 action="edit", conditions=dict(method=["GET"]))
207 m.connect("user", "/users/{id}",
207 m.connect("user", "/users/{id}",
208 action="show", conditions=dict(method=["GET"]))
208 action="show", conditions=dict(method=["GET"]))
209 m.connect("formatted_user", "/users/{id}.{format}",
209 m.connect("formatted_user", "/users/{id}.{format}",
210 action="show", conditions=dict(method=["GET"]))
210 action="show", conditions=dict(method=["GET"]))
211
211
212 #EXTRAS USER ROUTES
212 #EXTRAS USER ROUTES
213 m.connect("user_perm", "/users_perm/{id}",
213 m.connect("user_perm", "/users_perm/{id}",
214 action="update_perm", conditions=dict(method=["PUT"]))
214 action="update_perm", conditions=dict(method=["PUT"]))
215
215
216 #ADMIN USERS REST ROUTES
216 #ADMIN USERS REST ROUTES
217 with rmap.submapper(path_prefix=ADMIN_PREFIX,
217 with rmap.submapper(path_prefix=ADMIN_PREFIX,
218 controller='admin/users_groups') as m:
218 controller='admin/users_groups') as m:
219 m.connect("users_groups", "/users_groups",
219 m.connect("users_groups", "/users_groups",
220 action="create", conditions=dict(method=["POST"]))
220 action="create", conditions=dict(method=["POST"]))
221 m.connect("users_groups", "/users_groups",
221 m.connect("users_groups", "/users_groups",
222 action="index", conditions=dict(method=["GET"]))
222 action="index", conditions=dict(method=["GET"]))
223 m.connect("formatted_users_groups", "/users_groups.{format}",
223 m.connect("formatted_users_groups", "/users_groups.{format}",
224 action="index", conditions=dict(method=["GET"]))
224 action="index", conditions=dict(method=["GET"]))
225 m.connect("new_users_group", "/users_groups/new",
225 m.connect("new_users_group", "/users_groups/new",
226 action="new", conditions=dict(method=["GET"]))
226 action="new", conditions=dict(method=["GET"]))
227 m.connect("formatted_new_users_group", "/users_groups/new.{format}",
227 m.connect("formatted_new_users_group", "/users_groups/new.{format}",
228 action="new", conditions=dict(method=["GET"]))
228 action="new", conditions=dict(method=["GET"]))
229 m.connect("update_users_group", "/users_groups/{id}",
229 m.connect("update_users_group", "/users_groups/{id}",
230 action="update", conditions=dict(method=["PUT"]))
230 action="update", conditions=dict(method=["PUT"]))
231 m.connect("delete_users_group", "/users_groups/{id}",
231 m.connect("delete_users_group", "/users_groups/{id}",
232 action="delete", conditions=dict(method=["DELETE"]))
232 action="delete", conditions=dict(method=["DELETE"]))
233 m.connect("edit_users_group", "/users_groups/{id}/edit",
233 m.connect("edit_users_group", "/users_groups/{id}/edit",
234 action="edit", conditions=dict(method=["GET"]))
234 action="edit", conditions=dict(method=["GET"]))
235 m.connect("formatted_edit_users_group",
235 m.connect("formatted_edit_users_group",
236 "/users_groups/{id}.{format}/edit",
236 "/users_groups/{id}.{format}/edit",
237 action="edit", conditions=dict(method=["GET"]))
237 action="edit", conditions=dict(method=["GET"]))
238 m.connect("users_group", "/users_groups/{id}",
238 m.connect("users_group", "/users_groups/{id}",
239 action="show", conditions=dict(method=["GET"]))
239 action="show", conditions=dict(method=["GET"]))
240 m.connect("formatted_users_group", "/users_groups/{id}.{format}",
240 m.connect("formatted_users_group", "/users_groups/{id}.{format}",
241 action="show", conditions=dict(method=["GET"]))
241 action="show", conditions=dict(method=["GET"]))
242
242
243 #EXTRAS USER ROUTES
243 #EXTRAS USER ROUTES
244 m.connect("users_group_perm", "/users_groups_perm/{id}",
244 m.connect("users_group_perm", "/users_groups_perm/{id}",
245 action="update_perm", conditions=dict(method=["PUT"]))
245 action="update_perm", conditions=dict(method=["PUT"]))
246
246
247 #ADMIN GROUP REST ROUTES
247 #ADMIN GROUP REST ROUTES
248 rmap.resource('group', 'groups',
248 rmap.resource('group', 'groups',
249 controller='admin/groups', path_prefix=ADMIN_PREFIX)
249 controller='admin/groups', path_prefix=ADMIN_PREFIX)
250
250
251 #ADMIN PERMISSIONS REST ROUTES
251 #ADMIN PERMISSIONS REST ROUTES
252 rmap.resource('permission', 'permissions',
252 rmap.resource('permission', 'permissions',
253 controller='admin/permissions', path_prefix=ADMIN_PREFIX)
253 controller='admin/permissions', path_prefix=ADMIN_PREFIX)
254
254
255 ##ADMIN LDAP SETTINGS
255 ##ADMIN LDAP SETTINGS
256 rmap.connect('ldap_settings', '%s/ldap' % ADMIN_PREFIX,
256 rmap.connect('ldap_settings', '%s/ldap' % ADMIN_PREFIX,
257 controller='admin/ldap_settings', action='ldap_settings',
257 controller='admin/ldap_settings', action='ldap_settings',
258 conditions=dict(method=["POST"]))
258 conditions=dict(method=["POST"]))
259
259
260 rmap.connect('ldap_home', '%s/ldap' % ADMIN_PREFIX,
260 rmap.connect('ldap_home', '%s/ldap' % ADMIN_PREFIX,
261 controller='admin/ldap_settings')
261 controller='admin/ldap_settings')
262
262
263 #ADMIN SETTINGS REST ROUTES
263 #ADMIN SETTINGS REST ROUTES
264 with rmap.submapper(path_prefix=ADMIN_PREFIX,
264 with rmap.submapper(path_prefix=ADMIN_PREFIX,
265 controller='admin/settings') as m:
265 controller='admin/settings') as m:
266 m.connect("admin_settings", "/settings",
266 m.connect("admin_settings", "/settings",
267 action="create", conditions=dict(method=["POST"]))
267 action="create", conditions=dict(method=["POST"]))
268 m.connect("admin_settings", "/settings",
268 m.connect("admin_settings", "/settings",
269 action="index", conditions=dict(method=["GET"]))
269 action="index", conditions=dict(method=["GET"]))
270 m.connect("formatted_admin_settings", "/settings.{format}",
270 m.connect("formatted_admin_settings", "/settings.{format}",
271 action="index", conditions=dict(method=["GET"]))
271 action="index", conditions=dict(method=["GET"]))
272 m.connect("admin_new_setting", "/settings/new",
272 m.connect("admin_new_setting", "/settings/new",
273 action="new", conditions=dict(method=["GET"]))
273 action="new", conditions=dict(method=["GET"]))
274 m.connect("formatted_admin_new_setting", "/settings/new.{format}",
274 m.connect("formatted_admin_new_setting", "/settings/new.{format}",
275 action="new", conditions=dict(method=["GET"]))
275 action="new", conditions=dict(method=["GET"]))
276 m.connect("/settings/{setting_id}",
276 m.connect("/settings/{setting_id}",
277 action="update", conditions=dict(method=["PUT"]))
277 action="update", conditions=dict(method=["PUT"]))
278 m.connect("/settings/{setting_id}",
278 m.connect("/settings/{setting_id}",
279 action="delete", conditions=dict(method=["DELETE"]))
279 action="delete", conditions=dict(method=["DELETE"]))
280 m.connect("admin_edit_setting", "/settings/{setting_id}/edit",
280 m.connect("admin_edit_setting", "/settings/{setting_id}/edit",
281 action="edit", conditions=dict(method=["GET"]))
281 action="edit", conditions=dict(method=["GET"]))
282 m.connect("formatted_admin_edit_setting",
282 m.connect("formatted_admin_edit_setting",
283 "/settings/{setting_id}.{format}/edit",
283 "/settings/{setting_id}.{format}/edit",
284 action="edit", conditions=dict(method=["GET"]))
284 action="edit", conditions=dict(method=["GET"]))
285 m.connect("admin_setting", "/settings/{setting_id}",
285 m.connect("admin_setting", "/settings/{setting_id}",
286 action="show", conditions=dict(method=["GET"]))
286 action="show", conditions=dict(method=["GET"]))
287 m.connect("formatted_admin_setting", "/settings/{setting_id}.{format}",
287 m.connect("formatted_admin_setting", "/settings/{setting_id}.{format}",
288 action="show", conditions=dict(method=["GET"]))
288 action="show", conditions=dict(method=["GET"]))
289 m.connect("admin_settings_my_account", "/my_account",
289 m.connect("admin_settings_my_account", "/my_account",
290 action="my_account", conditions=dict(method=["GET"]))
290 action="my_account", conditions=dict(method=["GET"]))
291 m.connect("admin_settings_my_account_update", "/my_account_update",
291 m.connect("admin_settings_my_account_update", "/my_account_update",
292 action="my_account_update", conditions=dict(method=["PUT"]))
292 action="my_account_update", conditions=dict(method=["PUT"]))
293 m.connect("admin_settings_create_repository", "/create_repository",
293 m.connect("admin_settings_create_repository", "/create_repository",
294 action="create_repository", conditions=dict(method=["GET"]))
294 action="create_repository", conditions=dict(method=["GET"]))
295
295
296 #NOTIFICATION REST ROUTES
296 #NOTIFICATION REST ROUTES
297 with rmap.submapper(path_prefix=ADMIN_PREFIX,
297 with rmap.submapper(path_prefix=ADMIN_PREFIX,
298 controller='admin/notifications') as m:
298 controller='admin/notifications') as m:
299 m.connect("notifications", "/notifications",
299 m.connect("notifications", "/notifications",
300 action="create", conditions=dict(method=["POST"]))
300 action="create", conditions=dict(method=["POST"]))
301 m.connect("notifications", "/notifications",
301 m.connect("notifications", "/notifications",
302 action="index", conditions=dict(method=["GET"]))
302 action="index", conditions=dict(method=["GET"]))
303 m.connect("notifications_mark_all_read", "/notifications/mark_all_read",
303 m.connect("notifications_mark_all_read", "/notifications/mark_all_read",
304 action="mark_all_read", conditions=dict(method=["GET"]))
304 action="mark_all_read", conditions=dict(method=["GET"]))
305 m.connect("formatted_notifications", "/notifications.{format}",
305 m.connect("formatted_notifications", "/notifications.{format}",
306 action="index", conditions=dict(method=["GET"]))
306 action="index", conditions=dict(method=["GET"]))
307 m.connect("new_notification", "/notifications/new",
307 m.connect("new_notification", "/notifications/new",
308 action="new", conditions=dict(method=["GET"]))
308 action="new", conditions=dict(method=["GET"]))
309 m.connect("formatted_new_notification", "/notifications/new.{format}",
309 m.connect("formatted_new_notification", "/notifications/new.{format}",
310 action="new", conditions=dict(method=["GET"]))
310 action="new", conditions=dict(method=["GET"]))
311 m.connect("/notification/{notification_id}",
311 m.connect("/notification/{notification_id}",
312 action="update", conditions=dict(method=["PUT"]))
312 action="update", conditions=dict(method=["PUT"]))
313 m.connect("/notification/{notification_id}",
313 m.connect("/notification/{notification_id}",
314 action="delete", conditions=dict(method=["DELETE"]))
314 action="delete", conditions=dict(method=["DELETE"]))
315 m.connect("edit_notification", "/notification/{notification_id}/edit",
315 m.connect("edit_notification", "/notification/{notification_id}/edit",
316 action="edit", conditions=dict(method=["GET"]))
316 action="edit", conditions=dict(method=["GET"]))
317 m.connect("formatted_edit_notification",
317 m.connect("formatted_edit_notification",
318 "/notification/{notification_id}.{format}/edit",
318 "/notification/{notification_id}.{format}/edit",
319 action="edit", conditions=dict(method=["GET"]))
319 action="edit", conditions=dict(method=["GET"]))
320 m.connect("notification", "/notification/{notification_id}",
320 m.connect("notification", "/notification/{notification_id}",
321 action="show", conditions=dict(method=["GET"]))
321 action="show", conditions=dict(method=["GET"]))
322 m.connect("formatted_notification", "/notifications/{notification_id}.{format}",
322 m.connect("formatted_notification", "/notifications/{notification_id}.{format}",
323 action="show", conditions=dict(method=["GET"]))
323 action="show", conditions=dict(method=["GET"]))
324
324
325 #ADMIN MAIN PAGES
325 #ADMIN MAIN PAGES
326 with rmap.submapper(path_prefix=ADMIN_PREFIX,
326 with rmap.submapper(path_prefix=ADMIN_PREFIX,
327 controller='admin/admin') as m:
327 controller='admin/admin') as m:
328 m.connect('admin_home', '', action='index')
328 m.connect('admin_home', '', action='index')
329 m.connect('admin_add_repo', '/add_repo/{new_repo:[a-z0-9\. _-]*}',
329 m.connect('admin_add_repo', '/add_repo/{new_repo:[a-z0-9\. _-]*}',
330 action='add_repo')
330 action='add_repo')
331
331
332 #==========================================================================
332 #==========================================================================
333 # API V2
333 # API V2
334 #==========================================================================
334 #==========================================================================
335 with rmap.submapper(path_prefix=ADMIN_PREFIX,
335 with rmap.submapper(path_prefix=ADMIN_PREFIX,
336 controller='api/api') as m:
336 controller='api/api') as m:
337 m.connect('api', '/api')
337 m.connect('api', '/api')
338
338
339 #USER JOURNAL
339 #USER JOURNAL
340 rmap.connect('journal', '%s/journal' % ADMIN_PREFIX, controller='journal')
340 rmap.connect('journal', '%s/journal' % ADMIN_PREFIX, controller='journal')
341
341
342 rmap.connect('public_journal', '%s/public_journal' % ADMIN_PREFIX,
342 rmap.connect('public_journal', '%s/public_journal' % ADMIN_PREFIX,
343 controller='journal', action="public_journal")
343 controller='journal', action="public_journal")
344
344
345 rmap.connect('public_journal_rss', '%s/public_journal_rss' % ADMIN_PREFIX,
345 rmap.connect('public_journal_rss', '%s/public_journal_rss' % ADMIN_PREFIX,
346 controller='journal', action="public_journal_rss")
346 controller='journal', action="public_journal_rss")
347
347
348 rmap.connect('public_journal_atom',
348 rmap.connect('public_journal_atom',
349 '%s/public_journal_atom' % ADMIN_PREFIX, controller='journal',
349 '%s/public_journal_atom' % ADMIN_PREFIX, controller='journal',
350 action="public_journal_atom")
350 action="public_journal_atom")
351
351
352 rmap.connect('toggle_following', '%s/toggle_following' % ADMIN_PREFIX,
352 rmap.connect('toggle_following', '%s/toggle_following' % ADMIN_PREFIX,
353 controller='journal', action='toggle_following',
353 controller='journal', action='toggle_following',
354 conditions=dict(method=["POST"]))
354 conditions=dict(method=["POST"]))
355
355
356 #SEARCH
356 #SEARCH
357 rmap.connect('search', '%s/search' % ADMIN_PREFIX, controller='search',)
357 rmap.connect('search', '%s/search' % ADMIN_PREFIX, controller='search',)
358 rmap.connect('search_repo', '%s/search/{search_repo:.*}' % ADMIN_PREFIX,
358 rmap.connect('search_repo', '%s/search/{search_repo:.*}' % ADMIN_PREFIX,
359 controller='search')
359 controller='search')
360
360
361 #LOGIN/LOGOUT/REGISTER/SIGN IN
361 #LOGIN/LOGOUT/REGISTER/SIGN IN
362 rmap.connect('login_home', '%s/login' % ADMIN_PREFIX, controller='login')
362 rmap.connect('login_home', '%s/login' % ADMIN_PREFIX, controller='login')
363 rmap.connect('logout_home', '%s/logout' % ADMIN_PREFIX, controller='login',
363 rmap.connect('logout_home', '%s/logout' % ADMIN_PREFIX, controller='login',
364 action='logout')
364 action='logout')
365
365
366 rmap.connect('register', '%s/register' % ADMIN_PREFIX, controller='login',
366 rmap.connect('register', '%s/register' % ADMIN_PREFIX, controller='login',
367 action='register')
367 action='register')
368
368
369 rmap.connect('reset_password', '%s/password_reset' % ADMIN_PREFIX,
369 rmap.connect('reset_password', '%s/password_reset' % ADMIN_PREFIX,
370 controller='login', action='password_reset')
370 controller='login', action='password_reset')
371
371
372 rmap.connect('reset_password_confirmation',
372 rmap.connect('reset_password_confirmation',
373 '%s/password_reset_confirmation' % ADMIN_PREFIX,
373 '%s/password_reset_confirmation' % ADMIN_PREFIX,
374 controller='login', action='password_reset_confirmation')
374 controller='login', action='password_reset_confirmation')
375
375
376 #FEEDS
376 #FEEDS
377 rmap.connect('rss_feed_home', '/{repo_name:.*}/feed/rss',
377 rmap.connect('rss_feed_home', '/{repo_name:.*}/feed/rss',
378 controller='feed', action='rss',
378 controller='feed', action='rss',
379 conditions=dict(function=check_repo))
379 conditions=dict(function=check_repo))
380
380
381 rmap.connect('atom_feed_home', '/{repo_name:.*}/feed/atom',
381 rmap.connect('atom_feed_home', '/{repo_name:.*}/feed/atom',
382 controller='feed', action='atom',
382 controller='feed', action='atom',
383 conditions=dict(function=check_repo))
383 conditions=dict(function=check_repo))
384
384
385 #==========================================================================
385 #==========================================================================
386 # REPOSITORY ROUTES
386 # REPOSITORY ROUTES
387 #==========================================================================
387 #==========================================================================
388 rmap.connect('summary_home', '/{repo_name:.*}',
388 rmap.connect('summary_home', '/{repo_name:.*}',
389 controller='summary',
389 controller='summary',
390 conditions=dict(function=check_repo))
390 conditions=dict(function=check_repo))
391
391
392 rmap.connect('repos_group_home', '/{group_name:.*}',
392 rmap.connect('repos_group_home', '/{group_name:.*}',
393 controller='admin/repos_groups', action="show_by_name",
393 controller='admin/repos_groups', action="show_by_name",
394 conditions=dict(function=check_group))
394 conditions=dict(function=check_group))
395
395
396 rmap.connect('changeset_home', '/{repo_name:.*}/changeset/{revision}',
396 rmap.connect('changeset_home', '/{repo_name:.*}/changeset/{revision}',
397 controller='changeset', revision='tip',
397 controller='changeset', revision='tip',
398 conditions=dict(function=check_repo))
398 conditions=dict(function=check_repo))
399
399
400 rmap.connect('changeset_comment',
400 rmap.connect('changeset_comment',
401 '/{repo_name:.*}/changeset/{revision}/comment',
401 '/{repo_name:.*}/changeset/{revision}/comment',
402 controller='changeset', revision='tip', action='comment',
402 controller='changeset', revision='tip', action='comment',
403 conditions=dict(function=check_repo))
403 conditions=dict(function=check_repo))
404
404
405 rmap.connect('changeset_comment_delete',
405 rmap.connect('changeset_comment_delete',
406 '/{repo_name:.*}/changeset/comment/{comment_id}/delete',
406 '/{repo_name:.*}/changeset/comment/{comment_id}/delete',
407 controller='changeset', action='delete_comment',
407 controller='changeset', action='delete_comment',
408 conditions=dict(function=check_repo, method=["DELETE"]))
408 conditions=dict(function=check_repo, method=["DELETE"]))
409
409
410 rmap.connect('raw_changeset_home',
410 rmap.connect('raw_changeset_home',
411 '/{repo_name:.*}/raw-changeset/{revision}',
411 '/{repo_name:.*}/raw-changeset/{revision}',
412 controller='changeset', action='raw_changeset',
412 controller='changeset', action='raw_changeset',
413 revision='tip', conditions=dict(function=check_repo))
413 revision='tip', conditions=dict(function=check_repo))
414
414
415 rmap.connect('summary_home', '/{repo_name:.*}/summary',
415 rmap.connect('summary_home', '/{repo_name:.*}/summary',
416 controller='summary', conditions=dict(function=check_repo))
416 controller='summary', conditions=dict(function=check_repo))
417
417
418 rmap.connect('shortlog_home', '/{repo_name:.*}/shortlog',
418 rmap.connect('shortlog_home', '/{repo_name:.*}/shortlog',
419 controller='shortlog', conditions=dict(function=check_repo))
419 controller='shortlog', conditions=dict(function=check_repo))
420
420
421 rmap.connect('branches_home', '/{repo_name:.*}/branches',
421 rmap.connect('branches_home', '/{repo_name:.*}/branches',
422 controller='branches', conditions=dict(function=check_repo))
422 controller='branches', conditions=dict(function=check_repo))
423
423
424 rmap.connect('tags_home', '/{repo_name:.*}/tags',
424 rmap.connect('tags_home', '/{repo_name:.*}/tags',
425 controller='tags', conditions=dict(function=check_repo))
425 controller='tags', conditions=dict(function=check_repo))
426
426
427 rmap.connect('bookmarks_home', '/{repo_name:.*}/bookmarks',
427 rmap.connect('bookmarks_home', '/{repo_name:.*}/bookmarks',
428 controller='bookmarks', conditions=dict(function=check_repo))
428 controller='bookmarks', conditions=dict(function=check_repo))
429
429
430 rmap.connect('changelog_home', '/{repo_name:.*}/changelog',
430 rmap.connect('changelog_home', '/{repo_name:.*}/changelog',
431 controller='changelog', conditions=dict(function=check_repo))
431 controller='changelog', conditions=dict(function=check_repo))
432
432
433 rmap.connect('changelog_details', '/{repo_name:.*}/changelog_details/{cs}',
433 rmap.connect('changelog_details', '/{repo_name:.*}/changelog_details/{cs}',
434 controller='changelog', action='changelog_details',
434 controller='changelog', action='changelog_details',
435 conditions=dict(function=check_repo))
435 conditions=dict(function=check_repo))
436
436
437 rmap.connect('files_home', '/{repo_name:.*}/files/{revision}/{f_path:.*}',
437 rmap.connect('files_home', '/{repo_name:.*}/files/{revision}/{f_path:.*}',
438 controller='files', revision='tip', f_path='',
438 controller='files', revision='tip', f_path='',
439 conditions=dict(function=check_repo))
439 conditions=dict(function=check_repo))
440
440
441 rmap.connect('files_diff_home', '/{repo_name:.*}/diff/{f_path:.*}',
441 rmap.connect('files_diff_home', '/{repo_name:.*}/diff/{f_path:.*}',
442 controller='files', action='diff', revision='tip', f_path='',
442 controller='files', action='diff', revision='tip', f_path='',
443 conditions=dict(function=check_repo))
443 conditions=dict(function=check_repo))
444
444
445 rmap.connect('files_rawfile_home',
445 rmap.connect('files_rawfile_home',
446 '/{repo_name:.*}/rawfile/{revision}/{f_path:.*}',
446 '/{repo_name:.*}/rawfile/{revision}/{f_path:.*}',
447 controller='files', action='rawfile', revision='tip',
447 controller='files', action='rawfile', revision='tip',
448 f_path='', conditions=dict(function=check_repo))
448 f_path='', conditions=dict(function=check_repo))
449
449
450 rmap.connect('files_raw_home',
450 rmap.connect('files_raw_home',
451 '/{repo_name:.*}/raw/{revision}/{f_path:.*}',
451 '/{repo_name:.*}/raw/{revision}/{f_path:.*}',
452 controller='files', action='raw', revision='tip', f_path='',
452 controller='files', action='raw', revision='tip', f_path='',
453 conditions=dict(function=check_repo))
453 conditions=dict(function=check_repo))
454
454
455 rmap.connect('files_annotate_home',
455 rmap.connect('files_annotate_home',
456 '/{repo_name:.*}/annotate/{revision}/{f_path:.*}',
456 '/{repo_name:.*}/annotate/{revision}/{f_path:.*}',
457 controller='files', action='annotate', revision='tip',
457 controller='files', action='index', revision='tip',
458 f_path='', conditions=dict(function=check_repo))
458 f_path='', annotate=True, conditions=dict(function=check_repo))
459
459
460 rmap.connect('files_edit_home',
460 rmap.connect('files_edit_home',
461 '/{repo_name:.*}/edit/{revision}/{f_path:.*}',
461 '/{repo_name:.*}/edit/{revision}/{f_path:.*}',
462 controller='files', action='edit', revision='tip',
462 controller='files', action='edit', revision='tip',
463 f_path='', conditions=dict(function=check_repo))
463 f_path='', conditions=dict(function=check_repo))
464
464
465 rmap.connect('files_add_home',
465 rmap.connect('files_add_home',
466 '/{repo_name:.*}/add/{revision}/{f_path:.*}',
466 '/{repo_name:.*}/add/{revision}/{f_path:.*}',
467 controller='files', action='add', revision='tip',
467 controller='files', action='add', revision='tip',
468 f_path='', conditions=dict(function=check_repo))
468 f_path='', conditions=dict(function=check_repo))
469
469
470 rmap.connect('files_archive_home', '/{repo_name:.*}/archive/{fname}',
470 rmap.connect('files_archive_home', '/{repo_name:.*}/archive/{fname}',
471 controller='files', action='archivefile',
471 controller='files', action='archivefile',
472 conditions=dict(function=check_repo))
472 conditions=dict(function=check_repo))
473
473
474 rmap.connect('files_nodelist_home',
474 rmap.connect('files_nodelist_home',
475 '/{repo_name:.*}/nodelist/{revision}/{f_path:.*}',
475 '/{repo_name:.*}/nodelist/{revision}/{f_path:.*}',
476 controller='files', action='nodelist',
476 controller='files', action='nodelist',
477 conditions=dict(function=check_repo))
477 conditions=dict(function=check_repo))
478
478
479 rmap.connect('repo_settings_delete', '/{repo_name:.*}/settings',
479 rmap.connect('repo_settings_delete', '/{repo_name:.*}/settings',
480 controller='settings', action="delete",
480 controller='settings', action="delete",
481 conditions=dict(method=["DELETE"], function=check_repo))
481 conditions=dict(method=["DELETE"], function=check_repo))
482
482
483 rmap.connect('repo_settings_update', '/{repo_name:.*}/settings',
483 rmap.connect('repo_settings_update', '/{repo_name:.*}/settings',
484 controller='settings', action="update",
484 controller='settings', action="update",
485 conditions=dict(method=["PUT"], function=check_repo))
485 conditions=dict(method=["PUT"], function=check_repo))
486
486
487 rmap.connect('repo_settings_home', '/{repo_name:.*}/settings',
487 rmap.connect('repo_settings_home', '/{repo_name:.*}/settings',
488 controller='settings', action='index',
488 controller='settings', action='index',
489 conditions=dict(function=check_repo))
489 conditions=dict(function=check_repo))
490
490
491 rmap.connect('repo_fork_create_home', '/{repo_name:.*}/fork',
491 rmap.connect('repo_fork_create_home', '/{repo_name:.*}/fork',
492 controller='forks', action='fork_create',
492 controller='forks', action='fork_create',
493 conditions=dict(function=check_repo, method=["POST"]))
493 conditions=dict(function=check_repo, method=["POST"]))
494
494
495 rmap.connect('repo_fork_home', '/{repo_name:.*}/fork',
495 rmap.connect('repo_fork_home', '/{repo_name:.*}/fork',
496 controller='forks', action='fork',
496 controller='forks', action='fork',
497 conditions=dict(function=check_repo))
497 conditions=dict(function=check_repo))
498
498
499 rmap.connect('repo_forks_home', '/{repo_name:.*}/forks',
499 rmap.connect('repo_forks_home', '/{repo_name:.*}/forks',
500 controller='forks', action='forks',
500 controller='forks', action='forks',
501 conditions=dict(function=check_repo))
501 conditions=dict(function=check_repo))
502
502
503 rmap.connect('repo_followers_home', '/{repo_name:.*}/followers',
503 rmap.connect('repo_followers_home', '/{repo_name:.*}/followers',
504 controller='followers', action='followers',
504 controller='followers', action='followers',
505 conditions=dict(function=check_repo))
505 conditions=dict(function=check_repo))
506
506
507 return rmap
507 return rmap
@@ -1,496 +1,486 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) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
10 :copyright: (C) 2010-2012 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 modify
13 # This program is free software: you can redistribute it and/or modify
14 # it under the terms of the GNU General Public License as published by
14 # it under the terms of the GNU General Public License as published by
15 # the Free Software Foundation, either version 3 of the License, or
15 # the Free Software Foundation, either version 3 of the License, or
16 # (at your option) any later version.
16 # (at your option) any later version.
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, 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 traceback
28 import traceback
29
29
30 from pylons import request, response, tmpl_context as c, url
30 from pylons import request, response, 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 from pylons.decorators import jsonify
33 from pylons.decorators import jsonify
34
34
35 from rhodecode.lib import diffs
35 from rhodecode.lib import diffs
36 from rhodecode.lib import helpers as h
36 from rhodecode.lib import helpers as h
37
37
38 from rhodecode.lib.compat import OrderedDict
38 from rhodecode.lib.compat import OrderedDict
39 from rhodecode.lib.utils2 import convert_line_endings, detect_mode, safe_str
39 from rhodecode.lib.utils2 import convert_line_endings, detect_mode, safe_str
40 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
40 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
41 from rhodecode.lib.base import BaseRepoController, render
41 from rhodecode.lib.base import BaseRepoController, render
42 from rhodecode.lib.utils import EmptyChangeset
42 from rhodecode.lib.utils import EmptyChangeset
43 from rhodecode.lib.vcs.conf import settings
43 from rhodecode.lib.vcs.conf import settings
44 from rhodecode.lib.vcs.exceptions import RepositoryError, \
44 from rhodecode.lib.vcs.exceptions import RepositoryError, \
45 ChangesetDoesNotExistError, EmptyRepositoryError, \
45 ChangesetDoesNotExistError, EmptyRepositoryError, \
46 ImproperArchiveTypeError, VCSError, NodeAlreadyExistsError
46 ImproperArchiveTypeError, VCSError, NodeAlreadyExistsError
47 from rhodecode.lib.vcs.nodes import FileNode
47 from rhodecode.lib.vcs.nodes import FileNode
48
48
49 from rhodecode.model.repo import RepoModel
49 from rhodecode.model.repo import RepoModel
50 from rhodecode.model.scm import ScmModel
50 from rhodecode.model.scm import ScmModel
51
51
52 from rhodecode.controllers.changeset import anchor_url, _ignorews_url,\
52 from rhodecode.controllers.changeset import anchor_url, _ignorews_url,\
53 _context_url, get_line_ctx, get_ignore_ws
53 _context_url, get_line_ctx, get_ignore_ws
54
54
55
55
56 log = logging.getLogger(__name__)
56 log = logging.getLogger(__name__)
57
57
58
58
59 class FilesController(BaseRepoController):
59 class FilesController(BaseRepoController):
60
60
61 @LoginRequired()
61 @LoginRequired()
62 def __before__(self):
62 def __before__(self):
63 super(FilesController, self).__before__()
63 super(FilesController, self).__before__()
64 c.cut_off_limit = self.cut_off_limit
64 c.cut_off_limit = self.cut_off_limit
65
65
66 def __get_cs_or_redirect(self, rev, repo_name, redirect_after=True):
66 def __get_cs_or_redirect(self, rev, repo_name, redirect_after=True):
67 """
67 """
68 Safe way to get changeset if error occur it redirects to tip with
68 Safe way to get changeset if error occur it redirects to tip with
69 proper message
69 proper message
70
70
71 :param rev: revision to fetch
71 :param rev: revision to fetch
72 :param repo_name: repo name to redirect after
72 :param repo_name: repo name to redirect after
73 """
73 """
74
74
75 try:
75 try:
76 return c.rhodecode_repo.get_changeset(rev)
76 return c.rhodecode_repo.get_changeset(rev)
77 except EmptyRepositoryError, e:
77 except EmptyRepositoryError, e:
78 if not redirect_after:
78 if not redirect_after:
79 return None
79 return None
80 url_ = url('files_add_home',
80 url_ = url('files_add_home',
81 repo_name=c.repo_name,
81 repo_name=c.repo_name,
82 revision=0, f_path='')
82 revision=0, f_path='')
83 add_new = '<a href="%s">[%s]</a>' % (url_, _('add new'))
83 add_new = '<a href="%s">[%s]</a>' % (url_, _('add new'))
84 h.flash(h.literal(_('There are no files yet %s' % add_new)),
84 h.flash(h.literal(_('There are no files yet %s' % add_new)),
85 category='warning')
85 category='warning')
86 redirect(h.url('summary_home', repo_name=repo_name))
86 redirect(h.url('summary_home', repo_name=repo_name))
87
87
88 except RepositoryError, e:
88 except RepositoryError, e:
89 h.flash(str(e), category='warning')
89 h.flash(str(e), category='warning')
90 redirect(h.url('files_home', repo_name=repo_name, revision='tip'))
90 redirect(h.url('files_home', repo_name=repo_name, revision='tip'))
91
91
92 def __get_filenode_or_redirect(self, repo_name, cs, path):
92 def __get_filenode_or_redirect(self, repo_name, cs, path):
93 """
93 """
94 Returns file_node, if error occurs or given path is directory,
94 Returns file_node, if error occurs or given path is directory,
95 it'll redirect to top level path
95 it'll redirect to top level path
96
96
97 :param repo_name: repo_name
97 :param repo_name: repo_name
98 :param cs: given changeset
98 :param cs: given changeset
99 :param path: path to lookup
99 :param path: path to lookup
100 """
100 """
101
101
102 try:
102 try:
103 file_node = cs.get_node(path)
103 file_node = cs.get_node(path)
104 if file_node.is_dir():
104 if file_node.is_dir():
105 raise RepositoryError('given path is a directory')
105 raise RepositoryError('given path is a directory')
106 except RepositoryError, e:
106 except RepositoryError, e:
107 h.flash(str(e), category='warning')
107 h.flash(str(e), category='warning')
108 redirect(h.url('files_home', repo_name=repo_name,
108 redirect(h.url('files_home', repo_name=repo_name,
109 revision=cs.raw_id))
109 revision=cs.raw_id))
110
110
111 return file_node
111 return file_node
112
112
113 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
113 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
114 'repository.admin')
114 'repository.admin')
115 def index(self, repo_name, revision, f_path):
115 def index(self, repo_name, revision, f_path, annotate=False):
116 # redirect to given revision from form if given
116 # redirect to given revision from form if given
117 post_revision = request.POST.get('at_rev', None)
117 post_revision = request.POST.get('at_rev', None)
118 if post_revision:
118 if post_revision:
119 cs = self.__get_cs_or_redirect(post_revision, repo_name)
119 cs = self.__get_cs_or_redirect(post_revision, repo_name)
120 redirect(url('files_home', repo_name=c.repo_name,
120 redirect(url('files_home', repo_name=c.repo_name,
121 revision=cs.raw_id, f_path=f_path))
121 revision=cs.raw_id, f_path=f_path))
122
122
123 c.changeset = self.__get_cs_or_redirect(revision, repo_name)
123 c.changeset = self.__get_cs_or_redirect(revision, repo_name)
124 c.branch = request.GET.get('branch', None)
124 c.branch = request.GET.get('branch', None)
125 c.f_path = f_path
125 c.f_path = f_path
126
126 c.annotate = annotate
127 cur_rev = c.changeset.revision
127 cur_rev = c.changeset.revision
128
128
129 # prev link
129 # prev link
130 try:
130 try:
131 prev_rev = c.rhodecode_repo.get_changeset(cur_rev).prev(c.branch)
131 prev_rev = c.rhodecode_repo.get_changeset(cur_rev).prev(c.branch)
132 c.url_prev = url('files_home', repo_name=c.repo_name,
132 c.url_prev = url('files_home', repo_name=c.repo_name,
133 revision=prev_rev.raw_id, f_path=f_path)
133 revision=prev_rev.raw_id, f_path=f_path)
134 if c.branch:
134 if c.branch:
135 c.url_prev += '?branch=%s' % c.branch
135 c.url_prev += '?branch=%s' % c.branch
136 except (ChangesetDoesNotExistError, VCSError):
136 except (ChangesetDoesNotExistError, VCSError):
137 c.url_prev = '#'
137 c.url_prev = '#'
138
138
139 # next link
139 # next link
140 try:
140 try:
141 next_rev = c.rhodecode_repo.get_changeset(cur_rev).next(c.branch)
141 next_rev = c.rhodecode_repo.get_changeset(cur_rev).next(c.branch)
142 c.url_next = url('files_home', repo_name=c.repo_name,
142 c.url_next = url('files_home', repo_name=c.repo_name,
143 revision=next_rev.raw_id, f_path=f_path)
143 revision=next_rev.raw_id, f_path=f_path)
144 if c.branch:
144 if c.branch:
145 c.url_next += '?branch=%s' % c.branch
145 c.url_next += '?branch=%s' % c.branch
146 except (ChangesetDoesNotExistError, VCSError):
146 except (ChangesetDoesNotExistError, VCSError):
147 c.url_next = '#'
147 c.url_next = '#'
148
148
149 # files or dirs
149 # files or dirs
150 try:
150 try:
151 c.file = c.changeset.get_node(f_path)
151 c.file = c.changeset.get_node(f_path)
152
152
153 if c.file.is_file():
153 if c.file.is_file():
154 c.file_history = self._get_node_history(c.changeset, f_path)
154 c.file_history = self._get_node_history(c.changeset, f_path)
155 else:
155 else:
156 c.file_history = []
156 c.file_history = []
157 except RepositoryError, e:
157 except RepositoryError, e:
158 h.flash(str(e), category='warning')
158 h.flash(str(e), category='warning')
159 redirect(h.url('files_home', repo_name=repo_name,
159 redirect(h.url('files_home', repo_name=repo_name,
160 revision=revision))
160 revision=revision))
161
161
162 return render('files/files.html')
162 return render('files/files.html')
163
163
164 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
164 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
165 'repository.admin')
165 'repository.admin')
166 def rawfile(self, repo_name, revision, f_path):
166 def rawfile(self, repo_name, revision, f_path):
167 cs = self.__get_cs_or_redirect(revision, repo_name)
167 cs = self.__get_cs_or_redirect(revision, repo_name)
168 file_node = self.__get_filenode_or_redirect(repo_name, cs, f_path)
168 file_node = self.__get_filenode_or_redirect(repo_name, cs, f_path)
169
169
170 response.content_disposition = 'attachment; filename=%s' % \
170 response.content_disposition = 'attachment; filename=%s' % \
171 safe_str(f_path.split(os.sep)[-1])
171 safe_str(f_path.split(os.sep)[-1])
172
172
173 response.content_type = file_node.mimetype
173 response.content_type = file_node.mimetype
174 return file_node.content
174 return file_node.content
175
175
176 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
176 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
177 'repository.admin')
177 'repository.admin')
178 def raw(self, repo_name, revision, f_path):
178 def raw(self, repo_name, revision, f_path):
179 cs = self.__get_cs_or_redirect(revision, repo_name)
179 cs = self.__get_cs_or_redirect(revision, repo_name)
180 file_node = self.__get_filenode_or_redirect(repo_name, cs, f_path)
180 file_node = self.__get_filenode_or_redirect(repo_name, cs, f_path)
181
181
182 raw_mimetype_mapping = {
182 raw_mimetype_mapping = {
183 # map original mimetype to a mimetype used for "show as raw"
183 # map original mimetype to a mimetype used for "show as raw"
184 # you can also provide a content-disposition to override the
184 # you can also provide a content-disposition to override the
185 # default "attachment" disposition.
185 # default "attachment" disposition.
186 # orig_type: (new_type, new_dispo)
186 # orig_type: (new_type, new_dispo)
187
187
188 # show images inline:
188 # show images inline:
189 'image/x-icon': ('image/x-icon', 'inline'),
189 'image/x-icon': ('image/x-icon', 'inline'),
190 'image/png': ('image/png', 'inline'),
190 'image/png': ('image/png', 'inline'),
191 'image/gif': ('image/gif', 'inline'),
191 'image/gif': ('image/gif', 'inline'),
192 'image/jpeg': ('image/jpeg', 'inline'),
192 'image/jpeg': ('image/jpeg', 'inline'),
193 'image/svg+xml': ('image/svg+xml', 'inline'),
193 'image/svg+xml': ('image/svg+xml', 'inline'),
194 }
194 }
195
195
196 mimetype = file_node.mimetype
196 mimetype = file_node.mimetype
197 try:
197 try:
198 mimetype, dispo = raw_mimetype_mapping[mimetype]
198 mimetype, dispo = raw_mimetype_mapping[mimetype]
199 except KeyError:
199 except KeyError:
200 # we don't know anything special about this, handle it safely
200 # we don't know anything special about this, handle it safely
201 if file_node.is_binary:
201 if file_node.is_binary:
202 # do same as download raw for binary files
202 # do same as download raw for binary files
203 mimetype, dispo = 'application/octet-stream', 'attachment'
203 mimetype, dispo = 'application/octet-stream', 'attachment'
204 else:
204 else:
205 # do not just use the original mimetype, but force text/plain,
205 # do not just use the original mimetype, but force text/plain,
206 # otherwise it would serve text/html and that might be unsafe.
206 # otherwise it would serve text/html and that might be unsafe.
207 # Note: underlying vcs library fakes text/plain mimetype if the
207 # Note: underlying vcs library fakes text/plain mimetype if the
208 # mimetype can not be determined and it thinks it is not
208 # mimetype can not be determined and it thinks it is not
209 # binary.This might lead to erroneous text display in some
209 # binary.This might lead to erroneous text display in some
210 # cases, but helps in other cases, like with text files
210 # cases, but helps in other cases, like with text files
211 # without extension.
211 # without extension.
212 mimetype, dispo = 'text/plain', 'inline'
212 mimetype, dispo = 'text/plain', 'inline'
213
213
214 if dispo == 'attachment':
214 if dispo == 'attachment':
215 dispo = 'attachment; filename=%s' % \
215 dispo = 'attachment; filename=%s' % \
216 safe_str(f_path.split(os.sep)[-1])
216 safe_str(f_path.split(os.sep)[-1])
217
217
218 response.content_disposition = dispo
218 response.content_disposition = dispo
219 response.content_type = mimetype
219 response.content_type = mimetype
220 return file_node.content
220 return file_node.content
221
221
222 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
223 'repository.admin')
224 def annotate(self, repo_name, revision, f_path):
225 c.cs = self.__get_cs_or_redirect(revision, repo_name)
226 c.file = self.__get_filenode_or_redirect(repo_name, c.cs, f_path)
227
228 c.file_history = self._get_node_history(c.cs, f_path)
229 c.f_path = f_path
230 return render('files/files_annotate.html')
231
232 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
222 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
233 def edit(self, repo_name, revision, f_path):
223 def edit(self, repo_name, revision, f_path):
234 r_post = request.POST
224 r_post = request.POST
235
225
236 c.cs = self.__get_cs_or_redirect(revision, repo_name)
226 c.cs = self.__get_cs_or_redirect(revision, repo_name)
237 c.file = self.__get_filenode_or_redirect(repo_name, c.cs, f_path)
227 c.file = self.__get_filenode_or_redirect(repo_name, c.cs, f_path)
238
228
239 if c.file.is_binary:
229 if c.file.is_binary:
240 return redirect(url('files_home', repo_name=c.repo_name,
230 return redirect(url('files_home', repo_name=c.repo_name,
241 revision=c.cs.raw_id, f_path=f_path))
231 revision=c.cs.raw_id, f_path=f_path))
242
232
243 c.f_path = f_path
233 c.f_path = f_path
244
234
245 if r_post:
235 if r_post:
246
236
247 old_content = c.file.content
237 old_content = c.file.content
248 sl = old_content.splitlines(1)
238 sl = old_content.splitlines(1)
249 first_line = sl[0] if sl else ''
239 first_line = sl[0] if sl else ''
250 # modes: 0 - Unix, 1 - Mac, 2 - DOS
240 # modes: 0 - Unix, 1 - Mac, 2 - DOS
251 mode = detect_mode(first_line, 0)
241 mode = detect_mode(first_line, 0)
252 content = convert_line_endings(r_post.get('content'), mode)
242 content = convert_line_endings(r_post.get('content'), mode)
253
243
254 message = r_post.get('message') or (_('Edited %s via RhodeCode')
244 message = r_post.get('message') or (_('Edited %s via RhodeCode')
255 % (f_path))
245 % (f_path))
256 author = self.rhodecode_user.full_contact
246 author = self.rhodecode_user.full_contact
257
247
258 if content == old_content:
248 if content == old_content:
259 h.flash(_('No changes'),
249 h.flash(_('No changes'),
260 category='warning')
250 category='warning')
261 return redirect(url('changeset_home', repo_name=c.repo_name,
251 return redirect(url('changeset_home', repo_name=c.repo_name,
262 revision='tip'))
252 revision='tip'))
263
253
264 try:
254 try:
265 self.scm_model.commit_change(repo=c.rhodecode_repo,
255 self.scm_model.commit_change(repo=c.rhodecode_repo,
266 repo_name=repo_name, cs=c.cs,
256 repo_name=repo_name, cs=c.cs,
267 user=self.rhodecode_user,
257 user=self.rhodecode_user,
268 author=author, message=message,
258 author=author, message=message,
269 content=content, f_path=f_path)
259 content=content, f_path=f_path)
270 h.flash(_('Successfully committed to %s' % f_path),
260 h.flash(_('Successfully committed to %s' % f_path),
271 category='success')
261 category='success')
272
262
273 except Exception:
263 except Exception:
274 log.error(traceback.format_exc())
264 log.error(traceback.format_exc())
275 h.flash(_('Error occurred during commit'), category='error')
265 h.flash(_('Error occurred during commit'), category='error')
276 return redirect(url('changeset_home',
266 return redirect(url('changeset_home',
277 repo_name=c.repo_name, revision='tip'))
267 repo_name=c.repo_name, revision='tip'))
278
268
279 return render('files/files_edit.html')
269 return render('files/files_edit.html')
280
270
281 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
271 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
282 def add(self, repo_name, revision, f_path):
272 def add(self, repo_name, revision, f_path):
283 r_post = request.POST
273 r_post = request.POST
284 c.cs = self.__get_cs_or_redirect(revision, repo_name,
274 c.cs = self.__get_cs_or_redirect(revision, repo_name,
285 redirect_after=False)
275 redirect_after=False)
286 if c.cs is None:
276 if c.cs is None:
287 c.cs = EmptyChangeset(alias=c.rhodecode_repo.alias)
277 c.cs = EmptyChangeset(alias=c.rhodecode_repo.alias)
288
278
289 c.f_path = f_path
279 c.f_path = f_path
290
280
291 if r_post:
281 if r_post:
292 unix_mode = 0
282 unix_mode = 0
293 content = convert_line_endings(r_post.get('content'), unix_mode)
283 content = convert_line_endings(r_post.get('content'), unix_mode)
294
284
295 message = r_post.get('message') or (_('Added %s via RhodeCode')
285 message = r_post.get('message') or (_('Added %s via RhodeCode')
296 % (f_path))
286 % (f_path))
297 location = r_post.get('location')
287 location = r_post.get('location')
298 filename = r_post.get('filename')
288 filename = r_post.get('filename')
299 file_obj = r_post.get('upload_file', None)
289 file_obj = r_post.get('upload_file', None)
300
290
301 if file_obj is not None and hasattr(file_obj, 'filename'):
291 if file_obj is not None and hasattr(file_obj, 'filename'):
302 filename = file_obj.filename
292 filename = file_obj.filename
303 content = file_obj.file
293 content = file_obj.file
304
294
305 node_path = os.path.join(location, filename)
295 node_path = os.path.join(location, filename)
306 author = self.rhodecode_user.full_contact
296 author = self.rhodecode_user.full_contact
307
297
308 if not content:
298 if not content:
309 h.flash(_('No content'), category='warning')
299 h.flash(_('No content'), category='warning')
310 return redirect(url('changeset_home', repo_name=c.repo_name,
300 return redirect(url('changeset_home', repo_name=c.repo_name,
311 revision='tip'))
301 revision='tip'))
312 if not filename:
302 if not filename:
313 h.flash(_('No filename'), category='warning')
303 h.flash(_('No filename'), category='warning')
314 return redirect(url('changeset_home', repo_name=c.repo_name,
304 return redirect(url('changeset_home', repo_name=c.repo_name,
315 revision='tip'))
305 revision='tip'))
316
306
317 try:
307 try:
318 self.scm_model.create_node(repo=c.rhodecode_repo,
308 self.scm_model.create_node(repo=c.rhodecode_repo,
319 repo_name=repo_name, cs=c.cs,
309 repo_name=repo_name, cs=c.cs,
320 user=self.rhodecode_user,
310 user=self.rhodecode_user,
321 author=author, message=message,
311 author=author, message=message,
322 content=content, f_path=node_path)
312 content=content, f_path=node_path)
323 h.flash(_('Successfully committed to %s' % node_path),
313 h.flash(_('Successfully committed to %s' % node_path),
324 category='success')
314 category='success')
325 except NodeAlreadyExistsError, e:
315 except NodeAlreadyExistsError, e:
326 h.flash(_(e), category='error')
316 h.flash(_(e), category='error')
327 except Exception:
317 except Exception:
328 log.error(traceback.format_exc())
318 log.error(traceback.format_exc())
329 h.flash(_('Error occurred during commit'), category='error')
319 h.flash(_('Error occurred during commit'), category='error')
330 return redirect(url('changeset_home',
320 return redirect(url('changeset_home',
331 repo_name=c.repo_name, revision='tip'))
321 repo_name=c.repo_name, revision='tip'))
332
322
333 return render('files/files_add.html')
323 return render('files/files_add.html')
334
324
335 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
325 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
336 'repository.admin')
326 'repository.admin')
337 def archivefile(self, repo_name, fname):
327 def archivefile(self, repo_name, fname):
338
328
339 fileformat = None
329 fileformat = None
340 revision = None
330 revision = None
341 ext = None
331 ext = None
342 subrepos = request.GET.get('subrepos') == 'true'
332 subrepos = request.GET.get('subrepos') == 'true'
343
333
344 for a_type, ext_data in settings.ARCHIVE_SPECS.items():
334 for a_type, ext_data in settings.ARCHIVE_SPECS.items():
345 archive_spec = fname.split(ext_data[1])
335 archive_spec = fname.split(ext_data[1])
346 if len(archive_spec) == 2 and archive_spec[1] == '':
336 if len(archive_spec) == 2 and archive_spec[1] == '':
347 fileformat = a_type or ext_data[1]
337 fileformat = a_type or ext_data[1]
348 revision = archive_spec[0]
338 revision = archive_spec[0]
349 ext = ext_data[1]
339 ext = ext_data[1]
350
340
351 try:
341 try:
352 dbrepo = RepoModel().get_by_repo_name(repo_name)
342 dbrepo = RepoModel().get_by_repo_name(repo_name)
353 if dbrepo.enable_downloads is False:
343 if dbrepo.enable_downloads is False:
354 return _('downloads disabled')
344 return _('downloads disabled')
355
345
356 if c.rhodecode_repo.alias == 'hg':
346 if c.rhodecode_repo.alias == 'hg':
357 # patch and reset hooks section of UI config to not run any
347 # patch and reset hooks section of UI config to not run any
358 # hooks on fetching archives with subrepos
348 # hooks on fetching archives with subrepos
359 for k, v in c.rhodecode_repo._repo.ui.configitems('hooks'):
349 for k, v in c.rhodecode_repo._repo.ui.configitems('hooks'):
360 c.rhodecode_repo._repo.ui.setconfig('hooks', k, None)
350 c.rhodecode_repo._repo.ui.setconfig('hooks', k, None)
361
351
362 cs = c.rhodecode_repo.get_changeset(revision)
352 cs = c.rhodecode_repo.get_changeset(revision)
363 content_type = settings.ARCHIVE_SPECS[fileformat][0]
353 content_type = settings.ARCHIVE_SPECS[fileformat][0]
364 except ChangesetDoesNotExistError:
354 except ChangesetDoesNotExistError:
365 return _('Unknown revision %s') % revision
355 return _('Unknown revision %s') % revision
366 except EmptyRepositoryError:
356 except EmptyRepositoryError:
367 return _('Empty repository')
357 return _('Empty repository')
368 except (ImproperArchiveTypeError, KeyError):
358 except (ImproperArchiveTypeError, KeyError):
369 return _('Unknown archive type')
359 return _('Unknown archive type')
370
360
371 response.content_type = content_type
361 response.content_type = content_type
372 response.content_disposition = 'attachment; filename=%s-%s%s' \
362 response.content_disposition = 'attachment; filename=%s-%s%s' \
373 % (repo_name, revision, ext)
363 % (repo_name, revision, ext)
374
364
375 import tempfile
365 import tempfile
376 archive = tempfile.mkstemp()[1]
366 archive = tempfile.mkstemp()[1]
377 t = open(archive, 'wb')
367 t = open(archive, 'wb')
378 cs.fill_archive(stream=t, kind=fileformat, subrepos=subrepos)
368 cs.fill_archive(stream=t, kind=fileformat, subrepos=subrepos)
379
369
380 def get_chunked_archive(archive):
370 def get_chunked_archive(archive):
381 stream = open(archive, 'rb')
371 stream = open(archive, 'rb')
382 while True:
372 while True:
383 data = stream.read(4096)
373 data = stream.read(4096)
384 if not data:
374 if not data:
385 os.remove(archive)
375 os.remove(archive)
386 break
376 break
387 yield data
377 yield data
388
378
389 return get_chunked_archive(archive)
379 return get_chunked_archive(archive)
390
380
391 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
381 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
392 'repository.admin')
382 'repository.admin')
393 def diff(self, repo_name, f_path):
383 def diff(self, repo_name, f_path):
394 ignore_whitespace = request.GET.get('ignorews') == '1'
384 ignore_whitespace = request.GET.get('ignorews') == '1'
395 line_context = request.GET.get('context', 3)
385 line_context = request.GET.get('context', 3)
396 diff1 = request.GET.get('diff1', '')
386 diff1 = request.GET.get('diff1', '')
397 diff2 = request.GET.get('diff2', '')
387 diff2 = request.GET.get('diff2', '')
398 c.action = request.GET.get('diff')
388 c.action = request.GET.get('diff')
399 c.no_changes = diff1 == diff2
389 c.no_changes = diff1 == diff2
400 c.f_path = f_path
390 c.f_path = f_path
401 c.big_diff = False
391 c.big_diff = False
402 c.anchor_url = anchor_url
392 c.anchor_url = anchor_url
403 c.ignorews_url = _ignorews_url
393 c.ignorews_url = _ignorews_url
404 c.context_url = _context_url
394 c.context_url = _context_url
405 c.changes = OrderedDict()
395 c.changes = OrderedDict()
406 c.changes[diff2] = []
396 c.changes[diff2] = []
407 try:
397 try:
408 if diff1 not in ['', None, 'None', '0' * 12, '0' * 40]:
398 if diff1 not in ['', None, 'None', '0' * 12, '0' * 40]:
409 c.changeset_1 = c.rhodecode_repo.get_changeset(diff1)
399 c.changeset_1 = c.rhodecode_repo.get_changeset(diff1)
410 node1 = c.changeset_1.get_node(f_path)
400 node1 = c.changeset_1.get_node(f_path)
411 else:
401 else:
412 c.changeset_1 = EmptyChangeset(repo=c.rhodecode_repo)
402 c.changeset_1 = EmptyChangeset(repo=c.rhodecode_repo)
413 node1 = FileNode('.', '', changeset=c.changeset_1)
403 node1 = FileNode('.', '', changeset=c.changeset_1)
414
404
415 if diff2 not in ['', None, 'None', '0' * 12, '0' * 40]:
405 if diff2 not in ['', None, 'None', '0' * 12, '0' * 40]:
416 c.changeset_2 = c.rhodecode_repo.get_changeset(diff2)
406 c.changeset_2 = c.rhodecode_repo.get_changeset(diff2)
417 node2 = c.changeset_2.get_node(f_path)
407 node2 = c.changeset_2.get_node(f_path)
418 else:
408 else:
419 c.changeset_2 = EmptyChangeset(repo=c.rhodecode_repo)
409 c.changeset_2 = EmptyChangeset(repo=c.rhodecode_repo)
420 node2 = FileNode('.', '', changeset=c.changeset_2)
410 node2 = FileNode('.', '', changeset=c.changeset_2)
421 except RepositoryError:
411 except RepositoryError:
422 return redirect(url('files_home', repo_name=c.repo_name,
412 return redirect(url('files_home', repo_name=c.repo_name,
423 f_path=f_path))
413 f_path=f_path))
424
414
425 if c.action == 'download':
415 if c.action == 'download':
426 _diff = diffs.get_gitdiff(node1, node2,
416 _diff = diffs.get_gitdiff(node1, node2,
427 ignore_whitespace=ignore_whitespace,
417 ignore_whitespace=ignore_whitespace,
428 context=line_context)
418 context=line_context)
429 diff = diffs.DiffProcessor(_diff, format='gitdiff')
419 diff = diffs.DiffProcessor(_diff, format='gitdiff')
430
420
431 diff_name = '%s_vs_%s.diff' % (diff1, diff2)
421 diff_name = '%s_vs_%s.diff' % (diff1, diff2)
432 response.content_type = 'text/plain'
422 response.content_type = 'text/plain'
433 response.content_disposition = (
423 response.content_disposition = (
434 'attachment; filename=%s' % diff_name
424 'attachment; filename=%s' % diff_name
435 )
425 )
436 return diff.raw_diff()
426 return diff.raw_diff()
437
427
438 elif c.action == 'raw':
428 elif c.action == 'raw':
439 _diff = diffs.get_gitdiff(node1, node2,
429 _diff = diffs.get_gitdiff(node1, node2,
440 ignore_whitespace=ignore_whitespace,
430 ignore_whitespace=ignore_whitespace,
441 context=line_context)
431 context=line_context)
442 diff = diffs.DiffProcessor(_diff, format='gitdiff')
432 diff = diffs.DiffProcessor(_diff, format='gitdiff')
443 response.content_type = 'text/plain'
433 response.content_type = 'text/plain'
444 return diff.raw_diff()
434 return diff.raw_diff()
445
435
446 else:
436 else:
447 fid = h.FID(diff2, node2.path)
437 fid = h.FID(diff2, node2.path)
448 line_context_lcl = get_line_ctx(fid, request.GET)
438 line_context_lcl = get_line_ctx(fid, request.GET)
449 ign_whitespace_lcl = get_ignore_ws(fid, request.GET)
439 ign_whitespace_lcl = get_ignore_ws(fid, request.GET)
450
440
451 lim = request.GET.get('fulldiff') or self.cut_off_limit
441 lim = request.GET.get('fulldiff') or self.cut_off_limit
452 _, cs1, cs2, diff, st = diffs.wrapped_diff(filenode_old=node1,
442 _, cs1, cs2, diff, st = diffs.wrapped_diff(filenode_old=node1,
453 filenode_new=node2,
443 filenode_new=node2,
454 cut_off_limit=lim,
444 cut_off_limit=lim,
455 ignore_whitespace=ign_whitespace_lcl,
445 ignore_whitespace=ign_whitespace_lcl,
456 line_context=line_context_lcl,
446 line_context=line_context_lcl,
457 enable_comments=False)
447 enable_comments=False)
458
448
459 c.changes = [('', node2, diff, cs1, cs2, st,)]
449 c.changes = [('', node2, diff, cs1, cs2, st,)]
460
450
461 return render('files/file_diff.html')
451 return render('files/file_diff.html')
462
452
463 def _get_node_history(self, cs, f_path):
453 def _get_node_history(self, cs, f_path):
464 changesets = cs.get_file_history(f_path)
454 changesets = cs.get_file_history(f_path)
465 hist_l = []
455 hist_l = []
466
456
467 changesets_group = ([], _("Changesets"))
457 changesets_group = ([], _("Changesets"))
468 branches_group = ([], _("Branches"))
458 branches_group = ([], _("Branches"))
469 tags_group = ([], _("Tags"))
459 tags_group = ([], _("Tags"))
470 _hg = cs.repository.alias == 'hg'
460 _hg = cs.repository.alias == 'hg'
471 for chs in changesets:
461 for chs in changesets:
472 _branch = '(%s)' % chs.branch if _hg else ''
462 _branch = '(%s)' % chs.branch if _hg else ''
473 n_desc = 'r%s:%s %s' % (chs.revision, chs.short_id, _branch)
463 n_desc = 'r%s:%s %s' % (chs.revision, chs.short_id, _branch)
474 changesets_group[0].append((chs.raw_id, n_desc,))
464 changesets_group[0].append((chs.raw_id, n_desc,))
475
465
476 hist_l.append(changesets_group)
466 hist_l.append(changesets_group)
477
467
478 for name, chs in c.rhodecode_repo.branches.items():
468 for name, chs in c.rhodecode_repo.branches.items():
479 branches_group[0].append((chs, name),)
469 branches_group[0].append((chs, name),)
480 hist_l.append(branches_group)
470 hist_l.append(branches_group)
481
471
482 for name, chs in c.rhodecode_repo.tags.items():
472 for name, chs in c.rhodecode_repo.tags.items():
483 tags_group[0].append((chs, name),)
473 tags_group[0].append((chs, name),)
484 hist_l.append(tags_group)
474 hist_l.append(tags_group)
485
475
486 return hist_l
476 return hist_l
487
477
488 @jsonify
478 @jsonify
489 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
479 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
490 'repository.admin')
480 'repository.admin')
491 def nodelist(self, repo_name, revision, f_path):
481 def nodelist(self, repo_name, revision, f_path):
492 if request.environ.get('HTTP_X_PARTIAL_XHR'):
482 if request.environ.get('HTTP_X_PARTIAL_XHR'):
493 cs = self.__get_cs_or_redirect(revision, repo_name)
483 cs = self.__get_cs_or_redirect(revision, repo_name)
494 _d, _f = ScmModel().get_nodes(repo_name, cs.raw_id, f_path,
484 _d, _f = ScmModel().get_nodes(repo_name, cs.raw_id, f_path,
495 flat=False)
485 flat=False)
496 return _d + _f
486 return _d + _f
@@ -1,104 +1,114 b''
1 <dl>
1 <dl>
2 <dt style="padding-top:10px;font-size:16px">${_('History')}</dt>
2 <dt style="padding-top:10px;font-size:16px">${_('History')}</dt>
3 <dd>
3 <dd>
4 <div>
4 <div>
5 ${h.form(h.url('files_diff_home',repo_name=c.repo_name,f_path=c.f_path),method='get')}
5 ${h.form(h.url('files_diff_home',repo_name=c.repo_name,f_path=c.f_path),method='get')}
6 ${h.hidden('diff2',c.file.changeset.raw_id)}
6 ${h.hidden('diff2',c.file.changeset.raw_id)}
7 ${h.select('diff1',c.file.changeset.raw_id,c.file_history)}
7 ${h.select('diff1',c.file.changeset.raw_id,c.file_history)}
8 ${h.submit('diff','diff to revision',class_="ui-btn")}
8 ${h.submit('diff','diff to revision',class_="ui-btn")}
9 ${h.submit('show_rev','show at revision',class_="ui-btn")}
9 ${h.submit('show_rev','show at revision',class_="ui-btn")}
10 ${h.end_form()}
10 ${h.end_form()}
11 </div>
11 </div>
12 </dd>
12 </dd>
13 </dl>
13 </dl>
14
14
15 <div id="body" class="codeblock">
15 <div id="body" class="codeblock">
16 <div class="code-header">
16 <div class="code-header">
17 <div class="stats">
17 <div class="stats">
18 <div class="left img"><img src="${h.url('/images/icons/file.png')}"/></div>
18 <div class="left img"><img src="${h.url('/images/icons/file.png')}"/></div>
19 <div class="left item"><pre>${h.link_to("r%s:%s" % (c.file.changeset.revision,h.short_id(c.file.changeset.raw_id)),h.url('changeset_home',repo_name=c.repo_name,revision=c.file.changeset.raw_id))}</pre></div>
19 <div class="left item"><pre>${h.link_to("r%s:%s" % (c.file.changeset.revision,h.short_id(c.file.changeset.raw_id)),h.url('changeset_home',repo_name=c.repo_name,revision=c.file.changeset.raw_id))}</pre></div>
20 <div class="left item"><pre>${h.format_byte_size(c.file.size,binary=True)}</pre></div>
20 <div class="left item"><pre>${h.format_byte_size(c.file.size,binary=True)}</pre></div>
21 <div class="left item last"><pre>${c.file.mimetype}</pre></div>
21 <div class="left item last"><pre>${c.file.mimetype}</pre></div>
22 <div class="buttons">
22 <div class="buttons">
23 ${h.link_to(_('show annotation'),h.url('files_annotate_home',repo_name=c.repo_name,revision=c.file.changeset.raw_id,f_path=c.f_path),class_="ui-btn")}
23 %if c.annotate:
24 ${h.link_to(_('show source'), h.url('files_home', repo_name=c.repo_name,revision=c.file.changeset.raw_id,f_path=c.f_path),class_="ui-btn")}
25 %else:
26 ${h.link_to(_('show annotation'),h.url('files_annotate_home',repo_name=c.repo_name,revision=c.file.changeset.raw_id,f_path=c.f_path),class_="ui-btn")}
27 %endif
24 ${h.link_to(_('show as raw'),h.url('files_raw_home',repo_name=c.repo_name,revision=c.file.changeset.raw_id,f_path=c.f_path),class_="ui-btn")}
28 ${h.link_to(_('show as raw'),h.url('files_raw_home',repo_name=c.repo_name,revision=c.file.changeset.raw_id,f_path=c.f_path),class_="ui-btn")}
25 ${h.link_to(_('download as raw'),h.url('files_rawfile_home',repo_name=c.repo_name,revision=c.file.changeset.raw_id,f_path=c.f_path),class_="ui-btn")}
29 ${h.link_to(_('download as raw'),h.url('files_rawfile_home',repo_name=c.repo_name,revision=c.file.changeset.raw_id,f_path=c.f_path),class_="ui-btn")}
26 % if h.HasRepoPermissionAny('repository.write','repository.admin')(c.repo_name):
30 % if h.HasRepoPermissionAny('repository.write','repository.admin')(c.repo_name):
27 % if not c.file.is_binary:
31 % if not c.file.is_binary:
28 ${h.link_to(_('edit'),h.url('files_edit_home',repo_name=c.repo_name,revision=c.file.changeset.raw_id,f_path=c.f_path),class_="ui-btn")}
32 ${h.link_to(_('edit'),h.url('files_edit_home',repo_name=c.repo_name,revision=c.file.changeset.raw_id,f_path=c.f_path),class_="ui-btn")}
29 % endif
33 % endif
30 % endif
34 % endif
31 </div>
35 </div>
32 </div>
36 </div>
33 <div class="author">
37 <div class="author">
34 <div class="gravatar">
38 <div class="gravatar">
35 <img alt="gravatar" src="${h.gravatar_url(h.email(c.file.changeset.author),16)}"/>
39 <img alt="gravatar" src="${h.gravatar_url(h.email(c.file.changeset.author),16)}"/>
36 </div>
40 </div>
37 <div title="${c.file.changeset.author}" class="user">${h.person(c.file.changeset.author)}</div>
41 <div title="${c.file.changeset.author}" class="user">${h.person(c.file.changeset.author)}</div>
38 </div>
42 </div>
39 <div class="commit">${h.urlify_commit(c.file.changeset.message,c.repo_name)}</div>
43 <div class="commit">${h.urlify_commit(c.file.changeset.message,c.repo_name)}</div>
40 </div>
44 </div>
41 <div class="code-body">
45 <div class="code-body">
42 %if c.file.is_binary:
46 %if c.file.is_binary:
43 ${_('Binary file (%s)') % c.file.mimetype}
47 ${_('Binary file (%s)') % c.file.mimetype}
44 %else:
48 %else:
45 % if c.file.size < c.cut_off_limit:
49 % if c.file.size < c.cut_off_limit:
46 ${h.pygmentize(c.file,linenos=True,anchorlinenos=True,lineanchors='L',cssclass="code-highlight")}
50 %if c.annotate:
51 ${h.pygmentize_annotation(c.repo_name,c.file,linenos=True,anchorlinenos=True,lineanchors='L',cssclass="code-highlight")}
52 %else:
53 ${h.pygmentize(c.file,linenos=True,anchorlinenos=True,lineanchors='L',cssclass="code-highlight")}
54 %endif
47 %else:
55 %else:
48 ${_('File is too big to display')} ${h.link_to(_('show as raw'),
56 ${_('File is too big to display')} ${h.link_to(_('show as raw'),
49 h.url('files_raw_home',repo_name=c.repo_name,revision=c.file.changeset.raw_id,f_path=c.f_path))}
57 h.url('files_raw_home',repo_name=c.repo_name,revision=c.file.changeset.raw_id,f_path=c.f_path))}
50 %endif
58 %endif
51 <script type="text/javascript">
52 function highlight_lines(lines){
53 for(pos in lines){
54 YUD.setStyle('L'+lines[pos],'background-color','#FFFFBE');
55 }
56 }
57 page_highlights = location.href.substring(location.href.indexOf('#')+1).split('L');
58 if (page_highlights.length == 2){
59 highlight_ranges = page_highlights[1].split(",");
60
61 var h_lines = [];
62 for (pos in highlight_ranges){
63 var _range = highlight_ranges[pos].split('-');
64 if(_range.length == 2){
65 var start = parseInt(_range[0]);
66 var end = parseInt(_range[1]);
67 if (start < end){
68 for(var i=start;i<=end;i++){
69 h_lines.push(i);
70 }
71 }
72 }
73 else{
74 h_lines.push(parseInt(highlight_ranges[pos]));
75 }
76 }
77 highlight_lines(h_lines);
78
79 //remember original location
80 var old_hash = location.href.substring(location.href.indexOf('#'));
81
82 // this makes a jump to anchor moved by 3 posstions for padding
83 window.location.hash = '#L'+Math.max(parseInt(h_lines[0])-3,1);
84
85 //sets old anchor
86 window.location.hash = old_hash;
87
88 }
89 </script>
90 %endif
59 %endif
91 </div>
60 </div>
92 </div>
61 </div>
93
62
94 <script type="text/javascript">
63 <script type="text/javascript">
95 YUE.onDOMReady(function(){
64 YUE.onDOMReady(function(){
65 function highlight_lines(lines){
66 for(pos in lines){
67 YUD.setStyle('L'+lines[pos],'background-color','#FFFFBE');
68 }
69 }
70 page_highlights = location.href.substring(location.href.indexOf('#')+1).split('L');
71 if (page_highlights.length == 2){
72 highlight_ranges = page_highlights[1].split(",");
73
74 var h_lines = [];
75 for (pos in highlight_ranges){
76 var _range = highlight_ranges[pos].split('-');
77 if(_range.length == 2){
78 var start = parseInt(_range[0]);
79 var end = parseInt(_range[1]);
80 if (start < end){
81 for(var i=start;i<=end;i++){
82 h_lines.push(i);
83 }
84 }
85 }
86 else{
87 h_lines.push(parseInt(highlight_ranges[pos]));
88 }
89 }
90 highlight_lines(h_lines);
91
92 //remember original location
93 var old_hash = location.href.substring(location.href.indexOf('#'));
94
95 // this makes a jump to anchor moved by 3 posstions for padding
96 window.location.hash = '#L'+Math.max(parseInt(h_lines[0])-3,1);
97
98 //sets old anchor
99 window.location.hash = old_hash;
100
101 }
96 YUE.on('show_rev','click',function(e){
102 YUE.on('show_rev','click',function(e){
97 YUE.preventDefault(e);
103 YUE.preventDefault(e);
98 var cs = YUD.get('diff1').value;
104 var cs = YUD.get('diff1').value;
99 var url = "${h.url('files_home',repo_name=c.repo_name,revision='__CS__',f_path=c.f_path)}".replace('__CS__',cs);
105 %if c.annotate:
106 var url = "${h.url('files_annotate_home',repo_name=c.repo_name,revision='__CS__',f_path=c.f_path)}".replace('__CS__',cs);
107 %else:
108 var url = "${h.url('files_home',repo_name=c.repo_name,revision='__CS__',f_path=c.f_path)}".replace('__CS__',cs);
109 %endif
100 window.location = url;
110 window.location = url;
101 });
111 });
102 YUE.on('hlcode','mouseup',getSelectionLink("${_('Selection link')}"))
112 YUE.on('hlcode','mouseup',getSelectionLink("${_('Selection link')}"))
103 });
113 });
104 </script>
114 </script>
@@ -1,15 +1,18 b''
1 %if c.file:
1 %if c.file:
2 <h3 class="files_location">
2 <h3 class="files_location">
3 ${_('Location')}: ${h.files_breadcrumbs(c.repo_name,c.changeset.raw_id,c.file.path)}
3 ${_('Location')}: ${h.files_breadcrumbs(c.repo_name,c.changeset.raw_id,c.file.path)}
4 %if c.annotate:
5 - ${_('annotation')}
6 %endif
4 </h3>
7 </h3>
5 %if c.file.is_dir():
8 %if c.file.is_dir():
6 <%include file='files_browser.html'/>
9 <%include file='files_browser.html'/>
7 %else:
10 %else:
8 <%include file='files_source.html'/>
11 <%include file='files_source.html'/>
9 %endif
12 %endif
10 %else:
13 %else:
11 <h2>
14 <h2>
12 <a href="#" onClick="javascript:parent.history.back();" target="main">${_('Go back')}</a>
15 <a href="#" onClick="javascript:parent.history.back();" target="main">${_('Go back')}</a>
13 ${_('No files at given path')}: "${c.f_path or "/"}"
16 ${_('No files at given path')}: "${c.f_path or "/"}"
14 </h2>
17 </h2>
15 %endif
18 %endif
1 NO CONTENT: file was removed
NO CONTENT: file was removed
General Comments 0
You need to be logged in to leave comments. Login now