##// END OF EJS Templates
better detection of deleting groups with subgroups inside....
marcink -
r3458:0ad025ee beta
parent child Browse files
Show More
@@ -1,648 +1,661 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 if match_dict.get('f_path'):
35 if match_dict.get('f_path'):
36 #fix for multiple initial slashes that causes errors
36 #fix for multiple initial slashes that causes errors
37 match_dict['f_path'] = match_dict['f_path'].lstrip('/')
37 match_dict['f_path'] = match_dict['f_path'].lstrip('/')
38
38
39 try:
39 try:
40 by_id = repo_name.split('_')
40 by_id = repo_name.split('_')
41 if len(by_id) == 2 and by_id[1].isdigit() and by_id[0] == '':
41 if len(by_id) == 2 and by_id[1].isdigit() and by_id[0] == '':
42 repo_name = Repository.get(by_id[1]).repo_name
42 repo_name = Repository.get(by_id[1]).repo_name
43 match_dict['repo_name'] = repo_name
43 match_dict['repo_name'] = repo_name
44 except:
44 except:
45 pass
45 pass
46
46
47 return is_valid_repo(repo_name, config['base_path'])
47 return is_valid_repo(repo_name, config['base_path'])
48
48
49 def check_group(environ, match_dict):
49 def check_group(environ, match_dict):
50 """
50 """
51 check for valid repository group for proper 404 handling
51 check for valid repository group for proper 404 handling
52
52
53 :param environ:
53 :param environ:
54 :param match_dict:
54 :param match_dict:
55 """
55 """
56 repos_group_name = match_dict.get('group_name')
56 repos_group_name = match_dict.get('group_name')
57 return is_valid_repos_group(repos_group_name, config['base_path'])
57 return is_valid_repos_group(repos_group_name, config['base_path'])
58
58
59 def check_group_skip_path(environ, match_dict):
60 """
61 check for valid repository group for proper 404 handling, but skips
62 verification of existing path
63
64 :param environ:
65 :param match_dict:
66 """
67 repos_group_name = match_dict.get('group_name')
68 return is_valid_repos_group(repos_group_name, config['base_path'],
69 skip_path_check=True)
70
59 def check_int(environ, match_dict):
71 def check_int(environ, match_dict):
60 return match_dict.get('id').isdigit()
72 return match_dict.get('id').isdigit()
61
73
62 # The ErrorController route (handles 404/500 error pages); it should
74 # The ErrorController route (handles 404/500 error pages); it should
63 # likely stay at the top, ensuring it can always be resolved
75 # likely stay at the top, ensuring it can always be resolved
64 rmap.connect('/error/{action}', controller='error')
76 rmap.connect('/error/{action}', controller='error')
65 rmap.connect('/error/{action}/{id}', controller='error')
77 rmap.connect('/error/{action}/{id}', controller='error')
66
78
67 #==========================================================================
79 #==========================================================================
68 # CUSTOM ROUTES HERE
80 # CUSTOM ROUTES HERE
69 #==========================================================================
81 #==========================================================================
70
82
71 #MAIN PAGE
83 #MAIN PAGE
72 rmap.connect('home', '/', controller='home', action='index')
84 rmap.connect('home', '/', controller='home', action='index')
73 rmap.connect('repo_switcher', '/repos', controller='home',
85 rmap.connect('repo_switcher', '/repos', controller='home',
74 action='repo_switcher')
86 action='repo_switcher')
75 rmap.connect('branch_tag_switcher', '/branches-tags/{repo_name:.*?}',
87 rmap.connect('branch_tag_switcher', '/branches-tags/{repo_name:.*?}',
76 controller='home', action='branch_tag_switcher')
88 controller='home', action='branch_tag_switcher')
77 rmap.connect('bugtracker',
89 rmap.connect('bugtracker',
78 "http://bitbucket.org/marcinkuzminski/rhodecode/issues",
90 "http://bitbucket.org/marcinkuzminski/rhodecode/issues",
79 _static=True)
91 _static=True)
80 rmap.connect('rst_help',
92 rmap.connect('rst_help',
81 "http://docutils.sourceforge.net/docs/user/rst/quickref.html",
93 "http://docutils.sourceforge.net/docs/user/rst/quickref.html",
82 _static=True)
94 _static=True)
83 rmap.connect('rhodecode_official', "http://rhodecode.org", _static=True)
95 rmap.connect('rhodecode_official', "http://rhodecode.org", _static=True)
84
96
85 #ADMIN REPOSITORY REST ROUTES
97 #ADMIN REPOSITORY REST ROUTES
86 with rmap.submapper(path_prefix=ADMIN_PREFIX,
98 with rmap.submapper(path_prefix=ADMIN_PREFIX,
87 controller='admin/repos') as m:
99 controller='admin/repos') as m:
88 m.connect("repos", "/repos",
100 m.connect("repos", "/repos",
89 action="create", conditions=dict(method=["POST"]))
101 action="create", conditions=dict(method=["POST"]))
90 m.connect("repos", "/repos",
102 m.connect("repos", "/repos",
91 action="index", conditions=dict(method=["GET"]))
103 action="index", conditions=dict(method=["GET"]))
92 m.connect("formatted_repos", "/repos.{format}",
104 m.connect("formatted_repos", "/repos.{format}",
93 action="index",
105 action="index",
94 conditions=dict(method=["GET"]))
106 conditions=dict(method=["GET"]))
95 m.connect("new_repo", "/repos/new",
107 m.connect("new_repo", "/repos/new",
96 action="new", conditions=dict(method=["GET"]))
108 action="new", conditions=dict(method=["GET"]))
97 m.connect("formatted_new_repo", "/repos/new.{format}",
109 m.connect("formatted_new_repo", "/repos/new.{format}",
98 action="new", conditions=dict(method=["GET"]))
110 action="new", conditions=dict(method=["GET"]))
99 m.connect("/repos/{repo_name:.*?}",
111 m.connect("/repos/{repo_name:.*?}",
100 action="update", conditions=dict(method=["PUT"],
112 action="update", conditions=dict(method=["PUT"],
101 function=check_repo))
113 function=check_repo))
102 m.connect("/repos/{repo_name:.*?}",
114 m.connect("/repos/{repo_name:.*?}",
103 action="delete", conditions=dict(method=["DELETE"],
115 action="delete", conditions=dict(method=["DELETE"],
104 function=check_repo))
116 function=check_repo))
105 # no longer used:
117 # no longer used:
106 m.connect("edit_repo_admin", "/repos/{repo_name:.*?}/edit",
118 m.connect("edit_repo_admin", "/repos/{repo_name:.*?}/edit",
107 action="edit", conditions=dict(method=["GET"],
119 action="edit", conditions=dict(method=["GET"],
108 function=check_repo))
120 function=check_repo))
109 m.connect("formatted_edit_repo", "/repos/{repo_name:.*?}.{format}/edit",
121 m.connect("formatted_edit_repo", "/repos/{repo_name:.*?}.{format}/edit",
110 action="edit", conditions=dict(method=["GET"],
122 action="edit", conditions=dict(method=["GET"],
111 function=check_repo))
123 function=check_repo))
112 m.connect("repo", "/repos/{repo_name:.*?}",
124 m.connect("repo", "/repos/{repo_name:.*?}",
113 action="show", conditions=dict(method=["GET"],
125 action="show", conditions=dict(method=["GET"],
114 function=check_repo))
126 function=check_repo))
115 m.connect("formatted_repo", "/repos/{repo_name:.*?}.{format}",
127 m.connect("formatted_repo", "/repos/{repo_name:.*?}.{format}",
116 action="show", conditions=dict(method=["GET"],
128 action="show", conditions=dict(method=["GET"],
117 function=check_repo))
129 function=check_repo))
118 #ajax delete repo perm user
130 #ajax delete repo perm user
119 m.connect('delete_repo_user', "/repos_delete_user/{repo_name:.*?}",
131 m.connect('delete_repo_user', "/repos_delete_user/{repo_name:.*?}",
120 action="delete_perm_user",
132 action="delete_perm_user",
121 conditions=dict(method=["DELETE"], function=check_repo))
133 conditions=dict(method=["DELETE"], function=check_repo))
122
134
123 #ajax delete repo perm users_group
135 #ajax delete repo perm users_group
124 m.connect('delete_repo_users_group',
136 m.connect('delete_repo_users_group',
125 "/repos_delete_users_group/{repo_name:.*?}",
137 "/repos_delete_users_group/{repo_name:.*?}",
126 action="delete_perm_users_group",
138 action="delete_perm_users_group",
127 conditions=dict(method=["DELETE"], function=check_repo))
139 conditions=dict(method=["DELETE"], function=check_repo))
128
140
129 #settings actions
141 #settings actions
130 m.connect('repo_stats', "/repos_stats/{repo_name:.*?}",
142 m.connect('repo_stats', "/repos_stats/{repo_name:.*?}",
131 action="repo_stats", conditions=dict(method=["DELETE"],
143 action="repo_stats", conditions=dict(method=["DELETE"],
132 function=check_repo))
144 function=check_repo))
133 m.connect('repo_cache', "/repos_cache/{repo_name:.*?}",
145 m.connect('repo_cache', "/repos_cache/{repo_name:.*?}",
134 action="repo_cache", conditions=dict(method=["DELETE"],
146 action="repo_cache", conditions=dict(method=["DELETE"],
135 function=check_repo))
147 function=check_repo))
136 m.connect('repo_public_journal', "/repos_public_journal/{repo_name:.*?}",
148 m.connect('repo_public_journal', "/repos_public_journal/{repo_name:.*?}",
137 action="repo_public_journal", conditions=dict(method=["PUT"],
149 action="repo_public_journal", conditions=dict(method=["PUT"],
138 function=check_repo))
150 function=check_repo))
139 m.connect('repo_pull', "/repo_pull/{repo_name:.*?}",
151 m.connect('repo_pull', "/repo_pull/{repo_name:.*?}",
140 action="repo_pull", conditions=dict(method=["PUT"],
152 action="repo_pull", conditions=dict(method=["PUT"],
141 function=check_repo))
153 function=check_repo))
142 m.connect('repo_as_fork', "/repo_as_fork/{repo_name:.*?}",
154 m.connect('repo_as_fork', "/repo_as_fork/{repo_name:.*?}",
143 action="repo_as_fork", conditions=dict(method=["PUT"],
155 action="repo_as_fork", conditions=dict(method=["PUT"],
144 function=check_repo))
156 function=check_repo))
145 m.connect('repo_locking', "/repo_locking/{repo_name:.*?}",
157 m.connect('repo_locking', "/repo_locking/{repo_name:.*?}",
146 action="repo_locking", conditions=dict(method=["PUT"],
158 action="repo_locking", conditions=dict(method=["PUT"],
147 function=check_repo))
159 function=check_repo))
148 #repo fields
160 #repo fields
149 m.connect('create_repo_fields', "/repo_fields/{repo_name:.*?}/new",
161 m.connect('create_repo_fields', "/repo_fields/{repo_name:.*?}/new",
150 action="create_repo_field", conditions=dict(method=["PUT"],
162 action="create_repo_field", conditions=dict(method=["PUT"],
151 function=check_repo))
163 function=check_repo))
152
164
153 m.connect('delete_repo_fields', "/repo_fields/{repo_name:.*?}/{field_id}",
165 m.connect('delete_repo_fields', "/repo_fields/{repo_name:.*?}/{field_id}",
154 action="delete_repo_field", conditions=dict(method=["DELETE"],
166 action="delete_repo_field", conditions=dict(method=["DELETE"],
155 function=check_repo))
167 function=check_repo))
156
168
157 with rmap.submapper(path_prefix=ADMIN_PREFIX,
169 with rmap.submapper(path_prefix=ADMIN_PREFIX,
158 controller='admin/repos_groups') as m:
170 controller='admin/repos_groups') as m:
159 m.connect("repos_groups", "/repos_groups",
171 m.connect("repos_groups", "/repos_groups",
160 action="create", conditions=dict(method=["POST"]))
172 action="create", conditions=dict(method=["POST"]))
161 m.connect("repos_groups", "/repos_groups",
173 m.connect("repos_groups", "/repos_groups",
162 action="index", conditions=dict(method=["GET"]))
174 action="index", conditions=dict(method=["GET"]))
163 m.connect("formatted_repos_groups", "/repos_groups.{format}",
175 m.connect("formatted_repos_groups", "/repos_groups.{format}",
164 action="index", conditions=dict(method=["GET"]))
176 action="index", conditions=dict(method=["GET"]))
165 m.connect("new_repos_group", "/repos_groups/new",
177 m.connect("new_repos_group", "/repos_groups/new",
166 action="new", conditions=dict(method=["GET"]))
178 action="new", conditions=dict(method=["GET"]))
167 m.connect("formatted_new_repos_group", "/repos_groups/new.{format}",
179 m.connect("formatted_new_repos_group", "/repos_groups/new.{format}",
168 action="new", conditions=dict(method=["GET"]))
180 action="new", conditions=dict(method=["GET"]))
169 m.connect("update_repos_group", "/repos_groups/{group_name:.*?}",
181 m.connect("update_repos_group", "/repos_groups/{group_name:.*?}",
170 action="update", conditions=dict(method=["PUT"],
182 action="update", conditions=dict(method=["PUT"],
171 function=check_group))
183 function=check_group))
172 m.connect("delete_repos_group", "/repos_groups/{group_name:.*?}",
184 m.connect("delete_repos_group", "/repos_groups/{group_name:.*?}",
173 action="delete", conditions=dict(method=["DELETE"],
185 action="delete", conditions=dict(method=["DELETE"],
174 function=check_group))
186 function=check_group_skip_path))
175 m.connect("edit_repos_group", "/repos_groups/{group_name:.*?}/edit",
187 m.connect("edit_repos_group", "/repos_groups/{group_name:.*?}/edit",
176 action="edit", conditions=dict(method=["GET"],))
188 action="edit", conditions=dict(method=["GET"],
189 function=check_group))
177 m.connect("formatted_edit_repos_group",
190 m.connect("formatted_edit_repos_group",
178 "/repos_groups/{group_name:.*?}.{format}/edit",
191 "/repos_groups/{group_name:.*?}.{format}/edit",
179 action="edit", conditions=dict(method=["GET"],
192 action="edit", conditions=dict(method=["GET"],
180 function=check_group))
193 function=check_group))
181 m.connect("repos_group", "/repos_groups/{group_name:.*?}",
194 m.connect("repos_group", "/repos_groups/{group_name:.*?}",
182 action="show", conditions=dict(method=["GET"],
195 action="show", conditions=dict(method=["GET"],
183 function=check_group))
196 function=check_group))
184 m.connect("formatted_repos_group", "/repos_groups/{group_name:.*?}.{format}",
197 m.connect("formatted_repos_group", "/repos_groups/{group_name:.*?}.{format}",
185 action="show", conditions=dict(method=["GET"],
198 action="show", conditions=dict(method=["GET"],
186 function=check_group))
199 function=check_group))
187 # ajax delete repos group perm user
200 # ajax delete repos group perm user
188 m.connect('delete_repos_group_user_perm',
201 m.connect('delete_repos_group_user_perm',
189 "/delete_repos_group_user_perm/{group_name:.*?}",
202 "/delete_repos_group_user_perm/{group_name:.*?}",
190 action="delete_repos_group_user_perm",
203 action="delete_repos_group_user_perm",
191 conditions=dict(method=["DELETE"], function=check_group))
204 conditions=dict(method=["DELETE"], function=check_group))
192
205
193 # ajax delete repos group perm users_group
206 # ajax delete repos group perm users_group
194 m.connect('delete_repos_group_users_group_perm',
207 m.connect('delete_repos_group_users_group_perm',
195 "/delete_repos_group_users_group_perm/{group_name:.*?}",
208 "/delete_repos_group_users_group_perm/{group_name:.*?}",
196 action="delete_repos_group_users_group_perm",
209 action="delete_repos_group_users_group_perm",
197 conditions=dict(method=["DELETE"], function=check_group))
210 conditions=dict(method=["DELETE"], function=check_group))
198
211
199 #ADMIN USER REST ROUTES
212 #ADMIN USER REST ROUTES
200 with rmap.submapper(path_prefix=ADMIN_PREFIX,
213 with rmap.submapper(path_prefix=ADMIN_PREFIX,
201 controller='admin/users') as m:
214 controller='admin/users') as m:
202 m.connect("users", "/users",
215 m.connect("users", "/users",
203 action="create", conditions=dict(method=["POST"]))
216 action="create", conditions=dict(method=["POST"]))
204 m.connect("users", "/users",
217 m.connect("users", "/users",
205 action="index", conditions=dict(method=["GET"]))
218 action="index", conditions=dict(method=["GET"]))
206 m.connect("formatted_users", "/users.{format}",
219 m.connect("formatted_users", "/users.{format}",
207 action="index", conditions=dict(method=["GET"]))
220 action="index", conditions=dict(method=["GET"]))
208 m.connect("new_user", "/users/new",
221 m.connect("new_user", "/users/new",
209 action="new", conditions=dict(method=["GET"]))
222 action="new", conditions=dict(method=["GET"]))
210 m.connect("formatted_new_user", "/users/new.{format}",
223 m.connect("formatted_new_user", "/users/new.{format}",
211 action="new", conditions=dict(method=["GET"]))
224 action="new", conditions=dict(method=["GET"]))
212 m.connect("update_user", "/users/{id}",
225 m.connect("update_user", "/users/{id}",
213 action="update", conditions=dict(method=["PUT"]))
226 action="update", conditions=dict(method=["PUT"]))
214 m.connect("delete_user", "/users/{id}",
227 m.connect("delete_user", "/users/{id}",
215 action="delete", conditions=dict(method=["DELETE"]))
228 action="delete", conditions=dict(method=["DELETE"]))
216 m.connect("edit_user", "/users/{id}/edit",
229 m.connect("edit_user", "/users/{id}/edit",
217 action="edit", conditions=dict(method=["GET"]))
230 action="edit", conditions=dict(method=["GET"]))
218 m.connect("formatted_edit_user",
231 m.connect("formatted_edit_user",
219 "/users/{id}.{format}/edit",
232 "/users/{id}.{format}/edit",
220 action="edit", conditions=dict(method=["GET"]))
233 action="edit", conditions=dict(method=["GET"]))
221 m.connect("user", "/users/{id}",
234 m.connect("user", "/users/{id}",
222 action="show", conditions=dict(method=["GET"]))
235 action="show", conditions=dict(method=["GET"]))
223 m.connect("formatted_user", "/users/{id}.{format}",
236 m.connect("formatted_user", "/users/{id}.{format}",
224 action="show", conditions=dict(method=["GET"]))
237 action="show", conditions=dict(method=["GET"]))
225
238
226 #EXTRAS USER ROUTES
239 #EXTRAS USER ROUTES
227 m.connect("user_perm", "/users_perm/{id}",
240 m.connect("user_perm", "/users_perm/{id}",
228 action="update_perm", conditions=dict(method=["PUT"]))
241 action="update_perm", conditions=dict(method=["PUT"]))
229 m.connect("user_emails", "/users_emails/{id}",
242 m.connect("user_emails", "/users_emails/{id}",
230 action="add_email", conditions=dict(method=["PUT"]))
243 action="add_email", conditions=dict(method=["PUT"]))
231 m.connect("user_emails_delete", "/users_emails/{id}",
244 m.connect("user_emails_delete", "/users_emails/{id}",
232 action="delete_email", conditions=dict(method=["DELETE"]))
245 action="delete_email", conditions=dict(method=["DELETE"]))
233 m.connect("user_ips", "/users_ips/{id}",
246 m.connect("user_ips", "/users_ips/{id}",
234 action="add_ip", conditions=dict(method=["PUT"]))
247 action="add_ip", conditions=dict(method=["PUT"]))
235 m.connect("user_ips_delete", "/users_ips/{id}",
248 m.connect("user_ips_delete", "/users_ips/{id}",
236 action="delete_ip", conditions=dict(method=["DELETE"]))
249 action="delete_ip", conditions=dict(method=["DELETE"]))
237
250
238 #ADMIN USER GROUPS REST ROUTES
251 #ADMIN USER GROUPS REST ROUTES
239 with rmap.submapper(path_prefix=ADMIN_PREFIX,
252 with rmap.submapper(path_prefix=ADMIN_PREFIX,
240 controller='admin/users_groups') as m:
253 controller='admin/users_groups') as m:
241 m.connect("users_groups", "/users_groups",
254 m.connect("users_groups", "/users_groups",
242 action="create", conditions=dict(method=["POST"]))
255 action="create", conditions=dict(method=["POST"]))
243 m.connect("users_groups", "/users_groups",
256 m.connect("users_groups", "/users_groups",
244 action="index", conditions=dict(method=["GET"]))
257 action="index", conditions=dict(method=["GET"]))
245 m.connect("formatted_users_groups", "/users_groups.{format}",
258 m.connect("formatted_users_groups", "/users_groups.{format}",
246 action="index", conditions=dict(method=["GET"]))
259 action="index", conditions=dict(method=["GET"]))
247 m.connect("new_users_group", "/users_groups/new",
260 m.connect("new_users_group", "/users_groups/new",
248 action="new", conditions=dict(method=["GET"]))
261 action="new", conditions=dict(method=["GET"]))
249 m.connect("formatted_new_users_group", "/users_groups/new.{format}",
262 m.connect("formatted_new_users_group", "/users_groups/new.{format}",
250 action="new", conditions=dict(method=["GET"]))
263 action="new", conditions=dict(method=["GET"]))
251 m.connect("update_users_group", "/users_groups/{id}",
264 m.connect("update_users_group", "/users_groups/{id}",
252 action="update", conditions=dict(method=["PUT"]))
265 action="update", conditions=dict(method=["PUT"]))
253 m.connect("delete_users_group", "/users_groups/{id}",
266 m.connect("delete_users_group", "/users_groups/{id}",
254 action="delete", conditions=dict(method=["DELETE"]))
267 action="delete", conditions=dict(method=["DELETE"]))
255 m.connect("edit_users_group", "/users_groups/{id}/edit",
268 m.connect("edit_users_group", "/users_groups/{id}/edit",
256 action="edit", conditions=dict(method=["GET"]))
269 action="edit", conditions=dict(method=["GET"]))
257 m.connect("formatted_edit_users_group",
270 m.connect("formatted_edit_users_group",
258 "/users_groups/{id}.{format}/edit",
271 "/users_groups/{id}.{format}/edit",
259 action="edit", conditions=dict(method=["GET"]))
272 action="edit", conditions=dict(method=["GET"]))
260 m.connect("users_group", "/users_groups/{id}",
273 m.connect("users_group", "/users_groups/{id}",
261 action="show", conditions=dict(method=["GET"]))
274 action="show", conditions=dict(method=["GET"]))
262 m.connect("formatted_users_group", "/users_groups/{id}.{format}",
275 m.connect("formatted_users_group", "/users_groups/{id}.{format}",
263 action="show", conditions=dict(method=["GET"]))
276 action="show", conditions=dict(method=["GET"]))
264
277
265 #EXTRAS USER ROUTES
278 #EXTRAS USER ROUTES
266 m.connect("users_group_perm", "/users_groups_perm/{id}",
279 m.connect("users_group_perm", "/users_groups_perm/{id}",
267 action="update_perm", conditions=dict(method=["PUT"]))
280 action="update_perm", conditions=dict(method=["PUT"]))
268
281
269 #ADMIN GROUP REST ROUTES
282 #ADMIN GROUP REST ROUTES
270 rmap.resource('group', 'groups',
283 rmap.resource('group', 'groups',
271 controller='admin/groups', path_prefix=ADMIN_PREFIX)
284 controller='admin/groups', path_prefix=ADMIN_PREFIX)
272
285
273 #ADMIN PERMISSIONS REST ROUTES
286 #ADMIN PERMISSIONS REST ROUTES
274 rmap.resource('permission', 'permissions',
287 rmap.resource('permission', 'permissions',
275 controller='admin/permissions', path_prefix=ADMIN_PREFIX)
288 controller='admin/permissions', path_prefix=ADMIN_PREFIX)
276
289
277 #ADMIN DEFAULTS REST ROUTES
290 #ADMIN DEFAULTS REST ROUTES
278 rmap.resource('default', 'defaults',
291 rmap.resource('default', 'defaults',
279 controller='admin/defaults', path_prefix=ADMIN_PREFIX)
292 controller='admin/defaults', path_prefix=ADMIN_PREFIX)
280
293
281 ##ADMIN LDAP SETTINGS
294 ##ADMIN LDAP SETTINGS
282 rmap.connect('ldap_settings', '%s/ldap' % ADMIN_PREFIX,
295 rmap.connect('ldap_settings', '%s/ldap' % ADMIN_PREFIX,
283 controller='admin/ldap_settings', action='ldap_settings',
296 controller='admin/ldap_settings', action='ldap_settings',
284 conditions=dict(method=["POST"]))
297 conditions=dict(method=["POST"]))
285
298
286 rmap.connect('ldap_home', '%s/ldap' % ADMIN_PREFIX,
299 rmap.connect('ldap_home', '%s/ldap' % ADMIN_PREFIX,
287 controller='admin/ldap_settings')
300 controller='admin/ldap_settings')
288
301
289 #ADMIN SETTINGS REST ROUTES
302 #ADMIN SETTINGS REST ROUTES
290 with rmap.submapper(path_prefix=ADMIN_PREFIX,
303 with rmap.submapper(path_prefix=ADMIN_PREFIX,
291 controller='admin/settings') as m:
304 controller='admin/settings') as m:
292 m.connect("admin_settings", "/settings",
305 m.connect("admin_settings", "/settings",
293 action="create", conditions=dict(method=["POST"]))
306 action="create", conditions=dict(method=["POST"]))
294 m.connect("admin_settings", "/settings",
307 m.connect("admin_settings", "/settings",
295 action="index", conditions=dict(method=["GET"]))
308 action="index", conditions=dict(method=["GET"]))
296 m.connect("formatted_admin_settings", "/settings.{format}",
309 m.connect("formatted_admin_settings", "/settings.{format}",
297 action="index", conditions=dict(method=["GET"]))
310 action="index", conditions=dict(method=["GET"]))
298 m.connect("admin_new_setting", "/settings/new",
311 m.connect("admin_new_setting", "/settings/new",
299 action="new", conditions=dict(method=["GET"]))
312 action="new", conditions=dict(method=["GET"]))
300 m.connect("formatted_admin_new_setting", "/settings/new.{format}",
313 m.connect("formatted_admin_new_setting", "/settings/new.{format}",
301 action="new", conditions=dict(method=["GET"]))
314 action="new", conditions=dict(method=["GET"]))
302 m.connect("/settings/{setting_id}",
315 m.connect("/settings/{setting_id}",
303 action="update", conditions=dict(method=["PUT"]))
316 action="update", conditions=dict(method=["PUT"]))
304 m.connect("/settings/{setting_id}",
317 m.connect("/settings/{setting_id}",
305 action="delete", conditions=dict(method=["DELETE"]))
318 action="delete", conditions=dict(method=["DELETE"]))
306 m.connect("admin_edit_setting", "/settings/{setting_id}/edit",
319 m.connect("admin_edit_setting", "/settings/{setting_id}/edit",
307 action="edit", conditions=dict(method=["GET"]))
320 action="edit", conditions=dict(method=["GET"]))
308 m.connect("formatted_admin_edit_setting",
321 m.connect("formatted_admin_edit_setting",
309 "/settings/{setting_id}.{format}/edit",
322 "/settings/{setting_id}.{format}/edit",
310 action="edit", conditions=dict(method=["GET"]))
323 action="edit", conditions=dict(method=["GET"]))
311 m.connect("admin_setting", "/settings/{setting_id}",
324 m.connect("admin_setting", "/settings/{setting_id}",
312 action="show", conditions=dict(method=["GET"]))
325 action="show", conditions=dict(method=["GET"]))
313 m.connect("formatted_admin_setting", "/settings/{setting_id}.{format}",
326 m.connect("formatted_admin_setting", "/settings/{setting_id}.{format}",
314 action="show", conditions=dict(method=["GET"]))
327 action="show", conditions=dict(method=["GET"]))
315 m.connect("admin_settings_my_account", "/my_account",
328 m.connect("admin_settings_my_account", "/my_account",
316 action="my_account", conditions=dict(method=["GET"]))
329 action="my_account", conditions=dict(method=["GET"]))
317 m.connect("admin_settings_my_account_update", "/my_account_update",
330 m.connect("admin_settings_my_account_update", "/my_account_update",
318 action="my_account_update", conditions=dict(method=["PUT"]))
331 action="my_account_update", conditions=dict(method=["PUT"]))
319 m.connect("admin_settings_create_repository", "/create_repository",
332 m.connect("admin_settings_create_repository", "/create_repository",
320 action="create_repository", conditions=dict(method=["GET"]))
333 action="create_repository", conditions=dict(method=["GET"]))
321 m.connect("admin_settings_my_repos", "/my_account/repos",
334 m.connect("admin_settings_my_repos", "/my_account/repos",
322 action="my_account_my_repos", conditions=dict(method=["GET"]))
335 action="my_account_my_repos", conditions=dict(method=["GET"]))
323 m.connect("admin_settings_my_pullrequests", "/my_account/pull_requests",
336 m.connect("admin_settings_my_pullrequests", "/my_account/pull_requests",
324 action="my_account_my_pullrequests", conditions=dict(method=["GET"]))
337 action="my_account_my_pullrequests", conditions=dict(method=["GET"]))
325
338
326 #NOTIFICATION REST ROUTES
339 #NOTIFICATION REST ROUTES
327 with rmap.submapper(path_prefix=ADMIN_PREFIX,
340 with rmap.submapper(path_prefix=ADMIN_PREFIX,
328 controller='admin/notifications') as m:
341 controller='admin/notifications') as m:
329 m.connect("notifications", "/notifications",
342 m.connect("notifications", "/notifications",
330 action="create", conditions=dict(method=["POST"]))
343 action="create", conditions=dict(method=["POST"]))
331 m.connect("notifications", "/notifications",
344 m.connect("notifications", "/notifications",
332 action="index", conditions=dict(method=["GET"]))
345 action="index", conditions=dict(method=["GET"]))
333 m.connect("notifications_mark_all_read", "/notifications/mark_all_read",
346 m.connect("notifications_mark_all_read", "/notifications/mark_all_read",
334 action="mark_all_read", conditions=dict(method=["GET"]))
347 action="mark_all_read", conditions=dict(method=["GET"]))
335 m.connect("formatted_notifications", "/notifications.{format}",
348 m.connect("formatted_notifications", "/notifications.{format}",
336 action="index", conditions=dict(method=["GET"]))
349 action="index", conditions=dict(method=["GET"]))
337 m.connect("new_notification", "/notifications/new",
350 m.connect("new_notification", "/notifications/new",
338 action="new", conditions=dict(method=["GET"]))
351 action="new", conditions=dict(method=["GET"]))
339 m.connect("formatted_new_notification", "/notifications/new.{format}",
352 m.connect("formatted_new_notification", "/notifications/new.{format}",
340 action="new", conditions=dict(method=["GET"]))
353 action="new", conditions=dict(method=["GET"]))
341 m.connect("/notification/{notification_id}",
354 m.connect("/notification/{notification_id}",
342 action="update", conditions=dict(method=["PUT"]))
355 action="update", conditions=dict(method=["PUT"]))
343 m.connect("/notification/{notification_id}",
356 m.connect("/notification/{notification_id}",
344 action="delete", conditions=dict(method=["DELETE"]))
357 action="delete", conditions=dict(method=["DELETE"]))
345 m.connect("edit_notification", "/notification/{notification_id}/edit",
358 m.connect("edit_notification", "/notification/{notification_id}/edit",
346 action="edit", conditions=dict(method=["GET"]))
359 action="edit", conditions=dict(method=["GET"]))
347 m.connect("formatted_edit_notification",
360 m.connect("formatted_edit_notification",
348 "/notification/{notification_id}.{format}/edit",
361 "/notification/{notification_id}.{format}/edit",
349 action="edit", conditions=dict(method=["GET"]))
362 action="edit", conditions=dict(method=["GET"]))
350 m.connect("notification", "/notification/{notification_id}",
363 m.connect("notification", "/notification/{notification_id}",
351 action="show", conditions=dict(method=["GET"]))
364 action="show", conditions=dict(method=["GET"]))
352 m.connect("formatted_notification", "/notifications/{notification_id}.{format}",
365 m.connect("formatted_notification", "/notifications/{notification_id}.{format}",
353 action="show", conditions=dict(method=["GET"]))
366 action="show", conditions=dict(method=["GET"]))
354
367
355 #ADMIN MAIN PAGES
368 #ADMIN MAIN PAGES
356 with rmap.submapper(path_prefix=ADMIN_PREFIX,
369 with rmap.submapper(path_prefix=ADMIN_PREFIX,
357 controller='admin/admin') as m:
370 controller='admin/admin') as m:
358 m.connect('admin_home', '', action='index')
371 m.connect('admin_home', '', action='index')
359 m.connect('admin_add_repo', '/add_repo/{new_repo:[a-z0-9\. _-]*}',
372 m.connect('admin_add_repo', '/add_repo/{new_repo:[a-z0-9\. _-]*}',
360 action='add_repo')
373 action='add_repo')
361
374
362 #==========================================================================
375 #==========================================================================
363 # API V2
376 # API V2
364 #==========================================================================
377 #==========================================================================
365 with rmap.submapper(path_prefix=ADMIN_PREFIX,
378 with rmap.submapper(path_prefix=ADMIN_PREFIX,
366 controller='api/api') as m:
379 controller='api/api') as m:
367 m.connect('api', '/api')
380 m.connect('api', '/api')
368
381
369 #USER JOURNAL
382 #USER JOURNAL
370 rmap.connect('journal', '%s/journal' % ADMIN_PREFIX,
383 rmap.connect('journal', '%s/journal' % ADMIN_PREFIX,
371 controller='journal', action='index')
384 controller='journal', action='index')
372 rmap.connect('journal_rss', '%s/journal/rss' % ADMIN_PREFIX,
385 rmap.connect('journal_rss', '%s/journal/rss' % ADMIN_PREFIX,
373 controller='journal', action='journal_rss')
386 controller='journal', action='journal_rss')
374 rmap.connect('journal_atom', '%s/journal/atom' % ADMIN_PREFIX,
387 rmap.connect('journal_atom', '%s/journal/atom' % ADMIN_PREFIX,
375 controller='journal', action='journal_atom')
388 controller='journal', action='journal_atom')
376
389
377 rmap.connect('public_journal', '%s/public_journal' % ADMIN_PREFIX,
390 rmap.connect('public_journal', '%s/public_journal' % ADMIN_PREFIX,
378 controller='journal', action="public_journal")
391 controller='journal', action="public_journal")
379
392
380 rmap.connect('public_journal_rss', '%s/public_journal/rss' % ADMIN_PREFIX,
393 rmap.connect('public_journal_rss', '%s/public_journal/rss' % ADMIN_PREFIX,
381 controller='journal', action="public_journal_rss")
394 controller='journal', action="public_journal_rss")
382
395
383 rmap.connect('public_journal_rss_old', '%s/public_journal_rss' % ADMIN_PREFIX,
396 rmap.connect('public_journal_rss_old', '%s/public_journal_rss' % ADMIN_PREFIX,
384 controller='journal', action="public_journal_rss")
397 controller='journal', action="public_journal_rss")
385
398
386 rmap.connect('public_journal_atom',
399 rmap.connect('public_journal_atom',
387 '%s/public_journal/atom' % ADMIN_PREFIX, controller='journal',
400 '%s/public_journal/atom' % ADMIN_PREFIX, controller='journal',
388 action="public_journal_atom")
401 action="public_journal_atom")
389
402
390 rmap.connect('public_journal_atom_old',
403 rmap.connect('public_journal_atom_old',
391 '%s/public_journal_atom' % ADMIN_PREFIX, controller='journal',
404 '%s/public_journal_atom' % ADMIN_PREFIX, controller='journal',
392 action="public_journal_atom")
405 action="public_journal_atom")
393
406
394 rmap.connect('toggle_following', '%s/toggle_following' % ADMIN_PREFIX,
407 rmap.connect('toggle_following', '%s/toggle_following' % ADMIN_PREFIX,
395 controller='journal', action='toggle_following',
408 controller='journal', action='toggle_following',
396 conditions=dict(method=["POST"]))
409 conditions=dict(method=["POST"]))
397
410
398 #SEARCH
411 #SEARCH
399 rmap.connect('search', '%s/search' % ADMIN_PREFIX, controller='search',)
412 rmap.connect('search', '%s/search' % ADMIN_PREFIX, controller='search',)
400 rmap.connect('search_repo_admin', '%s/search/{repo_name:.*}' % ADMIN_PREFIX,
413 rmap.connect('search_repo_admin', '%s/search/{repo_name:.*}' % ADMIN_PREFIX,
401 controller='search',
414 controller='search',
402 conditions=dict(function=check_repo))
415 conditions=dict(function=check_repo))
403 rmap.connect('search_repo', '/{repo_name:.*?}/search',
416 rmap.connect('search_repo', '/{repo_name:.*?}/search',
404 controller='search',
417 controller='search',
405 conditions=dict(function=check_repo),
418 conditions=dict(function=check_repo),
406 )
419 )
407
420
408 #LOGIN/LOGOUT/REGISTER/SIGN IN
421 #LOGIN/LOGOUT/REGISTER/SIGN IN
409 rmap.connect('login_home', '%s/login' % ADMIN_PREFIX, controller='login')
422 rmap.connect('login_home', '%s/login' % ADMIN_PREFIX, controller='login')
410 rmap.connect('logout_home', '%s/logout' % ADMIN_PREFIX, controller='login',
423 rmap.connect('logout_home', '%s/logout' % ADMIN_PREFIX, controller='login',
411 action='logout')
424 action='logout')
412
425
413 rmap.connect('register', '%s/register' % ADMIN_PREFIX, controller='login',
426 rmap.connect('register', '%s/register' % ADMIN_PREFIX, controller='login',
414 action='register')
427 action='register')
415
428
416 rmap.connect('reset_password', '%s/password_reset' % ADMIN_PREFIX,
429 rmap.connect('reset_password', '%s/password_reset' % ADMIN_PREFIX,
417 controller='login', action='password_reset')
430 controller='login', action='password_reset')
418
431
419 rmap.connect('reset_password_confirmation',
432 rmap.connect('reset_password_confirmation',
420 '%s/password_reset_confirmation' % ADMIN_PREFIX,
433 '%s/password_reset_confirmation' % ADMIN_PREFIX,
421 controller='login', action='password_reset_confirmation')
434 controller='login', action='password_reset_confirmation')
422
435
423 #FEEDS
436 #FEEDS
424 rmap.connect('rss_feed_home', '/{repo_name:.*?}/feed/rss',
437 rmap.connect('rss_feed_home', '/{repo_name:.*?}/feed/rss',
425 controller='feed', action='rss',
438 controller='feed', action='rss',
426 conditions=dict(function=check_repo))
439 conditions=dict(function=check_repo))
427
440
428 rmap.connect('atom_feed_home', '/{repo_name:.*?}/feed/atom',
441 rmap.connect('atom_feed_home', '/{repo_name:.*?}/feed/atom',
429 controller='feed', action='atom',
442 controller='feed', action='atom',
430 conditions=dict(function=check_repo))
443 conditions=dict(function=check_repo))
431
444
432 #==========================================================================
445 #==========================================================================
433 # REPOSITORY ROUTES
446 # REPOSITORY ROUTES
434 #==========================================================================
447 #==========================================================================
435 rmap.connect('summary_home', '/{repo_name:.*?}',
448 rmap.connect('summary_home', '/{repo_name:.*?}',
436 controller='summary',
449 controller='summary',
437 conditions=dict(function=check_repo))
450 conditions=dict(function=check_repo))
438
451
439 rmap.connect('repo_size', '/{repo_name:.*?}/repo_size',
452 rmap.connect('repo_size', '/{repo_name:.*?}/repo_size',
440 controller='summary', action='repo_size',
453 controller='summary', action='repo_size',
441 conditions=dict(function=check_repo))
454 conditions=dict(function=check_repo))
442
455
443 rmap.connect('repos_group_home', '/{group_name:.*}',
456 rmap.connect('repos_group_home', '/{group_name:.*}',
444 controller='admin/repos_groups', action="show_by_name",
457 controller='admin/repos_groups', action="show_by_name",
445 conditions=dict(function=check_group))
458 conditions=dict(function=check_group))
446
459
447 rmap.connect('changeset_home', '/{repo_name:.*?}/changeset/{revision}',
460 rmap.connect('changeset_home', '/{repo_name:.*?}/changeset/{revision}',
448 controller='changeset', revision='tip',
461 controller='changeset', revision='tip',
449 conditions=dict(function=check_repo))
462 conditions=dict(function=check_repo))
450
463
451 rmap.connect("edit_repo", "/{repo_name:.*?}/edit",
464 rmap.connect("edit_repo", "/{repo_name:.*?}/edit",
452 controller='admin/repos', action="edit",
465 controller='admin/repos', action="edit",
453 conditions=dict(method=["GET"], function=check_repo)
466 conditions=dict(method=["GET"], function=check_repo)
454 )
467 )
455
468
456 #still working url for backward compat.
469 #still working url for backward compat.
457 rmap.connect('raw_changeset_home_depraced',
470 rmap.connect('raw_changeset_home_depraced',
458 '/{repo_name:.*?}/raw-changeset/{revision}',
471 '/{repo_name:.*?}/raw-changeset/{revision}',
459 controller='changeset', action='changeset_raw',
472 controller='changeset', action='changeset_raw',
460 revision='tip', conditions=dict(function=check_repo))
473 revision='tip', conditions=dict(function=check_repo))
461
474
462 ## new URLs
475 ## new URLs
463 rmap.connect('changeset_raw_home',
476 rmap.connect('changeset_raw_home',
464 '/{repo_name:.*?}/changeset-diff/{revision}',
477 '/{repo_name:.*?}/changeset-diff/{revision}',
465 controller='changeset', action='changeset_raw',
478 controller='changeset', action='changeset_raw',
466 revision='tip', conditions=dict(function=check_repo))
479 revision='tip', conditions=dict(function=check_repo))
467
480
468 rmap.connect('changeset_patch_home',
481 rmap.connect('changeset_patch_home',
469 '/{repo_name:.*?}/changeset-patch/{revision}',
482 '/{repo_name:.*?}/changeset-patch/{revision}',
470 controller='changeset', action='changeset_patch',
483 controller='changeset', action='changeset_patch',
471 revision='tip', conditions=dict(function=check_repo))
484 revision='tip', conditions=dict(function=check_repo))
472
485
473 rmap.connect('changeset_download_home',
486 rmap.connect('changeset_download_home',
474 '/{repo_name:.*?}/changeset-download/{revision}',
487 '/{repo_name:.*?}/changeset-download/{revision}',
475 controller='changeset', action='changeset_download',
488 controller='changeset', action='changeset_download',
476 revision='tip', conditions=dict(function=check_repo))
489 revision='tip', conditions=dict(function=check_repo))
477
490
478 rmap.connect('changeset_comment',
491 rmap.connect('changeset_comment',
479 '/{repo_name:.*?}/changeset/{revision}/comment',
492 '/{repo_name:.*?}/changeset/{revision}/comment',
480 controller='changeset', revision='tip', action='comment',
493 controller='changeset', revision='tip', action='comment',
481 conditions=dict(function=check_repo))
494 conditions=dict(function=check_repo))
482
495
483 rmap.connect('changeset_comment_delete',
496 rmap.connect('changeset_comment_delete',
484 '/{repo_name:.*?}/changeset/comment/{comment_id}/delete',
497 '/{repo_name:.*?}/changeset/comment/{comment_id}/delete',
485 controller='changeset', action='delete_comment',
498 controller='changeset', action='delete_comment',
486 conditions=dict(function=check_repo, method=["DELETE"]))
499 conditions=dict(function=check_repo, method=["DELETE"]))
487
500
488 rmap.connect('changeset_info', '/changeset_info/{repo_name:.*?}/{revision}',
501 rmap.connect('changeset_info', '/changeset_info/{repo_name:.*?}/{revision}',
489 controller='changeset', action='changeset_info')
502 controller='changeset', action='changeset_info')
490
503
491 rmap.connect('compare_url',
504 rmap.connect('compare_url',
492 '/{repo_name:.*?}/compare/{org_ref_type}@{org_ref:.*?}...{other_ref_type}@{other_ref:.*?}',
505 '/{repo_name:.*?}/compare/{org_ref_type}@{org_ref:.*?}...{other_ref_type}@{other_ref:.*?}',
493 controller='compare', action='index',
506 controller='compare', action='index',
494 conditions=dict(function=check_repo),
507 conditions=dict(function=check_repo),
495 requirements=dict(
508 requirements=dict(
496 org_ref_type='(branch|book|tag|rev|__other_ref_type__)',
509 org_ref_type='(branch|book|tag|rev|__other_ref_type__)',
497 other_ref_type='(branch|book|tag|rev|__org_ref_type__)')
510 other_ref_type='(branch|book|tag|rev|__org_ref_type__)')
498 )
511 )
499
512
500 rmap.connect('pullrequest_home',
513 rmap.connect('pullrequest_home',
501 '/{repo_name:.*?}/pull-request/new', controller='pullrequests',
514 '/{repo_name:.*?}/pull-request/new', controller='pullrequests',
502 action='index', conditions=dict(function=check_repo,
515 action='index', conditions=dict(function=check_repo,
503 method=["GET"]))
516 method=["GET"]))
504
517
505 rmap.connect('pullrequest',
518 rmap.connect('pullrequest',
506 '/{repo_name:.*?}/pull-request/new', controller='pullrequests',
519 '/{repo_name:.*?}/pull-request/new', controller='pullrequests',
507 action='create', conditions=dict(function=check_repo,
520 action='create', conditions=dict(function=check_repo,
508 method=["POST"]))
521 method=["POST"]))
509
522
510 rmap.connect('pullrequest_show',
523 rmap.connect('pullrequest_show',
511 '/{repo_name:.*?}/pull-request/{pull_request_id}',
524 '/{repo_name:.*?}/pull-request/{pull_request_id}',
512 controller='pullrequests',
525 controller='pullrequests',
513 action='show', conditions=dict(function=check_repo,
526 action='show', conditions=dict(function=check_repo,
514 method=["GET"]))
527 method=["GET"]))
515 rmap.connect('pullrequest_update',
528 rmap.connect('pullrequest_update',
516 '/{repo_name:.*?}/pull-request/{pull_request_id}',
529 '/{repo_name:.*?}/pull-request/{pull_request_id}',
517 controller='pullrequests',
530 controller='pullrequests',
518 action='update', conditions=dict(function=check_repo,
531 action='update', conditions=dict(function=check_repo,
519 method=["PUT"]))
532 method=["PUT"]))
520 rmap.connect('pullrequest_delete',
533 rmap.connect('pullrequest_delete',
521 '/{repo_name:.*?}/pull-request/{pull_request_id}',
534 '/{repo_name:.*?}/pull-request/{pull_request_id}',
522 controller='pullrequests',
535 controller='pullrequests',
523 action='delete', conditions=dict(function=check_repo,
536 action='delete', conditions=dict(function=check_repo,
524 method=["DELETE"]))
537 method=["DELETE"]))
525
538
526 rmap.connect('pullrequest_show_all',
539 rmap.connect('pullrequest_show_all',
527 '/{repo_name:.*?}/pull-request',
540 '/{repo_name:.*?}/pull-request',
528 controller='pullrequests',
541 controller='pullrequests',
529 action='show_all', conditions=dict(function=check_repo,
542 action='show_all', conditions=dict(function=check_repo,
530 method=["GET"]))
543 method=["GET"]))
531
544
532 rmap.connect('pullrequest_comment',
545 rmap.connect('pullrequest_comment',
533 '/{repo_name:.*?}/pull-request-comment/{pull_request_id}',
546 '/{repo_name:.*?}/pull-request-comment/{pull_request_id}',
534 controller='pullrequests',
547 controller='pullrequests',
535 action='comment', conditions=dict(function=check_repo,
548 action='comment', conditions=dict(function=check_repo,
536 method=["POST"]))
549 method=["POST"]))
537
550
538 rmap.connect('pullrequest_comment_delete',
551 rmap.connect('pullrequest_comment_delete',
539 '/{repo_name:.*?}/pull-request-comment/{comment_id}/delete',
552 '/{repo_name:.*?}/pull-request-comment/{comment_id}/delete',
540 controller='pullrequests', action='delete_comment',
553 controller='pullrequests', action='delete_comment',
541 conditions=dict(function=check_repo, method=["DELETE"]))
554 conditions=dict(function=check_repo, method=["DELETE"]))
542
555
543 rmap.connect('summary_home_summary', '/{repo_name:.*?}/summary',
556 rmap.connect('summary_home_summary', '/{repo_name:.*?}/summary',
544 controller='summary', conditions=dict(function=check_repo))
557 controller='summary', conditions=dict(function=check_repo))
545
558
546 rmap.connect('shortlog_home', '/{repo_name:.*?}/shortlog',
559 rmap.connect('shortlog_home', '/{repo_name:.*?}/shortlog',
547 controller='shortlog', conditions=dict(function=check_repo))
560 controller='shortlog', conditions=dict(function=check_repo))
548
561
549 rmap.connect('shortlog_file_home', '/{repo_name:.*?}/shortlog/{revision}/{f_path:.*}',
562 rmap.connect('shortlog_file_home', '/{repo_name:.*?}/shortlog/{revision}/{f_path:.*}',
550 controller='shortlog', f_path=None,
563 controller='shortlog', f_path=None,
551 conditions=dict(function=check_repo))
564 conditions=dict(function=check_repo))
552
565
553 rmap.connect('branches_home', '/{repo_name:.*?}/branches',
566 rmap.connect('branches_home', '/{repo_name:.*?}/branches',
554 controller='branches', conditions=dict(function=check_repo))
567 controller='branches', conditions=dict(function=check_repo))
555
568
556 rmap.connect('tags_home', '/{repo_name:.*?}/tags',
569 rmap.connect('tags_home', '/{repo_name:.*?}/tags',
557 controller='tags', conditions=dict(function=check_repo))
570 controller='tags', conditions=dict(function=check_repo))
558
571
559 rmap.connect('bookmarks_home', '/{repo_name:.*?}/bookmarks',
572 rmap.connect('bookmarks_home', '/{repo_name:.*?}/bookmarks',
560 controller='bookmarks', conditions=dict(function=check_repo))
573 controller='bookmarks', conditions=dict(function=check_repo))
561
574
562 rmap.connect('changelog_home', '/{repo_name:.*?}/changelog',
575 rmap.connect('changelog_home', '/{repo_name:.*?}/changelog',
563 controller='changelog', conditions=dict(function=check_repo))
576 controller='changelog', conditions=dict(function=check_repo))
564
577
565 rmap.connect('changelog_details', '/{repo_name:.*?}/changelog_details/{cs}',
578 rmap.connect('changelog_details', '/{repo_name:.*?}/changelog_details/{cs}',
566 controller='changelog', action='changelog_details',
579 controller='changelog', action='changelog_details',
567 conditions=dict(function=check_repo))
580 conditions=dict(function=check_repo))
568
581
569 rmap.connect('files_home', '/{repo_name:.*?}/files/{revision}/{f_path:.*}',
582 rmap.connect('files_home', '/{repo_name:.*?}/files/{revision}/{f_path:.*}',
570 controller='files', revision='tip', f_path='',
583 controller='files', revision='tip', f_path='',
571 conditions=dict(function=check_repo))
584 conditions=dict(function=check_repo))
572
585
573 rmap.connect('files_history_home',
586 rmap.connect('files_history_home',
574 '/{repo_name:.*?}/history/{revision}/{f_path:.*}',
587 '/{repo_name:.*?}/history/{revision}/{f_path:.*}',
575 controller='files', action='history', revision='tip', f_path='',
588 controller='files', action='history', revision='tip', f_path='',
576 conditions=dict(function=check_repo))
589 conditions=dict(function=check_repo))
577
590
578 rmap.connect('files_diff_home', '/{repo_name:.*?}/diff/{f_path:.*}',
591 rmap.connect('files_diff_home', '/{repo_name:.*?}/diff/{f_path:.*}',
579 controller='files', action='diff', revision='tip', f_path='',
592 controller='files', action='diff', revision='tip', f_path='',
580 conditions=dict(function=check_repo))
593 conditions=dict(function=check_repo))
581
594
582 rmap.connect('files_rawfile_home',
595 rmap.connect('files_rawfile_home',
583 '/{repo_name:.*?}/rawfile/{revision}/{f_path:.*}',
596 '/{repo_name:.*?}/rawfile/{revision}/{f_path:.*}',
584 controller='files', action='rawfile', revision='tip',
597 controller='files', action='rawfile', revision='tip',
585 f_path='', conditions=dict(function=check_repo))
598 f_path='', conditions=dict(function=check_repo))
586
599
587 rmap.connect('files_raw_home',
600 rmap.connect('files_raw_home',
588 '/{repo_name:.*?}/raw/{revision}/{f_path:.*}',
601 '/{repo_name:.*?}/raw/{revision}/{f_path:.*}',
589 controller='files', action='raw', revision='tip', f_path='',
602 controller='files', action='raw', revision='tip', f_path='',
590 conditions=dict(function=check_repo))
603 conditions=dict(function=check_repo))
591
604
592 rmap.connect('files_annotate_home',
605 rmap.connect('files_annotate_home',
593 '/{repo_name:.*?}/annotate/{revision}/{f_path:.*}',
606 '/{repo_name:.*?}/annotate/{revision}/{f_path:.*}',
594 controller='files', action='index', revision='tip',
607 controller='files', action='index', revision='tip',
595 f_path='', annotate=True, conditions=dict(function=check_repo))
608 f_path='', annotate=True, conditions=dict(function=check_repo))
596
609
597 rmap.connect('files_edit_home',
610 rmap.connect('files_edit_home',
598 '/{repo_name:.*?}/edit/{revision}/{f_path:.*}',
611 '/{repo_name:.*?}/edit/{revision}/{f_path:.*}',
599 controller='files', action='edit', revision='tip',
612 controller='files', action='edit', revision='tip',
600 f_path='', conditions=dict(function=check_repo))
613 f_path='', conditions=dict(function=check_repo))
601
614
602 rmap.connect('files_add_home',
615 rmap.connect('files_add_home',
603 '/{repo_name:.*?}/add/{revision}/{f_path:.*}',
616 '/{repo_name:.*?}/add/{revision}/{f_path:.*}',
604 controller='files', action='add', revision='tip',
617 controller='files', action='add', revision='tip',
605 f_path='', conditions=dict(function=check_repo))
618 f_path='', conditions=dict(function=check_repo))
606
619
607 rmap.connect('files_archive_home', '/{repo_name:.*?}/archive/{fname}',
620 rmap.connect('files_archive_home', '/{repo_name:.*?}/archive/{fname}',
608 controller='files', action='archivefile',
621 controller='files', action='archivefile',
609 conditions=dict(function=check_repo))
622 conditions=dict(function=check_repo))
610
623
611 rmap.connect('files_nodelist_home',
624 rmap.connect('files_nodelist_home',
612 '/{repo_name:.*?}/nodelist/{revision}/{f_path:.*}',
625 '/{repo_name:.*?}/nodelist/{revision}/{f_path:.*}',
613 controller='files', action='nodelist',
626 controller='files', action='nodelist',
614 conditions=dict(function=check_repo))
627 conditions=dict(function=check_repo))
615
628
616 rmap.connect('repo_settings_delete', '/{repo_name:.*?}/settings',
629 rmap.connect('repo_settings_delete', '/{repo_name:.*?}/settings',
617 controller='settings', action="delete",
630 controller='settings', action="delete",
618 conditions=dict(method=["DELETE"], function=check_repo))
631 conditions=dict(method=["DELETE"], function=check_repo))
619
632
620 rmap.connect('repo_settings_update', '/{repo_name:.*?}/settings',
633 rmap.connect('repo_settings_update', '/{repo_name:.*?}/settings',
621 controller='settings', action="update",
634 controller='settings', action="update",
622 conditions=dict(method=["PUT"], function=check_repo))
635 conditions=dict(method=["PUT"], function=check_repo))
623
636
624 rmap.connect('repo_settings_home', '/{repo_name:.*?}/settings',
637 rmap.connect('repo_settings_home', '/{repo_name:.*?}/settings',
625 controller='settings', action='index',
638 controller='settings', action='index',
626 conditions=dict(function=check_repo))
639 conditions=dict(function=check_repo))
627
640
628 rmap.connect('toggle_locking', "/{repo_name:.*?}/locking_toggle",
641 rmap.connect('toggle_locking', "/{repo_name:.*?}/locking_toggle",
629 controller='settings', action="toggle_locking",
642 controller='settings', action="toggle_locking",
630 conditions=dict(method=["GET"], function=check_repo))
643 conditions=dict(method=["GET"], function=check_repo))
631
644
632 rmap.connect('repo_fork_create_home', '/{repo_name:.*?}/fork',
645 rmap.connect('repo_fork_create_home', '/{repo_name:.*?}/fork',
633 controller='forks', action='fork_create',
646 controller='forks', action='fork_create',
634 conditions=dict(function=check_repo, method=["POST"]))
647 conditions=dict(function=check_repo, method=["POST"]))
635
648
636 rmap.connect('repo_fork_home', '/{repo_name:.*?}/fork',
649 rmap.connect('repo_fork_home', '/{repo_name:.*?}/fork',
637 controller='forks', action='fork',
650 controller='forks', action='fork',
638 conditions=dict(function=check_repo))
651 conditions=dict(function=check_repo))
639
652
640 rmap.connect('repo_forks_home', '/{repo_name:.*?}/forks',
653 rmap.connect('repo_forks_home', '/{repo_name:.*?}/forks',
641 controller='forks', action='forks',
654 controller='forks', action='forks',
642 conditions=dict(function=check_repo))
655 conditions=dict(function=check_repo))
643
656
644 rmap.connect('repo_followers_home', '/{repo_name:.*?}/followers',
657 rmap.connect('repo_followers_home', '/{repo_name:.*?}/followers',
645 controller='followers', action='followers',
658 controller='followers', action='followers',
646 conditions=dict(function=check_repo))
659 conditions=dict(function=check_repo))
647
660
648 return rmap
661 return rmap
@@ -1,398 +1,392 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.controllers.admin.repos_groups
3 rhodecode.controllers.admin.repos_groups
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5
5
6 Repository groups controller for RhodeCode
6 Repository groups controller for RhodeCode
7
7
8 :created_on: Mar 23, 2010
8 :created_on: Mar 23, 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 logging
26 import logging
27 import traceback
27 import traceback
28 import formencode
28 import formencode
29
29
30 from formencode import htmlfill
30 from formencode import htmlfill
31
31
32 from pylons import request, tmpl_context as c, url
32 from pylons import request, tmpl_context as c, url
33 from pylons.controllers.util import abort, redirect
33 from pylons.controllers.util import abort, redirect
34 from pylons.i18n.translation import _
34 from pylons.i18n.translation import _
35
35
36 from sqlalchemy.exc import IntegrityError
36 from sqlalchemy.exc import IntegrityError
37
37
38 import rhodecode
38 import rhodecode
39 from rhodecode.lib import helpers as h
39 from rhodecode.lib import helpers as h
40 from rhodecode.lib.ext_json import json
40 from rhodecode.lib.ext_json import json
41 from rhodecode.lib.auth import LoginRequired, HasPermissionAnyDecorator,\
41 from rhodecode.lib.auth import LoginRequired, HasPermissionAnyDecorator,\
42 HasReposGroupPermissionAnyDecorator, HasReposGroupPermissionAll,\
42 HasReposGroupPermissionAnyDecorator, HasReposGroupPermissionAll,\
43 HasPermissionAll
43 HasPermissionAll
44 from rhodecode.lib.base import BaseController, render
44 from rhodecode.lib.base import BaseController, render
45 from rhodecode.model.db import RepoGroup, Repository
45 from rhodecode.model.db import RepoGroup, Repository
46 from rhodecode.model.repos_group import ReposGroupModel
46 from rhodecode.model.repos_group import ReposGroupModel
47 from rhodecode.model.forms import ReposGroupForm
47 from rhodecode.model.forms import ReposGroupForm
48 from rhodecode.model.meta import Session
48 from rhodecode.model.meta import Session
49 from rhodecode.model.repo import RepoModel
49 from rhodecode.model.repo import RepoModel
50 from webob.exc import HTTPInternalServerError, HTTPNotFound
50 from webob.exc import HTTPInternalServerError, HTTPNotFound
51 from rhodecode.lib.utils2 import str2bool, safe_int
51 from rhodecode.lib.utils2 import str2bool, safe_int
52 from sqlalchemy.sql.expression import func
52 from sqlalchemy.sql.expression import func
53 from rhodecode.model.scm import GroupList
53 from rhodecode.model.scm import GroupList
54
54
55 log = logging.getLogger(__name__)
55 log = logging.getLogger(__name__)
56
56
57
57
58 class ReposGroupsController(BaseController):
58 class ReposGroupsController(BaseController):
59 """REST Controller styled on the Atom Publishing Protocol"""
59 """REST Controller styled on the Atom Publishing Protocol"""
60 # To properly map this controller, ensure your config/routing.py
60 # To properly map this controller, ensure your config/routing.py
61 # file has a resource setup:
61 # file has a resource setup:
62 # map.resource('repos_group', 'repos_groups')
62 # map.resource('repos_group', 'repos_groups')
63
63
64 @LoginRequired()
64 @LoginRequired()
65 def __before__(self):
65 def __before__(self):
66 super(ReposGroupsController, self).__before__()
66 super(ReposGroupsController, self).__before__()
67
67
68 def __load_defaults(self, allow_empty_group=False, exclude_group_ids=[]):
68 def __load_defaults(self, allow_empty_group=False, exclude_group_ids=[]):
69 if HasPermissionAll('hg.admin')('group edit'):
69 if HasPermissionAll('hg.admin')('group edit'):
70 #we're global admin, we're ok and we can create TOP level groups
70 #we're global admin, we're ok and we can create TOP level groups
71 allow_empty_group = True
71 allow_empty_group = True
72
72
73 #override the choices for this form, we need to filter choices
73 #override the choices for this form, we need to filter choices
74 #and display only those we have ADMIN right
74 #and display only those we have ADMIN right
75 groups_with_admin_rights = GroupList(RepoGroup.query().all(),
75 groups_with_admin_rights = GroupList(RepoGroup.query().all(),
76 perm_set=['group.admin'])
76 perm_set=['group.admin'])
77 c.repo_groups = RepoGroup.groups_choices(groups=groups_with_admin_rights,
77 c.repo_groups = RepoGroup.groups_choices(groups=groups_with_admin_rights,
78 show_empty_group=allow_empty_group)
78 show_empty_group=allow_empty_group)
79 # exclude filtered ids
79 # exclude filtered ids
80 c.repo_groups = filter(lambda x: x[0] not in exclude_group_ids,
80 c.repo_groups = filter(lambda x: x[0] not in exclude_group_ids,
81 c.repo_groups)
81 c.repo_groups)
82 c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups)
82 c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups)
83 repo_model = RepoModel()
83 repo_model = RepoModel()
84 c.users_array = repo_model.get_users_js()
84 c.users_array = repo_model.get_users_js()
85 c.users_groups_array = repo_model.get_users_groups_js()
85 c.users_groups_array = repo_model.get_users_groups_js()
86
86
87 def __load_data(self, group_id):
87 def __load_data(self, group_id):
88 """
88 """
89 Load defaults settings for edit, and update
89 Load defaults settings for edit, and update
90
90
91 :param group_id:
91 :param group_id:
92 """
92 """
93 repo_group = RepoGroup.get_or_404(group_id)
93 repo_group = RepoGroup.get_or_404(group_id)
94 data = repo_group.get_dict()
94 data = repo_group.get_dict()
95 data['group_name'] = repo_group.name
95 data['group_name'] = repo_group.name
96
96
97 # fill repository users
97 # fill repository users
98 for p in repo_group.repo_group_to_perm:
98 for p in repo_group.repo_group_to_perm:
99 data.update({'u_perm_%s' % p.user.username:
99 data.update({'u_perm_%s' % p.user.username:
100 p.permission.permission_name})
100 p.permission.permission_name})
101
101
102 # fill repository groups
102 # fill repository groups
103 for p in repo_group.users_group_to_perm:
103 for p in repo_group.users_group_to_perm:
104 data.update({'g_perm_%s' % p.users_group.users_group_name:
104 data.update({'g_perm_%s' % p.users_group.users_group_name:
105 p.permission.permission_name})
105 p.permission.permission_name})
106
106
107 return data
107 return data
108
108
109 def _revoke_perms_on_yourself(self, form_result):
109 def _revoke_perms_on_yourself(self, form_result):
110 _up = filter(lambda u: c.rhodecode_user.username == u[0],
110 _up = filter(lambda u: c.rhodecode_user.username == u[0],
111 form_result['perms_updates'])
111 form_result['perms_updates'])
112 _new = filter(lambda u: c.rhodecode_user.username == u[0],
112 _new = filter(lambda u: c.rhodecode_user.username == u[0],
113 form_result['perms_new'])
113 form_result['perms_new'])
114 if _new and _new[0][1] != 'group.admin' or _up and _up[0][1] != 'group.admin':
114 if _new and _new[0][1] != 'group.admin' or _up and _up[0][1] != 'group.admin':
115 return True
115 return True
116 return False
116 return False
117
117
118 def index(self, format='html'):
118 def index(self, format='html'):
119 """GET /repos_groups: All items in the collection"""
119 """GET /repos_groups: All items in the collection"""
120 # url('repos_groups')
120 # url('repos_groups')
121 group_iter = GroupList(RepoGroup.query().all(), perm_set=['group.admin'])
121 group_iter = GroupList(RepoGroup.query().all(), perm_set=['group.admin'])
122 sk = lambda g: g.parents[0].group_name if g.parents else g.group_name
122 sk = lambda g: g.parents[0].group_name if g.parents else g.group_name
123 c.groups = sorted(group_iter, key=sk)
123 c.groups = sorted(group_iter, key=sk)
124 return render('admin/repos_groups/repos_groups_show.html')
124 return render('admin/repos_groups/repos_groups_show.html')
125
125
126 def create(self):
126 def create(self):
127 """POST /repos_groups: Create a new item"""
127 """POST /repos_groups: Create a new item"""
128 # url('repos_groups')
128 # url('repos_groups')
129
129
130 self.__load_defaults()
130 self.__load_defaults()
131
131
132 # permissions for can create group based on parent_id are checked
132 # permissions for can create group based on parent_id are checked
133 # here in the Form
133 # here in the Form
134 repos_group_form = ReposGroupForm(available_groups=
134 repos_group_form = ReposGroupForm(available_groups=
135 map(lambda k: unicode(k[0]), c.repo_groups))()
135 map(lambda k: unicode(k[0]), c.repo_groups))()
136 try:
136 try:
137 form_result = repos_group_form.to_python(dict(request.POST))
137 form_result = repos_group_form.to_python(dict(request.POST))
138 ReposGroupModel().create(
138 ReposGroupModel().create(
139 group_name=form_result['group_name'],
139 group_name=form_result['group_name'],
140 group_description=form_result['group_description'],
140 group_description=form_result['group_description'],
141 parent=form_result['group_parent_id'],
141 parent=form_result['group_parent_id'],
142 owner=self.rhodecode_user.user_id
142 owner=self.rhodecode_user.user_id
143 )
143 )
144 Session().commit()
144 Session().commit()
145 h.flash(_('created repos group %s') \
145 h.flash(_('created repos group %s') \
146 % form_result['group_name'], category='success')
146 % form_result['group_name'], category='success')
147 #TODO: in futureaction_logger(, '', '', '', self.sa)
147 #TODO: in futureaction_logger(, '', '', '', self.sa)
148 except formencode.Invalid, errors:
148 except formencode.Invalid, errors:
149 return htmlfill.render(
149 return htmlfill.render(
150 render('admin/repos_groups/repos_groups_add.html'),
150 render('admin/repos_groups/repos_groups_add.html'),
151 defaults=errors.value,
151 defaults=errors.value,
152 errors=errors.error_dict or {},
152 errors=errors.error_dict or {},
153 prefix_error=False,
153 prefix_error=False,
154 encoding="UTF-8")
154 encoding="UTF-8")
155 except Exception:
155 except Exception:
156 log.error(traceback.format_exc())
156 log.error(traceback.format_exc())
157 h.flash(_('error occurred during creation of repos group %s') \
157 h.flash(_('error occurred during creation of repos group %s') \
158 % request.POST.get('group_name'), category='error')
158 % request.POST.get('group_name'), category='error')
159 parent_group_id = form_result['group_parent_id']
159 parent_group_id = form_result['group_parent_id']
160 #TODO: maybe we should get back to the main view, not the admin one
160 #TODO: maybe we should get back to the main view, not the admin one
161 return redirect(url('repos_groups', parent_group=parent_group_id))
161 return redirect(url('repos_groups', parent_group=parent_group_id))
162
162
163 def new(self, format='html'):
163 def new(self, format='html'):
164 """GET /repos_groups/new: Form to create a new item"""
164 """GET /repos_groups/new: Form to create a new item"""
165 # url('new_repos_group')
165 # url('new_repos_group')
166 if HasPermissionAll('hg.admin')('group create'):
166 if HasPermissionAll('hg.admin')('group create'):
167 #we're global admin, we're ok and we can create TOP level groups
167 #we're global admin, we're ok and we can create TOP level groups
168 pass
168 pass
169 else:
169 else:
170 # we pass in parent group into creation form, thus we know
170 # we pass in parent group into creation form, thus we know
171 # what would be the group, we can check perms here !
171 # what would be the group, we can check perms here !
172 group_id = safe_int(request.GET.get('parent_group'))
172 group_id = safe_int(request.GET.get('parent_group'))
173 group = RepoGroup.get(group_id) if group_id else None
173 group = RepoGroup.get(group_id) if group_id else None
174 group_name = group.group_name if group else None
174 group_name = group.group_name if group else None
175 if HasReposGroupPermissionAll('group.admin')(group_name, 'group create'):
175 if HasReposGroupPermissionAll('group.admin')(group_name, 'group create'):
176 pass
176 pass
177 else:
177 else:
178 return abort(403)
178 return abort(403)
179
179
180 self.__load_defaults()
180 self.__load_defaults()
181 return render('admin/repos_groups/repos_groups_add.html')
181 return render('admin/repos_groups/repos_groups_add.html')
182
182
183 @HasReposGroupPermissionAnyDecorator('group.admin')
183 @HasReposGroupPermissionAnyDecorator('group.admin')
184 def update(self, group_name):
184 def update(self, group_name):
185 """PUT /repos_groups/group_name: Update an existing item"""
185 """PUT /repos_groups/group_name: Update an existing item"""
186 # Forms posted to this method should contain a hidden field:
186 # Forms posted to this method should contain a hidden field:
187 # <input type="hidden" name="_method" value="PUT" />
187 # <input type="hidden" name="_method" value="PUT" />
188 # Or using helpers:
188 # Or using helpers:
189 # h.form(url('repos_group', group_name=GROUP_NAME),
189 # h.form(url('repos_group', group_name=GROUP_NAME),
190 # method='put')
190 # method='put')
191 # url('repos_group', group_name=GROUP_NAME)
191 # url('repos_group', group_name=GROUP_NAME)
192
192
193 c.repos_group = ReposGroupModel()._get_repos_group(group_name)
193 c.repos_group = ReposGroupModel()._get_repos_group(group_name)
194 if HasPermissionAll('hg.admin')('group edit'):
194 if HasPermissionAll('hg.admin')('group edit'):
195 #we're global admin, we're ok and we can create TOP level groups
195 #we're global admin, we're ok and we can create TOP level groups
196 allow_empty_group = True
196 allow_empty_group = True
197 elif not c.repos_group.parent_group:
197 elif not c.repos_group.parent_group:
198 allow_empty_group = True
198 allow_empty_group = True
199 else:
199 else:
200 allow_empty_group = False
200 allow_empty_group = False
201 self.__load_defaults(allow_empty_group=allow_empty_group,
201 self.__load_defaults(allow_empty_group=allow_empty_group,
202 exclude_group_ids=[c.repos_group.group_id])
202 exclude_group_ids=[c.repos_group.group_id])
203
203
204 repos_group_form = ReposGroupForm(
204 repos_group_form = ReposGroupForm(
205 edit=True,
205 edit=True,
206 old_data=c.repos_group.get_dict(),
206 old_data=c.repos_group.get_dict(),
207 available_groups=c.repo_groups_choices,
207 available_groups=c.repo_groups_choices,
208 can_create_in_root=allow_empty_group,
208 can_create_in_root=allow_empty_group,
209 )()
209 )()
210 try:
210 try:
211 form_result = repos_group_form.to_python(dict(request.POST))
211 form_result = repos_group_form.to_python(dict(request.POST))
212 if not c.rhodecode_user.is_admin:
212 if not c.rhodecode_user.is_admin:
213 if self._revoke_perms_on_yourself(form_result):
213 if self._revoke_perms_on_yourself(form_result):
214 msg = _('Cannot revoke permission for yourself as admin')
214 msg = _('Cannot revoke permission for yourself as admin')
215 h.flash(msg, category='warning')
215 h.flash(msg, category='warning')
216 raise Exception('revoke admin permission on self')
216 raise Exception('revoke admin permission on self')
217
217
218 new_gr = ReposGroupModel().update(group_name, form_result)
218 new_gr = ReposGroupModel().update(group_name, form_result)
219 Session().commit()
219 Session().commit()
220 h.flash(_('updated repos group %s') \
220 h.flash(_('updated repos group %s') \
221 % form_result['group_name'], category='success')
221 % form_result['group_name'], category='success')
222 # we now have new name !
222 # we now have new name !
223 group_name = new_gr.group_name
223 group_name = new_gr.group_name
224 #TODO: in future action_logger(, '', '', '', self.sa)
224 #TODO: in future action_logger(, '', '', '', self.sa)
225 except formencode.Invalid, errors:
225 except formencode.Invalid, errors:
226
226
227 return htmlfill.render(
227 return htmlfill.render(
228 render('admin/repos_groups/repos_groups_edit.html'),
228 render('admin/repos_groups/repos_groups_edit.html'),
229 defaults=errors.value,
229 defaults=errors.value,
230 errors=errors.error_dict or {},
230 errors=errors.error_dict or {},
231 prefix_error=False,
231 prefix_error=False,
232 encoding="UTF-8")
232 encoding="UTF-8")
233 except Exception:
233 except Exception:
234 log.error(traceback.format_exc())
234 log.error(traceback.format_exc())
235 h.flash(_('error occurred during update of repos group %s') \
235 h.flash(_('error occurred during update of repos group %s') \
236 % request.POST.get('group_name'), category='error')
236 % request.POST.get('group_name'), category='error')
237
237
238 return redirect(url('edit_repos_group', group_name=group_name))
238 return redirect(url('edit_repos_group', group_name=group_name))
239
239
240 @HasReposGroupPermissionAnyDecorator('group.admin')
240 @HasReposGroupPermissionAnyDecorator('group.admin')
241 def delete(self, group_name):
241 def delete(self, group_name):
242 """DELETE /repos_groups/group_name: Delete an existing item"""
242 """DELETE /repos_groups/group_name: Delete an existing item"""
243 # Forms posted to this method should contain a hidden field:
243 # Forms posted to this method should contain a hidden field:
244 # <input type="hidden" name="_method" value="DELETE" />
244 # <input type="hidden" name="_method" value="DELETE" />
245 # Or using helpers:
245 # Or using helpers:
246 # h.form(url('repos_group', group_name=GROUP_NAME),
246 # h.form(url('repos_group', group_name=GROUP_NAME),
247 # method='delete')
247 # method='delete')
248 # url('repos_group', group_name=GROUP_NAME)
248 # url('repos_group', group_name=GROUP_NAME)
249
249
250 gr = c.repos_group = ReposGroupModel()._get_repos_group(group_name)
250 gr = c.repos_group = ReposGroupModel()._get_repos_group(group_name)
251 repos = gr.repositories.all()
251 repos = gr.repositories.all()
252 if repos:
252 if repos:
253 h.flash(_('This group contains %s repositores and cannot be '
253 h.flash(_('This group contains %s repositores and cannot be '
254 'deleted') % len(repos),
254 'deleted') % len(repos), category='warning')
255 category='error')
255 return redirect(url('repos_groups'))
256
257 children = gr.children.all()
258 if children:
259 h.flash(_('This group contains %s subgroups and cannot be deleted'
260 % (len(children))), category='warning')
256 return redirect(url('repos_groups'))
261 return redirect(url('repos_groups'))
257
262
258 try:
263 try:
259 ReposGroupModel().delete(group_name)
264 ReposGroupModel().delete(group_name)
260 Session().commit()
265 Session().commit()
261 h.flash(_('removed repos group %s') % gr.group_name,
266 h.flash(_('removed repos group %s') % group_name,
262 category='success')
267 category='success')
263 #TODO: in future action_logger(, '', '', '', self.sa)
268 #TODO: in future action_logger(, '', '', '', self.sa)
264 except IntegrityError, e:
265 if str(e.message).find('groups_group_parent_id_fkey') != -1:
266 log.error(traceback.format_exc())
267 h.flash(_('Cannot delete this group it still contains '
268 'subgroups'),
269 category='warning')
270 else:
271 log.error(traceback.format_exc())
272 h.flash(_('error occurred during deletion of repos '
273 'group %s') % gr.group_name, category='error')
274
275 except Exception:
269 except Exception:
276 log.error(traceback.format_exc())
270 log.error(traceback.format_exc())
277 h.flash(_('error occurred during deletion of repos '
271 h.flash(_('error occurred during deletion of repos '
278 'group %s') % gr.group_name, category='error')
272 'group %s') % group_name, category='error')
279
273
280 return redirect(url('repos_groups'))
274 return redirect(url('repos_groups'))
281
275
282 @HasReposGroupPermissionAnyDecorator('group.admin')
276 @HasReposGroupPermissionAnyDecorator('group.admin')
283 def delete_repos_group_user_perm(self, group_name):
277 def delete_repos_group_user_perm(self, group_name):
284 """
278 """
285 DELETE an existing repository group permission user
279 DELETE an existing repository group permission user
286
280
287 :param group_name:
281 :param group_name:
288 """
282 """
289 try:
283 try:
290 if not c.rhodecode_user.is_admin:
284 if not c.rhodecode_user.is_admin:
291 if c.rhodecode_user.user_id == safe_int(request.POST['user_id']):
285 if c.rhodecode_user.user_id == safe_int(request.POST['user_id']):
292 msg = _('Cannot revoke permission for yourself as admin')
286 msg = _('Cannot revoke permission for yourself as admin')
293 h.flash(msg, category='warning')
287 h.flash(msg, category='warning')
294 raise Exception('revoke admin permission on self')
288 raise Exception('revoke admin permission on self')
295 recursive = str2bool(request.POST.get('recursive', False))
289 recursive = str2bool(request.POST.get('recursive', False))
296 ReposGroupModel().delete_permission(
290 ReposGroupModel().delete_permission(
297 repos_group=group_name, obj=request.POST['user_id'],
291 repos_group=group_name, obj=request.POST['user_id'],
298 obj_type='user', recursive=recursive
292 obj_type='user', recursive=recursive
299 )
293 )
300 Session().commit()
294 Session().commit()
301 except Exception:
295 except Exception:
302 log.error(traceback.format_exc())
296 log.error(traceback.format_exc())
303 h.flash(_('An error occurred during deletion of group user'),
297 h.flash(_('An error occurred during deletion of group user'),
304 category='error')
298 category='error')
305 raise HTTPInternalServerError()
299 raise HTTPInternalServerError()
306
300
307 @HasReposGroupPermissionAnyDecorator('group.admin')
301 @HasReposGroupPermissionAnyDecorator('group.admin')
308 def delete_repos_group_users_group_perm(self, group_name):
302 def delete_repos_group_users_group_perm(self, group_name):
309 """
303 """
310 DELETE an existing repository group permission user group
304 DELETE an existing repository group permission user group
311
305
312 :param group_name:
306 :param group_name:
313 """
307 """
314
308
315 try:
309 try:
316 recursive = str2bool(request.POST.get('recursive', False))
310 recursive = str2bool(request.POST.get('recursive', False))
317 ReposGroupModel().delete_permission(
311 ReposGroupModel().delete_permission(
318 repos_group=group_name, obj=request.POST['users_group_id'],
312 repos_group=group_name, obj=request.POST['users_group_id'],
319 obj_type='users_group', recursive=recursive
313 obj_type='users_group', recursive=recursive
320 )
314 )
321 Session().commit()
315 Session().commit()
322 except Exception:
316 except Exception:
323 log.error(traceback.format_exc())
317 log.error(traceback.format_exc())
324 h.flash(_('An error occurred during deletion of group'
318 h.flash(_('An error occurred during deletion of group'
325 ' user groups'),
319 ' user groups'),
326 category='error')
320 category='error')
327 raise HTTPInternalServerError()
321 raise HTTPInternalServerError()
328
322
329 def show_by_name(self, group_name):
323 def show_by_name(self, group_name):
330 """
324 """
331 This is a proxy that does a lookup group_name -> id, and shows
325 This is a proxy that does a lookup group_name -> id, and shows
332 the group by id view instead
326 the group by id view instead
333 """
327 """
334 group_name = group_name.rstrip('/')
328 group_name = group_name.rstrip('/')
335 id_ = RepoGroup.get_by_group_name(group_name)
329 id_ = RepoGroup.get_by_group_name(group_name)
336 if id_:
330 if id_:
337 return self.show(id_.group_id)
331 return self.show(id_.group_id)
338 raise HTTPNotFound
332 raise HTTPNotFound
339
333
340 @HasReposGroupPermissionAnyDecorator('group.read', 'group.write',
334 @HasReposGroupPermissionAnyDecorator('group.read', 'group.write',
341 'group.admin')
335 'group.admin')
342 def show(self, group_name, format='html'):
336 def show(self, group_name, format='html'):
343 """GET /repos_groups/group_name: Show a specific item"""
337 """GET /repos_groups/group_name: Show a specific item"""
344 # url('repos_group', group_name=GROUP_NAME)
338 # url('repos_group', group_name=GROUP_NAME)
345
339
346 c.group = c.repos_group = ReposGroupModel()._get_repos_group(group_name)
340 c.group = c.repos_group = ReposGroupModel()._get_repos_group(group_name)
347 c.group_repos = c.group.repositories.all()
341 c.group_repos = c.group.repositories.all()
348
342
349 #overwrite our cached list with current filter
343 #overwrite our cached list with current filter
350 gr_filter = c.group_repos
344 gr_filter = c.group_repos
351 c.repo_cnt = 0
345 c.repo_cnt = 0
352
346
353 groups = RepoGroup.query().order_by(RepoGroup.group_name)\
347 groups = RepoGroup.query().order_by(RepoGroup.group_name)\
354 .filter(RepoGroup.group_parent_id == c.group.group_id).all()
348 .filter(RepoGroup.group_parent_id == c.group.group_id).all()
355 c.groups = self.scm_model.get_repos_groups(groups)
349 c.groups = self.scm_model.get_repos_groups(groups)
356
350
357 if c.visual.lightweight_dashboard is False:
351 if c.visual.lightweight_dashboard is False:
358 c.repos_list = self.scm_model.get_repos(all_repos=gr_filter)
352 c.repos_list = self.scm_model.get_repos(all_repos=gr_filter)
359 ## lightweight version of dashboard
353 ## lightweight version of dashboard
360 else:
354 else:
361 c.repos_list = Repository.query()\
355 c.repos_list = Repository.query()\
362 .filter(Repository.group_id == c.group.group_id)\
356 .filter(Repository.group_id == c.group.group_id)\
363 .order_by(func.lower(Repository.repo_name))\
357 .order_by(func.lower(Repository.repo_name))\
364 .all()
358 .all()
365
359
366 repos_data = RepoModel().get_repos_as_dict(repos_list=c.repos_list,
360 repos_data = RepoModel().get_repos_as_dict(repos_list=c.repos_list,
367 admin=False)
361 admin=False)
368 #json used to render the grid
362 #json used to render the grid
369 c.data = json.dumps(repos_data)
363 c.data = json.dumps(repos_data)
370
364
371 return render('admin/repos_groups/repos_groups.html')
365 return render('admin/repos_groups/repos_groups.html')
372
366
373 @HasReposGroupPermissionAnyDecorator('group.admin')
367 @HasReposGroupPermissionAnyDecorator('group.admin')
374 def edit(self, group_name, format='html'):
368 def edit(self, group_name, format='html'):
375 """GET /repos_groups/group_name/edit: Form to edit an existing item"""
369 """GET /repos_groups/group_name/edit: Form to edit an existing item"""
376 # url('edit_repos_group', group_name=GROUP_NAME)
370 # url('edit_repos_group', group_name=GROUP_NAME)
377
371
378 c.repos_group = ReposGroupModel()._get_repos_group(group_name)
372 c.repos_group = ReposGroupModel()._get_repos_group(group_name)
379 #we can only allow moving empty group if it's already a top-level
373 #we can only allow moving empty group if it's already a top-level
380 #group, ie has no parents, or we're admin
374 #group, ie has no parents, or we're admin
381 if HasPermissionAll('hg.admin')('group edit'):
375 if HasPermissionAll('hg.admin')('group edit'):
382 #we're global admin, we're ok and we can create TOP level groups
376 #we're global admin, we're ok and we can create TOP level groups
383 allow_empty_group = True
377 allow_empty_group = True
384 elif not c.repos_group.parent_group:
378 elif not c.repos_group.parent_group:
385 allow_empty_group = True
379 allow_empty_group = True
386 else:
380 else:
387 allow_empty_group = False
381 allow_empty_group = False
388
382
389 self.__load_defaults(allow_empty_group=allow_empty_group,
383 self.__load_defaults(allow_empty_group=allow_empty_group,
390 exclude_group_ids=[c.repos_group.group_id])
384 exclude_group_ids=[c.repos_group.group_id])
391 defaults = self.__load_data(c.repos_group.group_id)
385 defaults = self.__load_data(c.repos_group.group_id)
392
386
393 return htmlfill.render(
387 return htmlfill.render(
394 render('admin/repos_groups/repos_groups_edit.html'),
388 render('admin/repos_groups/repos_groups_edit.html'),
395 defaults=defaults,
389 defaults=defaults,
396 encoding="UTF-8",
390 encoding="UTF-8",
397 force_defaults=False
391 force_defaults=False
398 )
392 )
@@ -1,801 +1,800 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.lib.utils
3 rhodecode.lib.utils
4 ~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~
5
5
6 Utilities library for RhodeCode
6 Utilities library for RhodeCode
7
7
8 :created_on: Apr 18, 2010
8 :created_on: Apr 18, 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 re
27 import re
28 import logging
28 import logging
29 import datetime
29 import datetime
30 import traceback
30 import traceback
31 import paste
31 import paste
32 import beaker
32 import beaker
33 import tarfile
33 import tarfile
34 import shutil
34 import shutil
35 import decorator
35 import decorator
36 import warnings
36 import warnings
37 from os.path import abspath
37 from os.path import abspath
38 from os.path import dirname as dn, join as jn
38 from os.path import dirname as dn, join as jn
39
39
40 from paste.script.command import Command, BadCommand
40 from paste.script.command import Command, BadCommand
41
41
42 from mercurial import ui, config
42 from mercurial import ui, config
43
43
44 from webhelpers.text import collapse, remove_formatting, strip_tags
44 from webhelpers.text import collapse, remove_formatting, strip_tags
45
45
46 from rhodecode.lib.vcs import get_backend
46 from rhodecode.lib.vcs import get_backend
47 from rhodecode.lib.vcs.backends.base import BaseChangeset
47 from rhodecode.lib.vcs.backends.base import BaseChangeset
48 from rhodecode.lib.vcs.utils.lazy import LazyProperty
48 from rhodecode.lib.vcs.utils.lazy import LazyProperty
49 from rhodecode.lib.vcs.utils.helpers import get_scm
49 from rhodecode.lib.vcs.utils.helpers import get_scm
50 from rhodecode.lib.vcs.exceptions import VCSError
50 from rhodecode.lib.vcs.exceptions import VCSError
51
51
52 from rhodecode.lib.caching_query import FromCache
52 from rhodecode.lib.caching_query import FromCache
53
53
54 from rhodecode.model import meta
54 from rhodecode.model import meta
55 from rhodecode.model.db import Repository, User, RhodeCodeUi, \
55 from rhodecode.model.db import Repository, User, RhodeCodeUi, \
56 UserLog, RepoGroup, RhodeCodeSetting, CacheInvalidation
56 UserLog, RepoGroup, RhodeCodeSetting, CacheInvalidation
57 from rhodecode.model.meta import Session
57 from rhodecode.model.meta import Session
58 from rhodecode.model.repos_group import ReposGroupModel
58 from rhodecode.model.repos_group import ReposGroupModel
59 from rhodecode.lib.utils2 import safe_str, safe_unicode
59 from rhodecode.lib.utils2 import safe_str, safe_unicode
60 from rhodecode.lib.vcs.utils.fakemod import create_module
60 from rhodecode.lib.vcs.utils.fakemod import create_module
61
61
62 log = logging.getLogger(__name__)
62 log = logging.getLogger(__name__)
63
63
64 REMOVED_REPO_PAT = re.compile(r'rm__\d{8}_\d{6}_\d{6}__.*')
64 REMOVED_REPO_PAT = re.compile(r'rm__\d{8}_\d{6}_\d{6}__.*')
65
65
66
66
67 def recursive_replace(str_, replace=' '):
67 def recursive_replace(str_, replace=' '):
68 """
68 """
69 Recursive replace of given sign to just one instance
69 Recursive replace of given sign to just one instance
70
70
71 :param str_: given string
71 :param str_: given string
72 :param replace: char to find and replace multiple instances
72 :param replace: char to find and replace multiple instances
73
73
74 Examples::
74 Examples::
75 >>> recursive_replace("Mighty---Mighty-Bo--sstones",'-')
75 >>> recursive_replace("Mighty---Mighty-Bo--sstones",'-')
76 'Mighty-Mighty-Bo-sstones'
76 'Mighty-Mighty-Bo-sstones'
77 """
77 """
78
78
79 if str_.find(replace * 2) == -1:
79 if str_.find(replace * 2) == -1:
80 return str_
80 return str_
81 else:
81 else:
82 str_ = str_.replace(replace * 2, replace)
82 str_ = str_.replace(replace * 2, replace)
83 return recursive_replace(str_, replace)
83 return recursive_replace(str_, replace)
84
84
85
85
86 def repo_name_slug(value):
86 def repo_name_slug(value):
87 """
87 """
88 Return slug of name of repository
88 Return slug of name of repository
89 This function is called on each creation/modification
89 This function is called on each creation/modification
90 of repository to prevent bad names in repo
90 of repository to prevent bad names in repo
91 """
91 """
92
92
93 slug = remove_formatting(value)
93 slug = remove_formatting(value)
94 slug = strip_tags(slug)
94 slug = strip_tags(slug)
95
95
96 for c in """`?=[]\;'"<>,/~!@#$%^&*()+{}|: """:
96 for c in """`?=[]\;'"<>,/~!@#$%^&*()+{}|: """:
97 slug = slug.replace(c, '-')
97 slug = slug.replace(c, '-')
98 slug = recursive_replace(slug, '-')
98 slug = recursive_replace(slug, '-')
99 slug = collapse(slug, '-')
99 slug = collapse(slug, '-')
100 return slug
100 return slug
101
101
102
102
103 def get_repo_slug(request):
103 def get_repo_slug(request):
104 _repo = request.environ['pylons.routes_dict'].get('repo_name')
104 _repo = request.environ['pylons.routes_dict'].get('repo_name')
105 if _repo:
105 if _repo:
106 _repo = _repo.rstrip('/')
106 _repo = _repo.rstrip('/')
107 return _repo
107 return _repo
108
108
109
109
110 def get_repos_group_slug(request):
110 def get_repos_group_slug(request):
111 _group = request.environ['pylons.routes_dict'].get('group_name')
111 _group = request.environ['pylons.routes_dict'].get('group_name')
112 if _group:
112 if _group:
113 _group = _group.rstrip('/')
113 _group = _group.rstrip('/')
114 return _group
114 return _group
115
115
116
116
117 def action_logger(user, action, repo, ipaddr='', sa=None, commit=False):
117 def action_logger(user, action, repo, ipaddr='', sa=None, commit=False):
118 """
118 """
119 Action logger for various actions made by users
119 Action logger for various actions made by users
120
120
121 :param user: user that made this action, can be a unique username string or
121 :param user: user that made this action, can be a unique username string or
122 object containing user_id attribute
122 object containing user_id attribute
123 :param action: action to log, should be on of predefined unique actions for
123 :param action: action to log, should be on of predefined unique actions for
124 easy translations
124 easy translations
125 :param repo: string name of repository or object containing repo_id,
125 :param repo: string name of repository or object containing repo_id,
126 that action was made on
126 that action was made on
127 :param ipaddr: optional ip address from what the action was made
127 :param ipaddr: optional ip address from what the action was made
128 :param sa: optional sqlalchemy session
128 :param sa: optional sqlalchemy session
129
129
130 """
130 """
131
131
132 if not sa:
132 if not sa:
133 sa = meta.Session()
133 sa = meta.Session()
134
134
135 try:
135 try:
136 if hasattr(user, 'user_id'):
136 if hasattr(user, 'user_id'):
137 user_obj = User.get(user.user_id)
137 user_obj = User.get(user.user_id)
138 elif isinstance(user, basestring):
138 elif isinstance(user, basestring):
139 user_obj = User.get_by_username(user)
139 user_obj = User.get_by_username(user)
140 else:
140 else:
141 raise Exception('You have to provide a user object or a username')
141 raise Exception('You have to provide a user object or a username')
142
142
143 if hasattr(repo, 'repo_id'):
143 if hasattr(repo, 'repo_id'):
144 repo_obj = Repository.get(repo.repo_id)
144 repo_obj = Repository.get(repo.repo_id)
145 repo_name = repo_obj.repo_name
145 repo_name = repo_obj.repo_name
146 elif isinstance(repo, basestring):
146 elif isinstance(repo, basestring):
147 repo_name = repo.lstrip('/')
147 repo_name = repo.lstrip('/')
148 repo_obj = Repository.get_by_repo_name(repo_name)
148 repo_obj = Repository.get_by_repo_name(repo_name)
149 else:
149 else:
150 repo_obj = None
150 repo_obj = None
151 repo_name = ''
151 repo_name = ''
152
152
153 user_log = UserLog()
153 user_log = UserLog()
154 user_log.user_id = user_obj.user_id
154 user_log.user_id = user_obj.user_id
155 user_log.username = user_obj.username
155 user_log.username = user_obj.username
156 user_log.action = safe_unicode(action)
156 user_log.action = safe_unicode(action)
157
157
158 user_log.repository = repo_obj
158 user_log.repository = repo_obj
159 user_log.repository_name = repo_name
159 user_log.repository_name = repo_name
160
160
161 user_log.action_date = datetime.datetime.now()
161 user_log.action_date = datetime.datetime.now()
162 user_log.user_ip = ipaddr
162 user_log.user_ip = ipaddr
163 sa.add(user_log)
163 sa.add(user_log)
164
164
165 log.info('Logging action %s on %s by %s' %
165 log.info('Logging action %s on %s by %s' %
166 (action, safe_unicode(repo), user_obj))
166 (action, safe_unicode(repo), user_obj))
167 if commit:
167 if commit:
168 sa.commit()
168 sa.commit()
169 except:
169 except:
170 log.error(traceback.format_exc())
170 log.error(traceback.format_exc())
171 raise
171 raise
172
172
173
173
174 def get_repos(path, recursive=False, skip_removed_repos=True):
174 def get_repos(path, recursive=False, skip_removed_repos=True):
175 """
175 """
176 Scans given path for repos and return (name,(type,path)) tuple
176 Scans given path for repos and return (name,(type,path)) tuple
177
177
178 :param path: path to scan for repositories
178 :param path: path to scan for repositories
179 :param recursive: recursive search and return names with subdirs in front
179 :param recursive: recursive search and return names with subdirs in front
180 """
180 """
181
181
182 # remove ending slash for better results
182 # remove ending slash for better results
183 path = path.rstrip(os.sep)
183 path = path.rstrip(os.sep)
184 log.debug('now scanning in %s location recursive:%s...' % (path, recursive))
184 log.debug('now scanning in %s location recursive:%s...' % (path, recursive))
185
185
186 def _get_repos(p):
186 def _get_repos(p):
187 if not os.access(p, os.W_OK):
187 if not os.access(p, os.W_OK):
188 return
188 return
189 for dirpath in os.listdir(p):
189 for dirpath in os.listdir(p):
190 if os.path.isfile(os.path.join(p, dirpath)):
190 if os.path.isfile(os.path.join(p, dirpath)):
191 continue
191 continue
192 cur_path = os.path.join(p, dirpath)
192 cur_path = os.path.join(p, dirpath)
193
193
194 # skip removed repos
194 # skip removed repos
195 if skip_removed_repos and REMOVED_REPO_PAT.match(dirpath):
195 if skip_removed_repos and REMOVED_REPO_PAT.match(dirpath):
196 continue
196 continue
197
197
198 #skip .<somethin> dirs
198 #skip .<somethin> dirs
199 if dirpath.startswith('.'):
199 if dirpath.startswith('.'):
200 continue
200 continue
201
201
202 try:
202 try:
203 scm_info = get_scm(cur_path)
203 scm_info = get_scm(cur_path)
204 yield scm_info[1].split(path, 1)[-1].lstrip(os.sep), scm_info
204 yield scm_info[1].split(path, 1)[-1].lstrip(os.sep), scm_info
205 except VCSError:
205 except VCSError:
206 if not recursive:
206 if not recursive:
207 continue
207 continue
208 #check if this dir containts other repos for recursive scan
208 #check if this dir containts other repos for recursive scan
209 rec_path = os.path.join(p, dirpath)
209 rec_path = os.path.join(p, dirpath)
210 if os.path.isdir(rec_path):
210 if os.path.isdir(rec_path):
211 for inner_scm in _get_repos(rec_path):
211 for inner_scm in _get_repos(rec_path):
212 yield inner_scm
212 yield inner_scm
213
213
214 return _get_repos(path)
214 return _get_repos(path)
215
215
216 #alias for backward compat
216 #alias for backward compat
217 get_filesystem_repos = get_repos
217 get_filesystem_repos = get_repos
218
218
219
219
220 def is_valid_repo(repo_name, base_path, scm=None):
220 def is_valid_repo(repo_name, base_path, scm=None):
221 """
221 """
222 Returns True if given path is a valid repository False otherwise.
222 Returns True if given path is a valid repository False otherwise.
223 If scm param is given also compare if given scm is the same as expected
223 If scm param is given also compare if given scm is the same as expected
224 from scm parameter
224 from scm parameter
225
225
226 :param repo_name:
226 :param repo_name:
227 :param base_path:
227 :param base_path:
228 :param scm:
228 :param scm:
229
229
230 :return True: if given path is a valid repository
230 :return True: if given path is a valid repository
231 """
231 """
232 full_path = os.path.join(safe_str(base_path), safe_str(repo_name))
232 full_path = os.path.join(safe_str(base_path), safe_str(repo_name))
233
233
234 try:
234 try:
235 scm_ = get_scm(full_path)
235 scm_ = get_scm(full_path)
236 if scm:
236 if scm:
237 return scm_[0] == scm
237 return scm_[0] == scm
238 return True
238 return True
239 except VCSError:
239 except VCSError:
240 return False
240 return False
241
241
242
242
243 def is_valid_repos_group(repos_group_name, base_path):
243 def is_valid_repos_group(repos_group_name, base_path, skip_path_check=False):
244 """
244 """
245 Returns True if given path is a repos group False otherwise
245 Returns True if given path is a repos group False otherwise
246
246
247 :param repo_name:
247 :param repo_name:
248 :param base_path:
248 :param base_path:
249 """
249 """
250 full_path = os.path.join(safe_str(base_path), safe_str(repos_group_name))
250 full_path = os.path.join(safe_str(base_path), safe_str(repos_group_name))
251
251
252 # check if it's not a repo
252 # check if it's not a repo
253 if is_valid_repo(repos_group_name, base_path):
253 if is_valid_repo(repos_group_name, base_path):
254 return False
254 return False
255
255
256 try:
256 try:
257 # we need to check bare git repos at higher level
257 # we need to check bare git repos at higher level
258 # since we might match branches/hooks/info/objects or possible
258 # since we might match branches/hooks/info/objects or possible
259 # other things inside bare git repo
259 # other things inside bare git repo
260 get_scm(os.path.dirname(full_path))
260 get_scm(os.path.dirname(full_path))
261 return False
261 return False
262 except VCSError:
262 except VCSError:
263 pass
263 pass
264
264
265 # check if it's a valid path
265 # check if it's a valid path
266 if os.path.isdir(full_path):
266 if skip_path_check or os.path.isdir(full_path):
267 return True
267 return True
268
268
269 return False
269 return False
270
270
271
271
272 def ask_ok(prompt, retries=4, complaint='Yes or no please!'):
272 def ask_ok(prompt, retries=4, complaint='Yes or no please!'):
273 while True:
273 while True:
274 ok = raw_input(prompt)
274 ok = raw_input(prompt)
275 if ok in ('y', 'ye', 'yes'):
275 if ok in ('y', 'ye', 'yes'):
276 return True
276 return True
277 if ok in ('n', 'no', 'nop', 'nope'):
277 if ok in ('n', 'no', 'nop', 'nope'):
278 return False
278 return False
279 retries = retries - 1
279 retries = retries - 1
280 if retries < 0:
280 if retries < 0:
281 raise IOError
281 raise IOError
282 print complaint
282 print complaint
283
283
284 #propagated from mercurial documentation
284 #propagated from mercurial documentation
285 ui_sections = ['alias', 'auth',
285 ui_sections = ['alias', 'auth',
286 'decode/encode', 'defaults',
286 'decode/encode', 'defaults',
287 'diff', 'email',
287 'diff', 'email',
288 'extensions', 'format',
288 'extensions', 'format',
289 'merge-patterns', 'merge-tools',
289 'merge-patterns', 'merge-tools',
290 'hooks', 'http_proxy',
290 'hooks', 'http_proxy',
291 'smtp', 'patch',
291 'smtp', 'patch',
292 'paths', 'profiling',
292 'paths', 'profiling',
293 'server', 'trusted',
293 'server', 'trusted',
294 'ui', 'web', ]
294 'ui', 'web', ]
295
295
296
296
297 def make_ui(read_from='file', path=None, checkpaths=True, clear_session=True):
297 def make_ui(read_from='file', path=None, checkpaths=True, clear_session=True):
298 """
298 """
299 A function that will read python rc files or database
299 A function that will read python rc files or database
300 and make an mercurial ui object from read options
300 and make an mercurial ui object from read options
301
301
302 :param path: path to mercurial config file
302 :param path: path to mercurial config file
303 :param checkpaths: check the path
303 :param checkpaths: check the path
304 :param read_from: read from 'file' or 'db'
304 :param read_from: read from 'file' or 'db'
305 """
305 """
306
306
307 baseui = ui.ui()
307 baseui = ui.ui()
308
308
309 # clean the baseui object
309 # clean the baseui object
310 baseui._ocfg = config.config()
310 baseui._ocfg = config.config()
311 baseui._ucfg = config.config()
311 baseui._ucfg = config.config()
312 baseui._tcfg = config.config()
312 baseui._tcfg = config.config()
313
313
314 if read_from == 'file':
314 if read_from == 'file':
315 if not os.path.isfile(path):
315 if not os.path.isfile(path):
316 log.debug('hgrc file is not present at %s, skipping...' % path)
316 log.debug('hgrc file is not present at %s, skipping...' % path)
317 return False
317 return False
318 log.debug('reading hgrc from %s' % path)
318 log.debug('reading hgrc from %s' % path)
319 cfg = config.config()
319 cfg = config.config()
320 cfg.read(path)
320 cfg.read(path)
321 for section in ui_sections:
321 for section in ui_sections:
322 for k, v in cfg.items(section):
322 for k, v in cfg.items(section):
323 log.debug('settings ui from file: [%s] %s=%s' % (section, k, v))
323 log.debug('settings ui from file: [%s] %s=%s' % (section, k, v))
324 baseui.setconfig(safe_str(section), safe_str(k), safe_str(v))
324 baseui.setconfig(safe_str(section), safe_str(k), safe_str(v))
325
325
326 elif read_from == 'db':
326 elif read_from == 'db':
327 sa = meta.Session()
327 sa = meta.Session()
328 ret = sa.query(RhodeCodeUi)\
328 ret = sa.query(RhodeCodeUi)\
329 .options(FromCache("sql_cache_short", "get_hg_ui_settings"))\
329 .options(FromCache("sql_cache_short", "get_hg_ui_settings"))\
330 .all()
330 .all()
331
331
332 hg_ui = ret
332 hg_ui = ret
333 for ui_ in hg_ui:
333 for ui_ in hg_ui:
334 if ui_.ui_active:
334 if ui_.ui_active:
335 log.debug('settings ui from db: [%s] %s=%s', ui_.ui_section,
335 log.debug('settings ui from db: [%s] %s=%s', ui_.ui_section,
336 ui_.ui_key, ui_.ui_value)
336 ui_.ui_key, ui_.ui_value)
337 baseui.setconfig(safe_str(ui_.ui_section), safe_str(ui_.ui_key),
337 baseui.setconfig(safe_str(ui_.ui_section), safe_str(ui_.ui_key),
338 safe_str(ui_.ui_value))
338 safe_str(ui_.ui_value))
339 if ui_.ui_key == 'push_ssl':
339 if ui_.ui_key == 'push_ssl':
340 # force set push_ssl requirement to False, rhodecode
340 # force set push_ssl requirement to False, rhodecode
341 # handles that
341 # handles that
342 baseui.setconfig(safe_str(ui_.ui_section), safe_str(ui_.ui_key),
342 baseui.setconfig(safe_str(ui_.ui_section), safe_str(ui_.ui_key),
343 False)
343 False)
344 if clear_session:
344 if clear_session:
345 meta.Session.remove()
345 meta.Session.remove()
346 return baseui
346 return baseui
347
347
348
348
349 def set_rhodecode_config(config):
349 def set_rhodecode_config(config):
350 """
350 """
351 Updates pylons config with new settings from database
351 Updates pylons config with new settings from database
352
352
353 :param config:
353 :param config:
354 """
354 """
355 hgsettings = RhodeCodeSetting.get_app_settings()
355 hgsettings = RhodeCodeSetting.get_app_settings()
356
356
357 for k, v in hgsettings.items():
357 for k, v in hgsettings.items():
358 config[k] = v
358 config[k] = v
359
359
360
360
361 def invalidate_cache(cache_key, *args):
361 def invalidate_cache(cache_key, *args):
362 """
362 """
363 Puts cache invalidation task into db for
363 Puts cache invalidation task into db for
364 further global cache invalidation
364 further global cache invalidation
365 """
365 """
366
366
367 from rhodecode.model.scm import ScmModel
367 from rhodecode.model.scm import ScmModel
368
368
369 if cache_key.startswith('get_repo_cached_'):
369 if cache_key.startswith('get_repo_cached_'):
370 name = cache_key.split('get_repo_cached_')[-1]
370 name = cache_key.split('get_repo_cached_')[-1]
371 ScmModel().mark_for_invalidation(name)
371 ScmModel().mark_for_invalidation(name)
372
372
373
373
374 def map_groups(path):
374 def map_groups(path):
375 """
375 """
376 Given a full path to a repository, create all nested groups that this
376 Given a full path to a repository, create all nested groups that this
377 repo is inside. This function creates parent-child relationships between
377 repo is inside. This function creates parent-child relationships between
378 groups and creates default perms for all new groups.
378 groups and creates default perms for all new groups.
379
379
380 :param paths: full path to repository
380 :param paths: full path to repository
381 """
381 """
382 sa = meta.Session()
382 sa = meta.Session()
383 groups = path.split(Repository.url_sep())
383 groups = path.split(Repository.url_sep())
384 parent = None
384 parent = None
385 group = None
385 group = None
386
386
387 # last element is repo in nested groups structure
387 # last element is repo in nested groups structure
388 groups = groups[:-1]
388 groups = groups[:-1]
389 rgm = ReposGroupModel(sa)
389 rgm = ReposGroupModel(sa)
390 for lvl, group_name in enumerate(groups):
390 for lvl, group_name in enumerate(groups):
391 group_name = '/'.join(groups[:lvl] + [group_name])
391 group_name = '/'.join(groups[:lvl] + [group_name])
392 group = RepoGroup.get_by_group_name(group_name)
392 group = RepoGroup.get_by_group_name(group_name)
393 desc = '%s group' % group_name
393 desc = '%s group' % group_name
394
394
395 # skip folders that are now removed repos
395 # skip folders that are now removed repos
396 if REMOVED_REPO_PAT.match(group_name):
396 if REMOVED_REPO_PAT.match(group_name):
397 break
397 break
398
398
399 if group is None:
399 if group is None:
400 log.debug('creating group level: %s group_name: %s' % (lvl,
400 log.debug('creating group level: %s group_name: %s' % (lvl,
401 group_name))
401 group_name))
402 group = RepoGroup(group_name, parent)
402 group = RepoGroup(group_name, parent)
403 group.group_description = desc
403 group.group_description = desc
404 sa.add(group)
404 sa.add(group)
405 rgm._create_default_perms(group)
405 rgm._create_default_perms(group)
406 sa.flush()
406 sa.flush()
407 parent = group
407 parent = group
408 return group
408 return group
409
409
410
410
411 def repo2db_mapper(initial_repo_list, remove_obsolete=False,
411 def repo2db_mapper(initial_repo_list, remove_obsolete=False,
412 install_git_hook=False):
412 install_git_hook=False):
413 """
413 """
414 maps all repos given in initial_repo_list, non existing repositories
414 maps all repos given in initial_repo_list, non existing repositories
415 are created, if remove_obsolete is True it also check for db entries
415 are created, if remove_obsolete is True it also check for db entries
416 that are not in initial_repo_list and removes them.
416 that are not in initial_repo_list and removes them.
417
417
418 :param initial_repo_list: list of repositories found by scanning methods
418 :param initial_repo_list: list of repositories found by scanning methods
419 :param remove_obsolete: check for obsolete entries in database
419 :param remove_obsolete: check for obsolete entries in database
420 :param install_git_hook: if this is True, also check and install githook
420 :param install_git_hook: if this is True, also check and install githook
421 for a repo if missing
421 for a repo if missing
422 """
422 """
423 from rhodecode.model.repo import RepoModel
423 from rhodecode.model.repo import RepoModel
424 from rhodecode.model.scm import ScmModel
424 from rhodecode.model.scm import ScmModel
425 sa = meta.Session()
425 sa = meta.Session()
426 rm = RepoModel()
426 rm = RepoModel()
427 user = sa.query(User).filter(User.admin == True).first()
427 user = sa.query(User).filter(User.admin == True).first()
428 if user is None:
428 if user is None:
429 raise Exception('Missing administrative account!')
429 raise Exception('Missing administrative account!')
430 added = []
430 added = []
431
431
432 # # clear cache keys
432 # # clear cache keys
433 # log.debug("Clearing cache keys now...")
433 # log.debug("Clearing cache keys now...")
434 # CacheInvalidation.clear_cache()
434 # CacheInvalidation.clear_cache()
435 # sa.commit()
435 # sa.commit()
436
436
437 ##creation defaults
437 ##creation defaults
438 defs = RhodeCodeSetting.get_default_repo_settings(strip_prefix=True)
438 defs = RhodeCodeSetting.get_default_repo_settings(strip_prefix=True)
439 enable_statistics = defs.get('repo_enable_statistics')
439 enable_statistics = defs.get('repo_enable_statistics')
440 enable_locking = defs.get('repo_enable_locking')
440 enable_locking = defs.get('repo_enable_locking')
441 enable_downloads = defs.get('repo_enable_downloads')
441 enable_downloads = defs.get('repo_enable_downloads')
442 private = defs.get('repo_private')
442 private = defs.get('repo_private')
443
443
444 for name, repo in initial_repo_list.items():
444 for name, repo in initial_repo_list.items():
445 group = map_groups(name)
445 group = map_groups(name)
446 db_repo = rm.get_by_repo_name(name)
446 db_repo = rm.get_by_repo_name(name)
447 # found repo that is on filesystem not in RhodeCode database
447 # found repo that is on filesystem not in RhodeCode database
448 if not db_repo:
448 if not db_repo:
449 log.info('repository %s not found, creating now' % name)
449 log.info('repository %s not found, creating now' % name)
450 added.append(name)
450 added.append(name)
451 desc = (repo.description
451 desc = (repo.description
452 if repo.description != 'unknown'
452 if repo.description != 'unknown'
453 else '%s repository' % name)
453 else '%s repository' % name)
454
454
455 new_repo = rm.create_repo(
455 new_repo = rm.create_repo(
456 repo_name=name,
456 repo_name=name,
457 repo_type=repo.alias,
457 repo_type=repo.alias,
458 description=desc,
458 description=desc,
459 repos_group=getattr(group, 'group_id', None),
459 repos_group=getattr(group, 'group_id', None),
460 owner=user,
460 owner=user,
461 just_db=True,
461 just_db=True,
462 enable_locking=enable_locking,
462 enable_locking=enable_locking,
463 enable_downloads=enable_downloads,
463 enable_downloads=enable_downloads,
464 enable_statistics=enable_statistics,
464 enable_statistics=enable_statistics,
465 private=private
465 private=private
466 )
466 )
467 # we added that repo just now, and make sure it has githook
467 # we added that repo just now, and make sure it has githook
468 # installed
468 # installed
469 if new_repo.repo_type == 'git':
469 if new_repo.repo_type == 'git':
470 ScmModel().install_git_hook(new_repo.scm_instance)
470 ScmModel().install_git_hook(new_repo.scm_instance)
471 new_repo.update_changeset_cache()
471 new_repo.update_changeset_cache()
472 elif install_git_hook:
472 elif install_git_hook:
473 if db_repo.repo_type == 'git':
473 if db_repo.repo_type == 'git':
474 ScmModel().install_git_hook(db_repo.scm_instance)
474 ScmModel().install_git_hook(db_repo.scm_instance)
475 # during starting install all cache keys for all repositories in the
475 # during starting install all cache keys for all repositories in the
476 # system, this will register all repos and multiple instances
476 # system, this will register all repos and multiple instances
477 key, _prefix, _org_key = CacheInvalidation._get_key(name)
477 key, _prefix, _org_key = CacheInvalidation._get_key(name)
478 CacheInvalidation.invalidate(name)
478 CacheInvalidation.invalidate(name)
479 log.debug("Creating a cache key for %s, instance_id %s"
479 log.debug("Creating a cache key for %s, instance_id %s"
480 % (name, _prefix or 'unknown'))
480 % (name, _prefix or 'unknown'))
481
481
482 sa.commit()
482 sa.commit()
483 removed = []
483 removed = []
484 if remove_obsolete:
484 if remove_obsolete:
485 # remove from database those repositories that are not in the filesystem
485 # remove from database those repositories that are not in the filesystem
486 for repo in sa.query(Repository).all():
486 for repo in sa.query(Repository).all():
487 if repo.repo_name not in initial_repo_list.keys():
487 if repo.repo_name not in initial_repo_list.keys():
488 log.debug("Removing non-existing repository found in db `%s`" %
488 log.debug("Removing non-existing repository found in db `%s`" %
489 repo.repo_name)
489 repo.repo_name)
490 try:
490 try:
491 sa.delete(repo)
491 sa.delete(repo)
492 sa.commit()
492 sa.commit()
493 removed.append(repo.repo_name)
493 removed.append(repo.repo_name)
494 except:
494 except:
495 #don't hold further removals on error
495 #don't hold further removals on error
496 log.error(traceback.format_exc())
496 log.error(traceback.format_exc())
497 sa.rollback()
497 sa.rollback()
498
499 return added, removed
498 return added, removed
500
499
501
500
502 # set cache regions for beaker so celery can utilise it
501 # set cache regions for beaker so celery can utilise it
503 def add_cache(settings):
502 def add_cache(settings):
504 cache_settings = {'regions': None}
503 cache_settings = {'regions': None}
505 for key in settings.keys():
504 for key in settings.keys():
506 for prefix in ['beaker.cache.', 'cache.']:
505 for prefix in ['beaker.cache.', 'cache.']:
507 if key.startswith(prefix):
506 if key.startswith(prefix):
508 name = key.split(prefix)[1].strip()
507 name = key.split(prefix)[1].strip()
509 cache_settings[name] = settings[key].strip()
508 cache_settings[name] = settings[key].strip()
510 if cache_settings['regions']:
509 if cache_settings['regions']:
511 for region in cache_settings['regions'].split(','):
510 for region in cache_settings['regions'].split(','):
512 region = region.strip()
511 region = region.strip()
513 region_settings = {}
512 region_settings = {}
514 for key, value in cache_settings.items():
513 for key, value in cache_settings.items():
515 if key.startswith(region):
514 if key.startswith(region):
516 region_settings[key.split('.')[1]] = value
515 region_settings[key.split('.')[1]] = value
517 region_settings['expire'] = int(region_settings.get('expire',
516 region_settings['expire'] = int(region_settings.get('expire',
518 60))
517 60))
519 region_settings.setdefault('lock_dir',
518 region_settings.setdefault('lock_dir',
520 cache_settings.get('lock_dir'))
519 cache_settings.get('lock_dir'))
521 region_settings.setdefault('data_dir',
520 region_settings.setdefault('data_dir',
522 cache_settings.get('data_dir'))
521 cache_settings.get('data_dir'))
523
522
524 if 'type' not in region_settings:
523 if 'type' not in region_settings:
525 region_settings['type'] = cache_settings.get('type',
524 region_settings['type'] = cache_settings.get('type',
526 'memory')
525 'memory')
527 beaker.cache.cache_regions[region] = region_settings
526 beaker.cache.cache_regions[region] = region_settings
528
527
529
528
530 def load_rcextensions(root_path):
529 def load_rcextensions(root_path):
531 import rhodecode
530 import rhodecode
532 from rhodecode.config import conf
531 from rhodecode.config import conf
533
532
534 path = os.path.join(root_path, 'rcextensions', '__init__.py')
533 path = os.path.join(root_path, 'rcextensions', '__init__.py')
535 if os.path.isfile(path):
534 if os.path.isfile(path):
536 rcext = create_module('rc', path)
535 rcext = create_module('rc', path)
537 EXT = rhodecode.EXTENSIONS = rcext
536 EXT = rhodecode.EXTENSIONS = rcext
538 log.debug('Found rcextensions now loading %s...' % rcext)
537 log.debug('Found rcextensions now loading %s...' % rcext)
539
538
540 # Additional mappings that are not present in the pygments lexers
539 # Additional mappings that are not present in the pygments lexers
541 conf.LANGUAGES_EXTENSIONS_MAP.update(getattr(EXT, 'EXTRA_MAPPINGS', {}))
540 conf.LANGUAGES_EXTENSIONS_MAP.update(getattr(EXT, 'EXTRA_MAPPINGS', {}))
542
541
543 #OVERRIDE OUR EXTENSIONS FROM RC-EXTENSIONS (if present)
542 #OVERRIDE OUR EXTENSIONS FROM RC-EXTENSIONS (if present)
544
543
545 if getattr(EXT, 'INDEX_EXTENSIONS', []) != []:
544 if getattr(EXT, 'INDEX_EXTENSIONS', []) != []:
546 log.debug('settings custom INDEX_EXTENSIONS')
545 log.debug('settings custom INDEX_EXTENSIONS')
547 conf.INDEX_EXTENSIONS = getattr(EXT, 'INDEX_EXTENSIONS', [])
546 conf.INDEX_EXTENSIONS = getattr(EXT, 'INDEX_EXTENSIONS', [])
548
547
549 #ADDITIONAL MAPPINGS
548 #ADDITIONAL MAPPINGS
550 log.debug('adding extra into INDEX_EXTENSIONS')
549 log.debug('adding extra into INDEX_EXTENSIONS')
551 conf.INDEX_EXTENSIONS.extend(getattr(EXT, 'EXTRA_INDEX_EXTENSIONS', []))
550 conf.INDEX_EXTENSIONS.extend(getattr(EXT, 'EXTRA_INDEX_EXTENSIONS', []))
552
551
553 # auto check if the module is not missing any data, set to default if is
552 # auto check if the module is not missing any data, set to default if is
554 # this will help autoupdate new feature of rcext module
553 # this will help autoupdate new feature of rcext module
555 from rhodecode.config import rcextensions
554 from rhodecode.config import rcextensions
556 for k in dir(rcextensions):
555 for k in dir(rcextensions):
557 if not k.startswith('_') and not hasattr(EXT, k):
556 if not k.startswith('_') and not hasattr(EXT, k):
558 setattr(EXT, k, getattr(rcextensions, k))
557 setattr(EXT, k, getattr(rcextensions, k))
559
558
560
559
561 def get_custom_lexer(extension):
560 def get_custom_lexer(extension):
562 """
561 """
563 returns a custom lexer if it's defined in rcextensions module, or None
562 returns a custom lexer if it's defined in rcextensions module, or None
564 if there's no custom lexer defined
563 if there's no custom lexer defined
565 """
564 """
566 import rhodecode
565 import rhodecode
567 from pygments import lexers
566 from pygments import lexers
568 #check if we didn't define this extension as other lexer
567 #check if we didn't define this extension as other lexer
569 if rhodecode.EXTENSIONS and extension in rhodecode.EXTENSIONS.EXTRA_LEXERS:
568 if rhodecode.EXTENSIONS and extension in rhodecode.EXTENSIONS.EXTRA_LEXERS:
570 _lexer_name = rhodecode.EXTENSIONS.EXTRA_LEXERS[extension]
569 _lexer_name = rhodecode.EXTENSIONS.EXTRA_LEXERS[extension]
571 return lexers.get_lexer_by_name(_lexer_name)
570 return lexers.get_lexer_by_name(_lexer_name)
572
571
573
572
574 #==============================================================================
573 #==============================================================================
575 # TEST FUNCTIONS AND CREATORS
574 # TEST FUNCTIONS AND CREATORS
576 #==============================================================================
575 #==============================================================================
577 def create_test_index(repo_location, config, full_index):
576 def create_test_index(repo_location, config, full_index):
578 """
577 """
579 Makes default test index
578 Makes default test index
580
579
581 :param config: test config
580 :param config: test config
582 :param full_index:
581 :param full_index:
583 """
582 """
584
583
585 from rhodecode.lib.indexers.daemon import WhooshIndexingDaemon
584 from rhodecode.lib.indexers.daemon import WhooshIndexingDaemon
586 from rhodecode.lib.pidlock import DaemonLock, LockHeld
585 from rhodecode.lib.pidlock import DaemonLock, LockHeld
587
586
588 repo_location = repo_location
587 repo_location = repo_location
589
588
590 index_location = os.path.join(config['app_conf']['index_dir'])
589 index_location = os.path.join(config['app_conf']['index_dir'])
591 if not os.path.exists(index_location):
590 if not os.path.exists(index_location):
592 os.makedirs(index_location)
591 os.makedirs(index_location)
593
592
594 try:
593 try:
595 l = DaemonLock(file_=jn(dn(index_location), 'make_index.lock'))
594 l = DaemonLock(file_=jn(dn(index_location), 'make_index.lock'))
596 WhooshIndexingDaemon(index_location=index_location,
595 WhooshIndexingDaemon(index_location=index_location,
597 repo_location=repo_location)\
596 repo_location=repo_location)\
598 .run(full_index=full_index)
597 .run(full_index=full_index)
599 l.release()
598 l.release()
600 except LockHeld:
599 except LockHeld:
601 pass
600 pass
602
601
603
602
604 def create_test_env(repos_test_path, config):
603 def create_test_env(repos_test_path, config):
605 """
604 """
606 Makes a fresh database and
605 Makes a fresh database and
607 install test repository into tmp dir
606 install test repository into tmp dir
608 """
607 """
609 from rhodecode.lib.db_manage import DbManage
608 from rhodecode.lib.db_manage import DbManage
610 from rhodecode.tests import HG_REPO, GIT_REPO, TESTS_TMP_PATH
609 from rhodecode.tests import HG_REPO, GIT_REPO, TESTS_TMP_PATH
611
610
612 # PART ONE create db
611 # PART ONE create db
613 dbconf = config['sqlalchemy.db1.url']
612 dbconf = config['sqlalchemy.db1.url']
614 log.debug('making test db %s' % dbconf)
613 log.debug('making test db %s' % dbconf)
615
614
616 # create test dir if it doesn't exist
615 # create test dir if it doesn't exist
617 if not os.path.isdir(repos_test_path):
616 if not os.path.isdir(repos_test_path):
618 log.debug('Creating testdir %s' % repos_test_path)
617 log.debug('Creating testdir %s' % repos_test_path)
619 os.makedirs(repos_test_path)
618 os.makedirs(repos_test_path)
620
619
621 dbmanage = DbManage(log_sql=True, dbconf=dbconf, root=config['here'],
620 dbmanage = DbManage(log_sql=True, dbconf=dbconf, root=config['here'],
622 tests=True)
621 tests=True)
623 dbmanage.create_tables(override=True)
622 dbmanage.create_tables(override=True)
624 dbmanage.create_settings(dbmanage.config_prompt(repos_test_path))
623 dbmanage.create_settings(dbmanage.config_prompt(repos_test_path))
625 dbmanage.create_default_user()
624 dbmanage.create_default_user()
626 dbmanage.admin_prompt()
625 dbmanage.admin_prompt()
627 dbmanage.create_permissions()
626 dbmanage.create_permissions()
628 dbmanage.populate_default_permissions()
627 dbmanage.populate_default_permissions()
629 Session().commit()
628 Session().commit()
630 # PART TWO make test repo
629 # PART TWO make test repo
631 log.debug('making test vcs repositories')
630 log.debug('making test vcs repositories')
632
631
633 idx_path = config['app_conf']['index_dir']
632 idx_path = config['app_conf']['index_dir']
634 data_path = config['app_conf']['cache_dir']
633 data_path = config['app_conf']['cache_dir']
635
634
636 #clean index and data
635 #clean index and data
637 if idx_path and os.path.exists(idx_path):
636 if idx_path and os.path.exists(idx_path):
638 log.debug('remove %s' % idx_path)
637 log.debug('remove %s' % idx_path)
639 shutil.rmtree(idx_path)
638 shutil.rmtree(idx_path)
640
639
641 if data_path and os.path.exists(data_path):
640 if data_path and os.path.exists(data_path):
642 log.debug('remove %s' % data_path)
641 log.debug('remove %s' % data_path)
643 shutil.rmtree(data_path)
642 shutil.rmtree(data_path)
644
643
645 #CREATE DEFAULT TEST REPOS
644 #CREATE DEFAULT TEST REPOS
646 cur_dir = dn(dn(abspath(__file__)))
645 cur_dir = dn(dn(abspath(__file__)))
647 tar = tarfile.open(jn(cur_dir, 'tests', "vcs_test_hg.tar.gz"))
646 tar = tarfile.open(jn(cur_dir, 'tests', "vcs_test_hg.tar.gz"))
648 tar.extractall(jn(TESTS_TMP_PATH, HG_REPO))
647 tar.extractall(jn(TESTS_TMP_PATH, HG_REPO))
649 tar.close()
648 tar.close()
650
649
651 cur_dir = dn(dn(abspath(__file__)))
650 cur_dir = dn(dn(abspath(__file__)))
652 tar = tarfile.open(jn(cur_dir, 'tests', "vcs_test_git.tar.gz"))
651 tar = tarfile.open(jn(cur_dir, 'tests', "vcs_test_git.tar.gz"))
653 tar.extractall(jn(TESTS_TMP_PATH, GIT_REPO))
652 tar.extractall(jn(TESTS_TMP_PATH, GIT_REPO))
654 tar.close()
653 tar.close()
655
654
656 #LOAD VCS test stuff
655 #LOAD VCS test stuff
657 from rhodecode.tests.vcs import setup_package
656 from rhodecode.tests.vcs import setup_package
658 setup_package()
657 setup_package()
659
658
660
659
661 #==============================================================================
660 #==============================================================================
662 # PASTER COMMANDS
661 # PASTER COMMANDS
663 #==============================================================================
662 #==============================================================================
664 class BasePasterCommand(Command):
663 class BasePasterCommand(Command):
665 """
664 """
666 Abstract Base Class for paster commands.
665 Abstract Base Class for paster commands.
667
666
668 The celery commands are somewhat aggressive about loading
667 The celery commands are somewhat aggressive about loading
669 celery.conf, and since our module sets the `CELERY_LOADER`
668 celery.conf, and since our module sets the `CELERY_LOADER`
670 environment variable to our loader, we have to bootstrap a bit and
669 environment variable to our loader, we have to bootstrap a bit and
671 make sure we've had a chance to load the pylons config off of the
670 make sure we've had a chance to load the pylons config off of the
672 command line, otherwise everything fails.
671 command line, otherwise everything fails.
673 """
672 """
674 min_args = 1
673 min_args = 1
675 min_args_error = "Please provide a paster config file as an argument."
674 min_args_error = "Please provide a paster config file as an argument."
676 takes_config_file = 1
675 takes_config_file = 1
677 requires_config_file = True
676 requires_config_file = True
678
677
679 def notify_msg(self, msg, log=False):
678 def notify_msg(self, msg, log=False):
680 """Make a notification to user, additionally if logger is passed
679 """Make a notification to user, additionally if logger is passed
681 it logs this action using given logger
680 it logs this action using given logger
682
681
683 :param msg: message that will be printed to user
682 :param msg: message that will be printed to user
684 :param log: logging instance, to use to additionally log this message
683 :param log: logging instance, to use to additionally log this message
685
684
686 """
685 """
687 if log and isinstance(log, logging):
686 if log and isinstance(log, logging):
688 log(msg)
687 log(msg)
689
688
690 def run(self, args):
689 def run(self, args):
691 """
690 """
692 Overrides Command.run
691 Overrides Command.run
693
692
694 Checks for a config file argument and loads it.
693 Checks for a config file argument and loads it.
695 """
694 """
696 if len(args) < self.min_args:
695 if len(args) < self.min_args:
697 raise BadCommand(
696 raise BadCommand(
698 self.min_args_error % {'min_args': self.min_args,
697 self.min_args_error % {'min_args': self.min_args,
699 'actual_args': len(args)})
698 'actual_args': len(args)})
700
699
701 # Decrement because we're going to lob off the first argument.
700 # Decrement because we're going to lob off the first argument.
702 # @@ This is hacky
701 # @@ This is hacky
703 self.min_args -= 1
702 self.min_args -= 1
704 self.bootstrap_config(args[0])
703 self.bootstrap_config(args[0])
705 self.update_parser()
704 self.update_parser()
706 return super(BasePasterCommand, self).run(args[1:])
705 return super(BasePasterCommand, self).run(args[1:])
707
706
708 def update_parser(self):
707 def update_parser(self):
709 """
708 """
710 Abstract method. Allows for the class's parser to be updated
709 Abstract method. Allows for the class's parser to be updated
711 before the superclass's `run` method is called. Necessary to
710 before the superclass's `run` method is called. Necessary to
712 allow options/arguments to be passed through to the underlying
711 allow options/arguments to be passed through to the underlying
713 celery command.
712 celery command.
714 """
713 """
715 raise NotImplementedError("Abstract Method.")
714 raise NotImplementedError("Abstract Method.")
716
715
717 def bootstrap_config(self, conf):
716 def bootstrap_config(self, conf):
718 """
717 """
719 Loads the pylons configuration.
718 Loads the pylons configuration.
720 """
719 """
721 from pylons import config as pylonsconfig
720 from pylons import config as pylonsconfig
722
721
723 self.path_to_ini_file = os.path.realpath(conf)
722 self.path_to_ini_file = os.path.realpath(conf)
724 conf = paste.deploy.appconfig('config:' + self.path_to_ini_file)
723 conf = paste.deploy.appconfig('config:' + self.path_to_ini_file)
725 pylonsconfig.init_app(conf.global_conf, conf.local_conf)
724 pylonsconfig.init_app(conf.global_conf, conf.local_conf)
726
725
727 def _init_session(self):
726 def _init_session(self):
728 """
727 """
729 Inits SqlAlchemy Session
728 Inits SqlAlchemy Session
730 """
729 """
731 logging.config.fileConfig(self.path_to_ini_file)
730 logging.config.fileConfig(self.path_to_ini_file)
732 from pylons import config
731 from pylons import config
733 from rhodecode.model import init_model
732 from rhodecode.model import init_model
734 from rhodecode.lib.utils2 import engine_from_config
733 from rhodecode.lib.utils2 import engine_from_config
735
734
736 #get to remove repos !!
735 #get to remove repos !!
737 add_cache(config)
736 add_cache(config)
738 engine = engine_from_config(config, 'sqlalchemy.db1.')
737 engine = engine_from_config(config, 'sqlalchemy.db1.')
739 init_model(engine)
738 init_model(engine)
740
739
741
740
742 def check_git_version():
741 def check_git_version():
743 """
742 """
744 Checks what version of git is installed in system, and issues a warning
743 Checks what version of git is installed in system, and issues a warning
745 if it's too old for RhodeCode to properly work.
744 if it's too old for RhodeCode to properly work.
746 """
745 """
747 from rhodecode import BACKENDS
746 from rhodecode import BACKENDS
748 from rhodecode.lib.vcs.backends.git.repository import GitRepository
747 from rhodecode.lib.vcs.backends.git.repository import GitRepository
749 from distutils.version import StrictVersion
748 from distutils.version import StrictVersion
750
749
751 stdout, stderr = GitRepository._run_git_command('--version', _bare=True,
750 stdout, stderr = GitRepository._run_git_command('--version', _bare=True,
752 _safe=True)
751 _safe=True)
753
752
754 ver = (stdout.split(' ')[-1] or '').strip() or '0.0.0'
753 ver = (stdout.split(' ')[-1] or '').strip() or '0.0.0'
755 if len(ver.split('.')) > 3:
754 if len(ver.split('.')) > 3:
756 #StrictVersion needs to be only 3 element type
755 #StrictVersion needs to be only 3 element type
757 ver = '.'.join(ver.split('.')[:3])
756 ver = '.'.join(ver.split('.')[:3])
758 try:
757 try:
759 _ver = StrictVersion(ver)
758 _ver = StrictVersion(ver)
760 except:
759 except:
761 _ver = StrictVersion('0.0.0')
760 _ver = StrictVersion('0.0.0')
762 stderr = traceback.format_exc()
761 stderr = traceback.format_exc()
763
762
764 req_ver = '1.7.4'
763 req_ver = '1.7.4'
765 to_old_git = False
764 to_old_git = False
766 if _ver < StrictVersion(req_ver):
765 if _ver < StrictVersion(req_ver):
767 to_old_git = True
766 to_old_git = True
768
767
769 if 'git' in BACKENDS:
768 if 'git' in BACKENDS:
770 log.debug('GIT version detected: %s' % stdout)
769 log.debug('GIT version detected: %s' % stdout)
771 if stderr:
770 if stderr:
772 log.warning('Unable to detect git version org error was:%r' % stderr)
771 log.warning('Unable to detect git version org error was:%r' % stderr)
773 elif to_old_git:
772 elif to_old_git:
774 log.warning('RhodeCode detected git version %s, which is too old '
773 log.warning('RhodeCode detected git version %s, which is too old '
775 'for the system to function properly. Make sure '
774 'for the system to function properly. Make sure '
776 'its version is at least %s' % (ver, req_ver))
775 'its version is at least %s' % (ver, req_ver))
777 return _ver
776 return _ver
778
777
779
778
780 @decorator.decorator
779 @decorator.decorator
781 def jsonify(func, *args, **kwargs):
780 def jsonify(func, *args, **kwargs):
782 """Action decorator that formats output for JSON
781 """Action decorator that formats output for JSON
783
782
784 Given a function that will return content, this decorator will turn
783 Given a function that will return content, this decorator will turn
785 the result into JSON, with a content-type of 'application/json' and
784 the result into JSON, with a content-type of 'application/json' and
786 output it.
785 output it.
787
786
788 """
787 """
789 from pylons.decorators.util import get_pylons
788 from pylons.decorators.util import get_pylons
790 from rhodecode.lib.ext_json import json
789 from rhodecode.lib.ext_json import json
791 pylons = get_pylons(args)
790 pylons = get_pylons(args)
792 pylons.response.headers['Content-Type'] = 'application/json; charset=utf-8'
791 pylons.response.headers['Content-Type'] = 'application/json; charset=utf-8'
793 data = func(*args, **kwargs)
792 data = func(*args, **kwargs)
794 if isinstance(data, (list, tuple)):
793 if isinstance(data, (list, tuple)):
795 msg = "JSON responses with Array envelopes are susceptible to " \
794 msg = "JSON responses with Array envelopes are susceptible to " \
796 "cross-site data leak attacks, see " \
795 "cross-site data leak attacks, see " \
797 "http://wiki.pylonshq.com/display/pylonsfaq/Warnings"
796 "http://wiki.pylonshq.com/display/pylonsfaq/Warnings"
798 warnings.warn(msg, Warning, 2)
797 warnings.warn(msg, Warning, 2)
799 log.warning(msg)
798 log.warning(msg)
800 log.debug("Returning JSON wrapped action output")
799 log.debug("Returning JSON wrapped action output")
801 return json.dumps(data, encoding='utf-8')
800 return json.dumps(data, encoding='utf-8')
General Comments 0
You need to be logged in to leave comments. Login now