##// END OF EJS Templates
Added quick links for editing permissions for users from permission overview
marcink -
r2631:f597cfb4 beta
parent child Browse files
Show More
@@ -1,573 +1,572
1 """
1 """
2 Routes configuration
2 Routes configuration
3
3
4 The more specific and detailed routes should be defined first so they
4 The more specific and detailed routes should be defined first so they
5 may take precedent over the more generic routes. For more information
5 may take precedent over the more generic routes. For more information
6 refer to the routes manual at http://routes.groovie.org/docs/
6 refer to the routes manual at http://routes.groovie.org/docs/
7 """
7 """
8 from __future__ import with_statement
8 from __future__ import with_statement
9 from routes import Mapper
9 from routes import Mapper
10
10
11 # prefix for non repository related links needs to be prefixed with `/`
11 # prefix for non repository related links needs to be prefixed with `/`
12 ADMIN_PREFIX = '/_admin'
12 ADMIN_PREFIX = '/_admin'
13
13
14
14
15 def make_map(config):
15 def make_map(config):
16 """Create, configure and return the routes Mapper"""
16 """Create, configure and return the routes Mapper"""
17 rmap = Mapper(directory=config['pylons.paths']['controllers'],
17 rmap = Mapper(directory=config['pylons.paths']['controllers'],
18 always_scan=config['debug'])
18 always_scan=config['debug'])
19 rmap.minimization = False
19 rmap.minimization = False
20 rmap.explicit = False
20 rmap.explicit = False
21
21
22 from rhodecode.lib.utils import is_valid_repo
22 from rhodecode.lib.utils import is_valid_repo
23 from rhodecode.lib.utils import is_valid_repos_group
23 from rhodecode.lib.utils import is_valid_repos_group
24
24
25 def check_repo(environ, match_dict):
25 def check_repo(environ, match_dict):
26 """
26 """
27 check for valid repository for proper 404 handling
27 check for valid repository for proper 404 handling
28
28
29 :param environ:
29 :param environ:
30 :param match_dict:
30 :param match_dict:
31 """
31 """
32 from rhodecode.model.db import Repository
32 from rhodecode.model.db import Repository
33 repo_name = match_dict.get('repo_name')
33 repo_name = match_dict.get('repo_name')
34
34
35 try:
35 try:
36 by_id = repo_name.split('_')
36 by_id = repo_name.split('_')
37 if len(by_id) == 2 and by_id[1].isdigit():
37 if len(by_id) == 2 and by_id[1].isdigit():
38 repo_name = Repository.get(by_id[1]).repo_name
38 repo_name = Repository.get(by_id[1]).repo_name
39 match_dict['repo_name'] = repo_name
39 match_dict['repo_name'] = repo_name
40 except:
40 except:
41 pass
41 pass
42
42
43 return is_valid_repo(repo_name, config['base_path'])
43 return is_valid_repo(repo_name, config['base_path'])
44
44
45 def check_group(environ, match_dict):
45 def check_group(environ, match_dict):
46 """
46 """
47 check for valid repositories group for proper 404 handling
47 check for valid repositories group for proper 404 handling
48
48
49 :param environ:
49 :param environ:
50 :param match_dict:
50 :param match_dict:
51 """
51 """
52 repos_group_name = match_dict.get('group_name')
52 repos_group_name = match_dict.get('group_name')
53
53
54 return is_valid_repos_group(repos_group_name, config['base_path'])
54 return is_valid_repos_group(repos_group_name, config['base_path'])
55
55
56 def check_int(environ, match_dict):
56 def check_int(environ, match_dict):
57 return match_dict.get('id').isdigit()
57 return match_dict.get('id').isdigit()
58
58
59 # The ErrorController route (handles 404/500 error pages); it should
59 # The ErrorController route (handles 404/500 error pages); it should
60 # likely stay at the top, ensuring it can always be resolved
60 # likely stay at the top, ensuring it can always be resolved
61 rmap.connect('/error/{action}', controller='error')
61 rmap.connect('/error/{action}', controller='error')
62 rmap.connect('/error/{action}/{id}', controller='error')
62 rmap.connect('/error/{action}/{id}', controller='error')
63
63
64 #==========================================================================
64 #==========================================================================
65 # CUSTOM ROUTES HERE
65 # CUSTOM ROUTES HERE
66 #==========================================================================
66 #==========================================================================
67
67
68 #MAIN PAGE
68 #MAIN PAGE
69 rmap.connect('home', '/', controller='home', action='index')
69 rmap.connect('home', '/', controller='home', action='index')
70 rmap.connect('repo_switcher', '/repos', controller='home',
70 rmap.connect('repo_switcher', '/repos', controller='home',
71 action='repo_switcher')
71 action='repo_switcher')
72 rmap.connect('branch_tag_switcher', '/branches-tags/{repo_name:.*}',
72 rmap.connect('branch_tag_switcher', '/branches-tags/{repo_name:.*}',
73 controller='home', action='branch_tag_switcher')
73 controller='home', action='branch_tag_switcher')
74 rmap.connect('bugtracker',
74 rmap.connect('bugtracker',
75 "http://bitbucket.org/marcinkuzminski/rhodecode/issues",
75 "http://bitbucket.org/marcinkuzminski/rhodecode/issues",
76 _static=True)
76 _static=True)
77 rmap.connect('rst_help',
77 rmap.connect('rst_help',
78 "http://docutils.sourceforge.net/docs/user/rst/quickref.html",
78 "http://docutils.sourceforge.net/docs/user/rst/quickref.html",
79 _static=True)
79 _static=True)
80 rmap.connect('rhodecode_official', "http://rhodecode.org", _static=True)
80 rmap.connect('rhodecode_official', "http://rhodecode.org", _static=True)
81
81
82 #ADMIN REPOSITORY REST ROUTES
82 #ADMIN REPOSITORY REST ROUTES
83 with rmap.submapper(path_prefix=ADMIN_PREFIX,
83 with rmap.submapper(path_prefix=ADMIN_PREFIX,
84 controller='admin/repos') as m:
84 controller='admin/repos') as m:
85 m.connect("repos", "/repos",
85 m.connect("repos", "/repos",
86 action="create", conditions=dict(method=["POST"]))
86 action="create", conditions=dict(method=["POST"]))
87 m.connect("repos", "/repos",
87 m.connect("repos", "/repos",
88 action="index", conditions=dict(method=["GET"]))
88 action="index", conditions=dict(method=["GET"]))
89 m.connect("formatted_repos", "/repos.{format}",
89 m.connect("formatted_repos", "/repos.{format}",
90 action="index",
90 action="index",
91 conditions=dict(method=["GET"]))
91 conditions=dict(method=["GET"]))
92 m.connect("new_repo", "/repos/new",
92 m.connect("new_repo", "/repos/new",
93 action="new", conditions=dict(method=["GET"]))
93 action="new", conditions=dict(method=["GET"]))
94 m.connect("formatted_new_repo", "/repos/new.{format}",
94 m.connect("formatted_new_repo", "/repos/new.{format}",
95 action="new", conditions=dict(method=["GET"]))
95 action="new", conditions=dict(method=["GET"]))
96 m.connect("/repos/{repo_name:.*}",
96 m.connect("/repos/{repo_name:.*}",
97 action="update", conditions=dict(method=["PUT"],
97 action="update", conditions=dict(method=["PUT"],
98 function=check_repo))
98 function=check_repo))
99 m.connect("/repos/{repo_name:.*}",
99 m.connect("/repos/{repo_name:.*}",
100 action="delete", conditions=dict(method=["DELETE"],
100 action="delete", conditions=dict(method=["DELETE"],
101 function=check_repo))
101 function=check_repo))
102 m.connect("edit_repo", "/repos/{repo_name:.*}/edit",
102 m.connect("edit_repo", "/repos/{repo_name:.*}/edit",
103 action="edit", conditions=dict(method=["GET"],
103 action="edit", conditions=dict(method=["GET"],
104 function=check_repo))
104 function=check_repo))
105 m.connect("formatted_edit_repo", "/repos/{repo_name:.*}.{format}/edit",
105 m.connect("formatted_edit_repo", "/repos/{repo_name:.*}.{format}/edit",
106 action="edit", conditions=dict(method=["GET"],
106 action="edit", conditions=dict(method=["GET"],
107 function=check_repo))
107 function=check_repo))
108 m.connect("repo", "/repos/{repo_name:.*}",
108 m.connect("repo", "/repos/{repo_name:.*}",
109 action="show", conditions=dict(method=["GET"],
109 action="show", conditions=dict(method=["GET"],
110 function=check_repo))
110 function=check_repo))
111 m.connect("formatted_repo", "/repos/{repo_name:.*}.{format}",
111 m.connect("formatted_repo", "/repos/{repo_name:.*}.{format}",
112 action="show", conditions=dict(method=["GET"],
112 action="show", conditions=dict(method=["GET"],
113 function=check_repo))
113 function=check_repo))
114 #ajax delete repo perm user
114 #ajax delete repo perm user
115 m.connect('delete_repo_user', "/repos_delete_user/{repo_name:.*}",
115 m.connect('delete_repo_user', "/repos_delete_user/{repo_name:.*}",
116 action="delete_perm_user",
116 action="delete_perm_user",
117 conditions=dict(method=["DELETE"], function=check_repo))
117 conditions=dict(method=["DELETE"], function=check_repo))
118
118
119 #ajax delete repo perm users_group
119 #ajax delete repo perm users_group
120 m.connect('delete_repo_users_group',
120 m.connect('delete_repo_users_group',
121 "/repos_delete_users_group/{repo_name:.*}",
121 "/repos_delete_users_group/{repo_name:.*}",
122 action="delete_perm_users_group",
122 action="delete_perm_users_group",
123 conditions=dict(method=["DELETE"], function=check_repo))
123 conditions=dict(method=["DELETE"], function=check_repo))
124
124
125 #settings actions
125 #settings actions
126 m.connect('repo_stats', "/repos_stats/{repo_name:.*}",
126 m.connect('repo_stats', "/repos_stats/{repo_name:.*}",
127 action="repo_stats", conditions=dict(method=["DELETE"],
127 action="repo_stats", conditions=dict(method=["DELETE"],
128 function=check_repo))
128 function=check_repo))
129 m.connect('repo_cache', "/repos_cache/{repo_name:.*}",
129 m.connect('repo_cache', "/repos_cache/{repo_name:.*}",
130 action="repo_cache", conditions=dict(method=["DELETE"],
130 action="repo_cache", conditions=dict(method=["DELETE"],
131 function=check_repo))
131 function=check_repo))
132 m.connect('repo_public_journal', "/repos_public_journal/{repo_name:.*}",
132 m.connect('repo_public_journal', "/repos_public_journal/{repo_name:.*}",
133 action="repo_public_journal", conditions=dict(method=["PUT"],
133 action="repo_public_journal", conditions=dict(method=["PUT"],
134 function=check_repo))
134 function=check_repo))
135 m.connect('repo_pull', "/repo_pull/{repo_name:.*}",
135 m.connect('repo_pull', "/repo_pull/{repo_name:.*}",
136 action="repo_pull", conditions=dict(method=["PUT"],
136 action="repo_pull", conditions=dict(method=["PUT"],
137 function=check_repo))
137 function=check_repo))
138 m.connect('repo_as_fork', "/repo_as_fork/{repo_name:.*}",
138 m.connect('repo_as_fork', "/repo_as_fork/{repo_name:.*}",
139 action="repo_as_fork", conditions=dict(method=["PUT"],
139 action="repo_as_fork", conditions=dict(method=["PUT"],
140 function=check_repo))
140 function=check_repo))
141
141
142 with rmap.submapper(path_prefix=ADMIN_PREFIX,
142 with rmap.submapper(path_prefix=ADMIN_PREFIX,
143 controller='admin/repos_groups') as m:
143 controller='admin/repos_groups') as m:
144 m.connect("repos_groups", "/repos_groups",
144 m.connect("repos_groups", "/repos_groups",
145 action="create", conditions=dict(method=["POST"]))
145 action="create", conditions=dict(method=["POST"]))
146 m.connect("repos_groups", "/repos_groups",
146 m.connect("repos_groups", "/repos_groups",
147 action="index", conditions=dict(method=["GET"]))
147 action="index", conditions=dict(method=["GET"]))
148 m.connect("formatted_repos_groups", "/repos_groups.{format}",
148 m.connect("formatted_repos_groups", "/repos_groups.{format}",
149 action="index", conditions=dict(method=["GET"]))
149 action="index", conditions=dict(method=["GET"]))
150 m.connect("new_repos_group", "/repos_groups/new",
150 m.connect("new_repos_group", "/repos_groups/new",
151 action="new", conditions=dict(method=["GET"]))
151 action="new", conditions=dict(method=["GET"]))
152 m.connect("formatted_new_repos_group", "/repos_groups/new.{format}",
152 m.connect("formatted_new_repos_group", "/repos_groups/new.{format}",
153 action="new", conditions=dict(method=["GET"]))
153 action="new", conditions=dict(method=["GET"]))
154 m.connect("update_repos_group", "/repos_groups/{id}",
154 m.connect("update_repos_group", "/repos_groups/{id}",
155 action="update", conditions=dict(method=["PUT"],
155 action="update", conditions=dict(method=["PUT"],
156 function=check_int))
156 function=check_int))
157 m.connect("delete_repos_group", "/repos_groups/{id}",
157 m.connect("delete_repos_group", "/repos_groups/{id}",
158 action="delete", conditions=dict(method=["DELETE"],
158 action="delete", conditions=dict(method=["DELETE"],
159 function=check_int))
159 function=check_int))
160 m.connect("edit_repos_group", "/repos_groups/{id}/edit",
160 m.connect("edit_repos_group", "/repos_groups/{id}/edit",
161 action="edit", conditions=dict(method=["GET"],
161 action="edit", conditions=dict(method=["GET"],))
162 function=check_int))
163 m.connect("formatted_edit_repos_group",
162 m.connect("formatted_edit_repos_group",
164 "/repos_groups/{id}.{format}/edit",
163 "/repos_groups/{id}.{format}/edit",
165 action="edit", conditions=dict(method=["GET"],
164 action="edit", conditions=dict(method=["GET"],
166 function=check_int))
165 function=check_int))
167 m.connect("repos_group", "/repos_groups/{id}",
166 m.connect("repos_group", "/repos_groups/{id}",
168 action="show", conditions=dict(method=["GET"],
167 action="show", conditions=dict(method=["GET"],
169 function=check_int))
168 function=check_int))
170 m.connect("formatted_repos_group", "/repos_groups/{id}.{format}",
169 m.connect("formatted_repos_group", "/repos_groups/{id}.{format}",
171 action="show", conditions=dict(method=["GET"],
170 action="show", conditions=dict(method=["GET"],
172 function=check_int))
171 function=check_int))
173 # ajax delete repos group perm user
172 # ajax delete repos group perm user
174 m.connect('delete_repos_group_user_perm',
173 m.connect('delete_repos_group_user_perm',
175 "/delete_repos_group_user_perm/{group_name:.*}",
174 "/delete_repos_group_user_perm/{group_name:.*}",
176 action="delete_repos_group_user_perm",
175 action="delete_repos_group_user_perm",
177 conditions=dict(method=["DELETE"], function=check_group))
176 conditions=dict(method=["DELETE"], function=check_group))
178
177
179 # ajax delete repos group perm users_group
178 # ajax delete repos group perm users_group
180 m.connect('delete_repos_group_users_group_perm',
179 m.connect('delete_repos_group_users_group_perm',
181 "/delete_repos_group_users_group_perm/{group_name:.*}",
180 "/delete_repos_group_users_group_perm/{group_name:.*}",
182 action="delete_repos_group_users_group_perm",
181 action="delete_repos_group_users_group_perm",
183 conditions=dict(method=["DELETE"], function=check_group))
182 conditions=dict(method=["DELETE"], function=check_group))
184
183
185 #ADMIN USER REST ROUTES
184 #ADMIN USER REST ROUTES
186 with rmap.submapper(path_prefix=ADMIN_PREFIX,
185 with rmap.submapper(path_prefix=ADMIN_PREFIX,
187 controller='admin/users') as m:
186 controller='admin/users') as m:
188 m.connect("users", "/users",
187 m.connect("users", "/users",
189 action="create", conditions=dict(method=["POST"]))
188 action="create", conditions=dict(method=["POST"]))
190 m.connect("users", "/users",
189 m.connect("users", "/users",
191 action="index", conditions=dict(method=["GET"]))
190 action="index", conditions=dict(method=["GET"]))
192 m.connect("formatted_users", "/users.{format}",
191 m.connect("formatted_users", "/users.{format}",
193 action="index", conditions=dict(method=["GET"]))
192 action="index", conditions=dict(method=["GET"]))
194 m.connect("new_user", "/users/new",
193 m.connect("new_user", "/users/new",
195 action="new", conditions=dict(method=["GET"]))
194 action="new", conditions=dict(method=["GET"]))
196 m.connect("formatted_new_user", "/users/new.{format}",
195 m.connect("formatted_new_user", "/users/new.{format}",
197 action="new", conditions=dict(method=["GET"]))
196 action="new", conditions=dict(method=["GET"]))
198 m.connect("update_user", "/users/{id}",
197 m.connect("update_user", "/users/{id}",
199 action="update", conditions=dict(method=["PUT"]))
198 action="update", conditions=dict(method=["PUT"]))
200 m.connect("delete_user", "/users/{id}",
199 m.connect("delete_user", "/users/{id}",
201 action="delete", conditions=dict(method=["DELETE"]))
200 action="delete", conditions=dict(method=["DELETE"]))
202 m.connect("edit_user", "/users/{id}/edit",
201 m.connect("edit_user", "/users/{id}/edit",
203 action="edit", conditions=dict(method=["GET"]))
202 action="edit", conditions=dict(method=["GET"]))
204 m.connect("formatted_edit_user",
203 m.connect("formatted_edit_user",
205 "/users/{id}.{format}/edit",
204 "/users/{id}.{format}/edit",
206 action="edit", conditions=dict(method=["GET"]))
205 action="edit", conditions=dict(method=["GET"]))
207 m.connect("user", "/users/{id}",
206 m.connect("user", "/users/{id}",
208 action="show", conditions=dict(method=["GET"]))
207 action="show", conditions=dict(method=["GET"]))
209 m.connect("formatted_user", "/users/{id}.{format}",
208 m.connect("formatted_user", "/users/{id}.{format}",
210 action="show", conditions=dict(method=["GET"]))
209 action="show", conditions=dict(method=["GET"]))
211
210
212 #EXTRAS USER ROUTES
211 #EXTRAS USER ROUTES
213 m.connect("user_perm", "/users_perm/{id}",
212 m.connect("user_perm", "/users_perm/{id}",
214 action="update_perm", conditions=dict(method=["PUT"]))
213 action="update_perm", conditions=dict(method=["PUT"]))
215 m.connect("user_emails", "/users_emails/{id}",
214 m.connect("user_emails", "/users_emails/{id}",
216 action="add_email", conditions=dict(method=["PUT"]))
215 action="add_email", conditions=dict(method=["PUT"]))
217 m.connect("user_emails_delete", "/users_emails/{id}",
216 m.connect("user_emails_delete", "/users_emails/{id}",
218 action="delete_email", conditions=dict(method=["DELETE"]))
217 action="delete_email", conditions=dict(method=["DELETE"]))
219
218
220 #ADMIN USERS GROUPS REST ROUTES
219 #ADMIN USERS GROUPS REST ROUTES
221 with rmap.submapper(path_prefix=ADMIN_PREFIX,
220 with rmap.submapper(path_prefix=ADMIN_PREFIX,
222 controller='admin/users_groups') as m:
221 controller='admin/users_groups') as m:
223 m.connect("users_groups", "/users_groups",
222 m.connect("users_groups", "/users_groups",
224 action="create", conditions=dict(method=["POST"]))
223 action="create", conditions=dict(method=["POST"]))
225 m.connect("users_groups", "/users_groups",
224 m.connect("users_groups", "/users_groups",
226 action="index", conditions=dict(method=["GET"]))
225 action="index", conditions=dict(method=["GET"]))
227 m.connect("formatted_users_groups", "/users_groups.{format}",
226 m.connect("formatted_users_groups", "/users_groups.{format}",
228 action="index", conditions=dict(method=["GET"]))
227 action="index", conditions=dict(method=["GET"]))
229 m.connect("new_users_group", "/users_groups/new",
228 m.connect("new_users_group", "/users_groups/new",
230 action="new", conditions=dict(method=["GET"]))
229 action="new", conditions=dict(method=["GET"]))
231 m.connect("formatted_new_users_group", "/users_groups/new.{format}",
230 m.connect("formatted_new_users_group", "/users_groups/new.{format}",
232 action="new", conditions=dict(method=["GET"]))
231 action="new", conditions=dict(method=["GET"]))
233 m.connect("update_users_group", "/users_groups/{id}",
232 m.connect("update_users_group", "/users_groups/{id}",
234 action="update", conditions=dict(method=["PUT"]))
233 action="update", conditions=dict(method=["PUT"]))
235 m.connect("delete_users_group", "/users_groups/{id}",
234 m.connect("delete_users_group", "/users_groups/{id}",
236 action="delete", conditions=dict(method=["DELETE"]))
235 action="delete", conditions=dict(method=["DELETE"]))
237 m.connect("edit_users_group", "/users_groups/{id}/edit",
236 m.connect("edit_users_group", "/users_groups/{id}/edit",
238 action="edit", conditions=dict(method=["GET"]))
237 action="edit", conditions=dict(method=["GET"]))
239 m.connect("formatted_edit_users_group",
238 m.connect("formatted_edit_users_group",
240 "/users_groups/{id}.{format}/edit",
239 "/users_groups/{id}.{format}/edit",
241 action="edit", conditions=dict(method=["GET"]))
240 action="edit", conditions=dict(method=["GET"]))
242 m.connect("users_group", "/users_groups/{id}",
241 m.connect("users_group", "/users_groups/{id}",
243 action="show", conditions=dict(method=["GET"]))
242 action="show", conditions=dict(method=["GET"]))
244 m.connect("formatted_users_group", "/users_groups/{id}.{format}",
243 m.connect("formatted_users_group", "/users_groups/{id}.{format}",
245 action="show", conditions=dict(method=["GET"]))
244 action="show", conditions=dict(method=["GET"]))
246
245
247 #EXTRAS USER ROUTES
246 #EXTRAS USER ROUTES
248 m.connect("users_group_perm", "/users_groups_perm/{id}",
247 m.connect("users_group_perm", "/users_groups_perm/{id}",
249 action="update_perm", conditions=dict(method=["PUT"]))
248 action="update_perm", conditions=dict(method=["PUT"]))
250
249
251 #ADMIN GROUP REST ROUTES
250 #ADMIN GROUP REST ROUTES
252 rmap.resource('group', 'groups',
251 rmap.resource('group', 'groups',
253 controller='admin/groups', path_prefix=ADMIN_PREFIX)
252 controller='admin/groups', path_prefix=ADMIN_PREFIX)
254
253
255 #ADMIN PERMISSIONS REST ROUTES
254 #ADMIN PERMISSIONS REST ROUTES
256 rmap.resource('permission', 'permissions',
255 rmap.resource('permission', 'permissions',
257 controller='admin/permissions', path_prefix=ADMIN_PREFIX)
256 controller='admin/permissions', path_prefix=ADMIN_PREFIX)
258
257
259 ##ADMIN LDAP SETTINGS
258 ##ADMIN LDAP SETTINGS
260 rmap.connect('ldap_settings', '%s/ldap' % ADMIN_PREFIX,
259 rmap.connect('ldap_settings', '%s/ldap' % ADMIN_PREFIX,
261 controller='admin/ldap_settings', action='ldap_settings',
260 controller='admin/ldap_settings', action='ldap_settings',
262 conditions=dict(method=["POST"]))
261 conditions=dict(method=["POST"]))
263
262
264 rmap.connect('ldap_home', '%s/ldap' % ADMIN_PREFIX,
263 rmap.connect('ldap_home', '%s/ldap' % ADMIN_PREFIX,
265 controller='admin/ldap_settings')
264 controller='admin/ldap_settings')
266
265
267 #ADMIN SETTINGS REST ROUTES
266 #ADMIN SETTINGS REST ROUTES
268 with rmap.submapper(path_prefix=ADMIN_PREFIX,
267 with rmap.submapper(path_prefix=ADMIN_PREFIX,
269 controller='admin/settings') as m:
268 controller='admin/settings') as m:
270 m.connect("admin_settings", "/settings",
269 m.connect("admin_settings", "/settings",
271 action="create", conditions=dict(method=["POST"]))
270 action="create", conditions=dict(method=["POST"]))
272 m.connect("admin_settings", "/settings",
271 m.connect("admin_settings", "/settings",
273 action="index", conditions=dict(method=["GET"]))
272 action="index", conditions=dict(method=["GET"]))
274 m.connect("formatted_admin_settings", "/settings.{format}",
273 m.connect("formatted_admin_settings", "/settings.{format}",
275 action="index", conditions=dict(method=["GET"]))
274 action="index", conditions=dict(method=["GET"]))
276 m.connect("admin_new_setting", "/settings/new",
275 m.connect("admin_new_setting", "/settings/new",
277 action="new", conditions=dict(method=["GET"]))
276 action="new", conditions=dict(method=["GET"]))
278 m.connect("formatted_admin_new_setting", "/settings/new.{format}",
277 m.connect("formatted_admin_new_setting", "/settings/new.{format}",
279 action="new", conditions=dict(method=["GET"]))
278 action="new", conditions=dict(method=["GET"]))
280 m.connect("/settings/{setting_id}",
279 m.connect("/settings/{setting_id}",
281 action="update", conditions=dict(method=["PUT"]))
280 action="update", conditions=dict(method=["PUT"]))
282 m.connect("/settings/{setting_id}",
281 m.connect("/settings/{setting_id}",
283 action="delete", conditions=dict(method=["DELETE"]))
282 action="delete", conditions=dict(method=["DELETE"]))
284 m.connect("admin_edit_setting", "/settings/{setting_id}/edit",
283 m.connect("admin_edit_setting", "/settings/{setting_id}/edit",
285 action="edit", conditions=dict(method=["GET"]))
284 action="edit", conditions=dict(method=["GET"]))
286 m.connect("formatted_admin_edit_setting",
285 m.connect("formatted_admin_edit_setting",
287 "/settings/{setting_id}.{format}/edit",
286 "/settings/{setting_id}.{format}/edit",
288 action="edit", conditions=dict(method=["GET"]))
287 action="edit", conditions=dict(method=["GET"]))
289 m.connect("admin_setting", "/settings/{setting_id}",
288 m.connect("admin_setting", "/settings/{setting_id}",
290 action="show", conditions=dict(method=["GET"]))
289 action="show", conditions=dict(method=["GET"]))
291 m.connect("formatted_admin_setting", "/settings/{setting_id}.{format}",
290 m.connect("formatted_admin_setting", "/settings/{setting_id}.{format}",
292 action="show", conditions=dict(method=["GET"]))
291 action="show", conditions=dict(method=["GET"]))
293 m.connect("admin_settings_my_account", "/my_account",
292 m.connect("admin_settings_my_account", "/my_account",
294 action="my_account", conditions=dict(method=["GET"]))
293 action="my_account", conditions=dict(method=["GET"]))
295 m.connect("admin_settings_my_account_update", "/my_account_update",
294 m.connect("admin_settings_my_account_update", "/my_account_update",
296 action="my_account_update", conditions=dict(method=["PUT"]))
295 action="my_account_update", conditions=dict(method=["PUT"]))
297 m.connect("admin_settings_create_repository", "/create_repository",
296 m.connect("admin_settings_create_repository", "/create_repository",
298 action="create_repository", conditions=dict(method=["GET"]))
297 action="create_repository", conditions=dict(method=["GET"]))
299 m.connect("admin_settings_my_repos", "/my_account/repos",
298 m.connect("admin_settings_my_repos", "/my_account/repos",
300 action="my_account_my_repos", conditions=dict(method=["GET"]))
299 action="my_account_my_repos", conditions=dict(method=["GET"]))
301 m.connect("admin_settings_my_pullrequests", "/my_account/pull_requests",
300 m.connect("admin_settings_my_pullrequests", "/my_account/pull_requests",
302 action="my_account_my_pullrequests", conditions=dict(method=["GET"]))
301 action="my_account_my_pullrequests", conditions=dict(method=["GET"]))
303
302
304
303
305 #NOTIFICATION REST ROUTES
304 #NOTIFICATION REST ROUTES
306 with rmap.submapper(path_prefix=ADMIN_PREFIX,
305 with rmap.submapper(path_prefix=ADMIN_PREFIX,
307 controller='admin/notifications') as m:
306 controller='admin/notifications') as m:
308 m.connect("notifications", "/notifications",
307 m.connect("notifications", "/notifications",
309 action="create", conditions=dict(method=["POST"]))
308 action="create", conditions=dict(method=["POST"]))
310 m.connect("notifications", "/notifications",
309 m.connect("notifications", "/notifications",
311 action="index", conditions=dict(method=["GET"]))
310 action="index", conditions=dict(method=["GET"]))
312 m.connect("notifications_mark_all_read", "/notifications/mark_all_read",
311 m.connect("notifications_mark_all_read", "/notifications/mark_all_read",
313 action="mark_all_read", conditions=dict(method=["GET"]))
312 action="mark_all_read", conditions=dict(method=["GET"]))
314 m.connect("formatted_notifications", "/notifications.{format}",
313 m.connect("formatted_notifications", "/notifications.{format}",
315 action="index", conditions=dict(method=["GET"]))
314 action="index", conditions=dict(method=["GET"]))
316 m.connect("new_notification", "/notifications/new",
315 m.connect("new_notification", "/notifications/new",
317 action="new", conditions=dict(method=["GET"]))
316 action="new", conditions=dict(method=["GET"]))
318 m.connect("formatted_new_notification", "/notifications/new.{format}",
317 m.connect("formatted_new_notification", "/notifications/new.{format}",
319 action="new", conditions=dict(method=["GET"]))
318 action="new", conditions=dict(method=["GET"]))
320 m.connect("/notification/{notification_id}",
319 m.connect("/notification/{notification_id}",
321 action="update", conditions=dict(method=["PUT"]))
320 action="update", conditions=dict(method=["PUT"]))
322 m.connect("/notification/{notification_id}",
321 m.connect("/notification/{notification_id}",
323 action="delete", conditions=dict(method=["DELETE"]))
322 action="delete", conditions=dict(method=["DELETE"]))
324 m.connect("edit_notification", "/notification/{notification_id}/edit",
323 m.connect("edit_notification", "/notification/{notification_id}/edit",
325 action="edit", conditions=dict(method=["GET"]))
324 action="edit", conditions=dict(method=["GET"]))
326 m.connect("formatted_edit_notification",
325 m.connect("formatted_edit_notification",
327 "/notification/{notification_id}.{format}/edit",
326 "/notification/{notification_id}.{format}/edit",
328 action="edit", conditions=dict(method=["GET"]))
327 action="edit", conditions=dict(method=["GET"]))
329 m.connect("notification", "/notification/{notification_id}",
328 m.connect("notification", "/notification/{notification_id}",
330 action="show", conditions=dict(method=["GET"]))
329 action="show", conditions=dict(method=["GET"]))
331 m.connect("formatted_notification", "/notifications/{notification_id}.{format}",
330 m.connect("formatted_notification", "/notifications/{notification_id}.{format}",
332 action="show", conditions=dict(method=["GET"]))
331 action="show", conditions=dict(method=["GET"]))
333
332
334 #ADMIN MAIN PAGES
333 #ADMIN MAIN PAGES
335 with rmap.submapper(path_prefix=ADMIN_PREFIX,
334 with rmap.submapper(path_prefix=ADMIN_PREFIX,
336 controller='admin/admin') as m:
335 controller='admin/admin') as m:
337 m.connect('admin_home', '', action='index')
336 m.connect('admin_home', '', action='index')
338 m.connect('admin_add_repo', '/add_repo/{new_repo:[a-z0-9\. _-]*}',
337 m.connect('admin_add_repo', '/add_repo/{new_repo:[a-z0-9\. _-]*}',
339 action='add_repo')
338 action='add_repo')
340
339
341 #==========================================================================
340 #==========================================================================
342 # API V2
341 # API V2
343 #==========================================================================
342 #==========================================================================
344 with rmap.submapper(path_prefix=ADMIN_PREFIX,
343 with rmap.submapper(path_prefix=ADMIN_PREFIX,
345 controller='api/api') as m:
344 controller='api/api') as m:
346 m.connect('api', '/api')
345 m.connect('api', '/api')
347
346
348 #USER JOURNAL
347 #USER JOURNAL
349 rmap.connect('journal', '%s/journal' % ADMIN_PREFIX,
348 rmap.connect('journal', '%s/journal' % ADMIN_PREFIX,
350 controller='journal', action='index')
349 controller='journal', action='index')
351 rmap.connect('journal_rss', '%s/journal/rss' % ADMIN_PREFIX,
350 rmap.connect('journal_rss', '%s/journal/rss' % ADMIN_PREFIX,
352 controller='journal', action='journal_rss')
351 controller='journal', action='journal_rss')
353 rmap.connect('journal_atom', '%s/journal/atom' % ADMIN_PREFIX,
352 rmap.connect('journal_atom', '%s/journal/atom' % ADMIN_PREFIX,
354 controller='journal', action='journal_atom')
353 controller='journal', action='journal_atom')
355
354
356 rmap.connect('public_journal', '%s/public_journal' % ADMIN_PREFIX,
355 rmap.connect('public_journal', '%s/public_journal' % ADMIN_PREFIX,
357 controller='journal', action="public_journal")
356 controller='journal', action="public_journal")
358
357
359 rmap.connect('public_journal_rss', '%s/public_journal/rss' % ADMIN_PREFIX,
358 rmap.connect('public_journal_rss', '%s/public_journal/rss' % ADMIN_PREFIX,
360 controller='journal', action="public_journal_rss")
359 controller='journal', action="public_journal_rss")
361
360
362 rmap.connect('public_journal_rss_old', '%s/public_journal_rss' % ADMIN_PREFIX,
361 rmap.connect('public_journal_rss_old', '%s/public_journal_rss' % ADMIN_PREFIX,
363 controller='journal', action="public_journal_rss")
362 controller='journal', action="public_journal_rss")
364
363
365 rmap.connect('public_journal_atom',
364 rmap.connect('public_journal_atom',
366 '%s/public_journal/atom' % ADMIN_PREFIX, controller='journal',
365 '%s/public_journal/atom' % ADMIN_PREFIX, controller='journal',
367 action="public_journal_atom")
366 action="public_journal_atom")
368
367
369 rmap.connect('public_journal_atom_old',
368 rmap.connect('public_journal_atom_old',
370 '%s/public_journal_atom' % ADMIN_PREFIX, controller='journal',
369 '%s/public_journal_atom' % ADMIN_PREFIX, controller='journal',
371 action="public_journal_atom")
370 action="public_journal_atom")
372
371
373 rmap.connect('toggle_following', '%s/toggle_following' % ADMIN_PREFIX,
372 rmap.connect('toggle_following', '%s/toggle_following' % ADMIN_PREFIX,
374 controller='journal', action='toggle_following',
373 controller='journal', action='toggle_following',
375 conditions=dict(method=["POST"]))
374 conditions=dict(method=["POST"]))
376
375
377 #SEARCH
376 #SEARCH
378 rmap.connect('search', '%s/search' % ADMIN_PREFIX, controller='search',)
377 rmap.connect('search', '%s/search' % ADMIN_PREFIX, controller='search',)
379 rmap.connect('search_repo', '%s/search/{search_repo:.*}' % ADMIN_PREFIX,
378 rmap.connect('search_repo', '%s/search/{search_repo:.*}' % ADMIN_PREFIX,
380 controller='search')
379 controller='search')
381
380
382 #LOGIN/LOGOUT/REGISTER/SIGN IN
381 #LOGIN/LOGOUT/REGISTER/SIGN IN
383 rmap.connect('login_home', '%s/login' % ADMIN_PREFIX, controller='login')
382 rmap.connect('login_home', '%s/login' % ADMIN_PREFIX, controller='login')
384 rmap.connect('logout_home', '%s/logout' % ADMIN_PREFIX, controller='login',
383 rmap.connect('logout_home', '%s/logout' % ADMIN_PREFIX, controller='login',
385 action='logout')
384 action='logout')
386
385
387 rmap.connect('register', '%s/register' % ADMIN_PREFIX, controller='login',
386 rmap.connect('register', '%s/register' % ADMIN_PREFIX, controller='login',
388 action='register')
387 action='register')
389
388
390 rmap.connect('reset_password', '%s/password_reset' % ADMIN_PREFIX,
389 rmap.connect('reset_password', '%s/password_reset' % ADMIN_PREFIX,
391 controller='login', action='password_reset')
390 controller='login', action='password_reset')
392
391
393 rmap.connect('reset_password_confirmation',
392 rmap.connect('reset_password_confirmation',
394 '%s/password_reset_confirmation' % ADMIN_PREFIX,
393 '%s/password_reset_confirmation' % ADMIN_PREFIX,
395 controller='login', action='password_reset_confirmation')
394 controller='login', action='password_reset_confirmation')
396
395
397 #FEEDS
396 #FEEDS
398 rmap.connect('rss_feed_home', '/{repo_name:.*}/feed/rss',
397 rmap.connect('rss_feed_home', '/{repo_name:.*}/feed/rss',
399 controller='feed', action='rss',
398 controller='feed', action='rss',
400 conditions=dict(function=check_repo))
399 conditions=dict(function=check_repo))
401
400
402 rmap.connect('atom_feed_home', '/{repo_name:.*}/feed/atom',
401 rmap.connect('atom_feed_home', '/{repo_name:.*}/feed/atom',
403 controller='feed', action='atom',
402 controller='feed', action='atom',
404 conditions=dict(function=check_repo))
403 conditions=dict(function=check_repo))
405
404
406 #==========================================================================
405 #==========================================================================
407 # REPOSITORY ROUTES
406 # REPOSITORY ROUTES
408 #==========================================================================
407 #==========================================================================
409 rmap.connect('summary_home', '/{repo_name:.*}',
408 rmap.connect('summary_home', '/{repo_name:.*}',
410 controller='summary',
409 controller='summary',
411 conditions=dict(function=check_repo))
410 conditions=dict(function=check_repo))
412
411
413 rmap.connect('repos_group_home', '/{group_name:.*}',
412 rmap.connect('repos_group_home', '/{group_name:.*}',
414 controller='admin/repos_groups', action="show_by_name",
413 controller='admin/repos_groups', action="show_by_name",
415 conditions=dict(function=check_group))
414 conditions=dict(function=check_group))
416
415
417 rmap.connect('changeset_home', '/{repo_name:.*}/changeset/{revision}',
416 rmap.connect('changeset_home', '/{repo_name:.*}/changeset/{revision}',
418 controller='changeset', revision='tip',
417 controller='changeset', revision='tip',
419 conditions=dict(function=check_repo))
418 conditions=dict(function=check_repo))
420
419
421 rmap.connect('changeset_comment',
420 rmap.connect('changeset_comment',
422 '/{repo_name:.*}/changeset/{revision}/comment',
421 '/{repo_name:.*}/changeset/{revision}/comment',
423 controller='changeset', revision='tip', action='comment',
422 controller='changeset', revision='tip', action='comment',
424 conditions=dict(function=check_repo))
423 conditions=dict(function=check_repo))
425
424
426 rmap.connect('changeset_comment_delete',
425 rmap.connect('changeset_comment_delete',
427 '/{repo_name:.*}/changeset/comment/{comment_id}/delete',
426 '/{repo_name:.*}/changeset/comment/{comment_id}/delete',
428 controller='changeset', action='delete_comment',
427 controller='changeset', action='delete_comment',
429 conditions=dict(function=check_repo, method=["DELETE"]))
428 conditions=dict(function=check_repo, method=["DELETE"]))
430
429
431 rmap.connect('raw_changeset_home',
430 rmap.connect('raw_changeset_home',
432 '/{repo_name:.*}/raw-changeset/{revision}',
431 '/{repo_name:.*}/raw-changeset/{revision}',
433 controller='changeset', action='raw_changeset',
432 controller='changeset', action='raw_changeset',
434 revision='tip', conditions=dict(function=check_repo))
433 revision='tip', conditions=dict(function=check_repo))
435
434
436 rmap.connect('compare_url',
435 rmap.connect('compare_url',
437 '/{repo_name:.*}/compare/{org_ref_type}@{org_ref}...{other_ref_type}@{other_ref}',
436 '/{repo_name:.*}/compare/{org_ref_type}@{org_ref}...{other_ref_type}@{other_ref}',
438 controller='compare', action='index',
437 controller='compare', action='index',
439 conditions=dict(function=check_repo),
438 conditions=dict(function=check_repo),
440 requirements=dict(org_ref_type='(branch|book|tag|rev)',
439 requirements=dict(org_ref_type='(branch|book|tag|rev)',
441 other_ref_type='(branch|book|tag|rev)'))
440 other_ref_type='(branch|book|tag|rev)'))
442
441
443 rmap.connect('pullrequest_home',
442 rmap.connect('pullrequest_home',
444 '/{repo_name:.*}/pull-request/new', controller='pullrequests',
443 '/{repo_name:.*}/pull-request/new', controller='pullrequests',
445 action='index', conditions=dict(function=check_repo,
444 action='index', conditions=dict(function=check_repo,
446 method=["GET"]))
445 method=["GET"]))
447
446
448 rmap.connect('pullrequest',
447 rmap.connect('pullrequest',
449 '/{repo_name:.*}/pull-request/new', controller='pullrequests',
448 '/{repo_name:.*}/pull-request/new', controller='pullrequests',
450 action='create', conditions=dict(function=check_repo,
449 action='create', conditions=dict(function=check_repo,
451 method=["POST"]))
450 method=["POST"]))
452
451
453 rmap.connect('pullrequest_show',
452 rmap.connect('pullrequest_show',
454 '/{repo_name:.*}/pull-request/{pull_request_id}',
453 '/{repo_name:.*}/pull-request/{pull_request_id}',
455 controller='pullrequests',
454 controller='pullrequests',
456 action='show', conditions=dict(function=check_repo,
455 action='show', conditions=dict(function=check_repo,
457 method=["GET"]))
456 method=["GET"]))
458 rmap.connect('pullrequest_update',
457 rmap.connect('pullrequest_update',
459 '/{repo_name:.*}/pull-request/{pull_request_id}',
458 '/{repo_name:.*}/pull-request/{pull_request_id}',
460 controller='pullrequests',
459 controller='pullrequests',
461 action='update', conditions=dict(function=check_repo,
460 action='update', conditions=dict(function=check_repo,
462 method=["PUT"]))
461 method=["PUT"]))
463
462
464 rmap.connect('pullrequest_show_all',
463 rmap.connect('pullrequest_show_all',
465 '/{repo_name:.*}/pull-request',
464 '/{repo_name:.*}/pull-request',
466 controller='pullrequests',
465 controller='pullrequests',
467 action='show_all', conditions=dict(function=check_repo,
466 action='show_all', conditions=dict(function=check_repo,
468 method=["GET"]))
467 method=["GET"]))
469
468
470 rmap.connect('pullrequest_comment',
469 rmap.connect('pullrequest_comment',
471 '/{repo_name:.*}/pull-request-comment/{pull_request_id}',
470 '/{repo_name:.*}/pull-request-comment/{pull_request_id}',
472 controller='pullrequests',
471 controller='pullrequests',
473 action='comment', conditions=dict(function=check_repo,
472 action='comment', conditions=dict(function=check_repo,
474 method=["POST"]))
473 method=["POST"]))
475
474
476 rmap.connect('pullrequest_comment_delete',
475 rmap.connect('pullrequest_comment_delete',
477 '/{repo_name:.*}/pull-request-comment/{comment_id}/delete',
476 '/{repo_name:.*}/pull-request-comment/{comment_id}/delete',
478 controller='pullrequests', action='delete_comment',
477 controller='pullrequests', action='delete_comment',
479 conditions=dict(function=check_repo, method=["DELETE"]))
478 conditions=dict(function=check_repo, method=["DELETE"]))
480
479
481 rmap.connect('summary_home', '/{repo_name:.*}/summary',
480 rmap.connect('summary_home', '/{repo_name:.*}/summary',
482 controller='summary', conditions=dict(function=check_repo))
481 controller='summary', conditions=dict(function=check_repo))
483
482
484 rmap.connect('shortlog_home', '/{repo_name:.*}/shortlog',
483 rmap.connect('shortlog_home', '/{repo_name:.*}/shortlog',
485 controller='shortlog', conditions=dict(function=check_repo))
484 controller='shortlog', conditions=dict(function=check_repo))
486
485
487 rmap.connect('branches_home', '/{repo_name:.*}/branches',
486 rmap.connect('branches_home', '/{repo_name:.*}/branches',
488 controller='branches', conditions=dict(function=check_repo))
487 controller='branches', conditions=dict(function=check_repo))
489
488
490 rmap.connect('tags_home', '/{repo_name:.*}/tags',
489 rmap.connect('tags_home', '/{repo_name:.*}/tags',
491 controller='tags', conditions=dict(function=check_repo))
490 controller='tags', conditions=dict(function=check_repo))
492
491
493 rmap.connect('bookmarks_home', '/{repo_name:.*}/bookmarks',
492 rmap.connect('bookmarks_home', '/{repo_name:.*}/bookmarks',
494 controller='bookmarks', conditions=dict(function=check_repo))
493 controller='bookmarks', conditions=dict(function=check_repo))
495
494
496 rmap.connect('changelog_home', '/{repo_name:.*}/changelog',
495 rmap.connect('changelog_home', '/{repo_name:.*}/changelog',
497 controller='changelog', conditions=dict(function=check_repo))
496 controller='changelog', conditions=dict(function=check_repo))
498
497
499 rmap.connect('changelog_details', '/{repo_name:.*}/changelog_details/{cs}',
498 rmap.connect('changelog_details', '/{repo_name:.*}/changelog_details/{cs}',
500 controller='changelog', action='changelog_details',
499 controller='changelog', action='changelog_details',
501 conditions=dict(function=check_repo))
500 conditions=dict(function=check_repo))
502
501
503 rmap.connect('files_home', '/{repo_name:.*}/files/{revision}/{f_path:.*}',
502 rmap.connect('files_home', '/{repo_name:.*}/files/{revision}/{f_path:.*}',
504 controller='files', revision='tip', f_path='',
503 controller='files', revision='tip', f_path='',
505 conditions=dict(function=check_repo))
504 conditions=dict(function=check_repo))
506
505
507 rmap.connect('files_diff_home', '/{repo_name:.*}/diff/{f_path:.*}',
506 rmap.connect('files_diff_home', '/{repo_name:.*}/diff/{f_path:.*}',
508 controller='files', action='diff', revision='tip', f_path='',
507 controller='files', action='diff', revision='tip', f_path='',
509 conditions=dict(function=check_repo))
508 conditions=dict(function=check_repo))
510
509
511 rmap.connect('files_rawfile_home',
510 rmap.connect('files_rawfile_home',
512 '/{repo_name:.*}/rawfile/{revision}/{f_path:.*}',
511 '/{repo_name:.*}/rawfile/{revision}/{f_path:.*}',
513 controller='files', action='rawfile', revision='tip',
512 controller='files', action='rawfile', revision='tip',
514 f_path='', conditions=dict(function=check_repo))
513 f_path='', conditions=dict(function=check_repo))
515
514
516 rmap.connect('files_raw_home',
515 rmap.connect('files_raw_home',
517 '/{repo_name:.*}/raw/{revision}/{f_path:.*}',
516 '/{repo_name:.*}/raw/{revision}/{f_path:.*}',
518 controller='files', action='raw', revision='tip', f_path='',
517 controller='files', action='raw', revision='tip', f_path='',
519 conditions=dict(function=check_repo))
518 conditions=dict(function=check_repo))
520
519
521 rmap.connect('files_annotate_home',
520 rmap.connect('files_annotate_home',
522 '/{repo_name:.*}/annotate/{revision}/{f_path:.*}',
521 '/{repo_name:.*}/annotate/{revision}/{f_path:.*}',
523 controller='files', action='index', revision='tip',
522 controller='files', action='index', revision='tip',
524 f_path='', annotate=True, conditions=dict(function=check_repo))
523 f_path='', annotate=True, conditions=dict(function=check_repo))
525
524
526 rmap.connect('files_edit_home',
525 rmap.connect('files_edit_home',
527 '/{repo_name:.*}/edit/{revision}/{f_path:.*}',
526 '/{repo_name:.*}/edit/{revision}/{f_path:.*}',
528 controller='files', action='edit', revision='tip',
527 controller='files', action='edit', revision='tip',
529 f_path='', conditions=dict(function=check_repo))
528 f_path='', conditions=dict(function=check_repo))
530
529
531 rmap.connect('files_add_home',
530 rmap.connect('files_add_home',
532 '/{repo_name:.*}/add/{revision}/{f_path:.*}',
531 '/{repo_name:.*}/add/{revision}/{f_path:.*}',
533 controller='files', action='add', revision='tip',
532 controller='files', action='add', revision='tip',
534 f_path='', conditions=dict(function=check_repo))
533 f_path='', conditions=dict(function=check_repo))
535
534
536 rmap.connect('files_archive_home', '/{repo_name:.*}/archive/{fname}',
535 rmap.connect('files_archive_home', '/{repo_name:.*}/archive/{fname}',
537 controller='files', action='archivefile',
536 controller='files', action='archivefile',
538 conditions=dict(function=check_repo))
537 conditions=dict(function=check_repo))
539
538
540 rmap.connect('files_nodelist_home',
539 rmap.connect('files_nodelist_home',
541 '/{repo_name:.*}/nodelist/{revision}/{f_path:.*}',
540 '/{repo_name:.*}/nodelist/{revision}/{f_path:.*}',
542 controller='files', action='nodelist',
541 controller='files', action='nodelist',
543 conditions=dict(function=check_repo))
542 conditions=dict(function=check_repo))
544
543
545 rmap.connect('repo_settings_delete', '/{repo_name:.*}/settings',
544 rmap.connect('repo_settings_delete', '/{repo_name:.*}/settings',
546 controller='settings', action="delete",
545 controller='settings', action="delete",
547 conditions=dict(method=["DELETE"], function=check_repo))
546 conditions=dict(method=["DELETE"], function=check_repo))
548
547
549 rmap.connect('repo_settings_update', '/{repo_name:.*}/settings',
548 rmap.connect('repo_settings_update', '/{repo_name:.*}/settings',
550 controller='settings', action="update",
549 controller='settings', action="update",
551 conditions=dict(method=["PUT"], function=check_repo))
550 conditions=dict(method=["PUT"], function=check_repo))
552
551
553 rmap.connect('repo_settings_home', '/{repo_name:.*}/settings',
552 rmap.connect('repo_settings_home', '/{repo_name:.*}/settings',
554 controller='settings', action='index',
553 controller='settings', action='index',
555 conditions=dict(function=check_repo))
554 conditions=dict(function=check_repo))
556
555
557 rmap.connect('repo_fork_create_home', '/{repo_name:.*}/fork',
556 rmap.connect('repo_fork_create_home', '/{repo_name:.*}/fork',
558 controller='forks', action='fork_create',
557 controller='forks', action='fork_create',
559 conditions=dict(function=check_repo, method=["POST"]))
558 conditions=dict(function=check_repo, method=["POST"]))
560
559
561 rmap.connect('repo_fork_home', '/{repo_name:.*}/fork',
560 rmap.connect('repo_fork_home', '/{repo_name:.*}/fork',
562 controller='forks', action='fork',
561 controller='forks', action='fork',
563 conditions=dict(function=check_repo))
562 conditions=dict(function=check_repo))
564
563
565 rmap.connect('repo_forks_home', '/{repo_name:.*}/forks',
564 rmap.connect('repo_forks_home', '/{repo_name:.*}/forks',
566 controller='forks', action='forks',
565 controller='forks', action='forks',
567 conditions=dict(function=check_repo))
566 conditions=dict(function=check_repo))
568
567
569 rmap.connect('repo_followers_home', '/{repo_name:.*}/followers',
568 rmap.connect('repo_followers_home', '/{repo_name:.*}/followers',
570 controller='followers', action='followers',
569 controller='followers', action='followers',
571 conditions=dict(function=check_repo))
570 conditions=dict(function=check_repo))
572
571
573 return rmap
572 return rmap
@@ -1,317 +1,316
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 Repositories groups controller for RhodeCode
6 Repositories 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 redirect
33 from pylons.controllers.util import 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 from rhodecode.lib import helpers as h
38 from rhodecode.lib import helpers as h
39 from rhodecode.lib.auth import LoginRequired, HasPermissionAnyDecorator,\
39 from rhodecode.lib.auth import LoginRequired, HasPermissionAnyDecorator,\
40 HasReposGroupPermissionAnyDecorator
40 HasReposGroupPermissionAnyDecorator
41 from rhodecode.lib.base import BaseController, render
41 from rhodecode.lib.base import BaseController, render
42 from rhodecode.model.db import RepoGroup
42 from rhodecode.model.db import RepoGroup
43 from rhodecode.model.repos_group import ReposGroupModel
43 from rhodecode.model.repos_group import ReposGroupModel
44 from rhodecode.model.forms import ReposGroupForm
44 from rhodecode.model.forms import ReposGroupForm
45 from rhodecode.model.meta import Session
45 from rhodecode.model.meta import Session
46 from rhodecode.model.repo import RepoModel
46 from rhodecode.model.repo import RepoModel
47 from webob.exc import HTTPInternalServerError, HTTPNotFound
47 from webob.exc import HTTPInternalServerError, HTTPNotFound
48
48
49 log = logging.getLogger(__name__)
49 log = logging.getLogger(__name__)
50
50
51
51
52 class ReposGroupsController(BaseController):
52 class ReposGroupsController(BaseController):
53 """REST Controller styled on the Atom Publishing Protocol"""
53 """REST Controller styled on the Atom Publishing Protocol"""
54 # To properly map this controller, ensure your config/routing.py
54 # To properly map this controller, ensure your config/routing.py
55 # file has a resource setup:
55 # file has a resource setup:
56 # map.resource('repos_group', 'repos_groups')
56 # map.resource('repos_group', 'repos_groups')
57
57
58 @LoginRequired()
58 @LoginRequired()
59 def __before__(self):
59 def __before__(self):
60 super(ReposGroupsController, self).__before__()
60 super(ReposGroupsController, self).__before__()
61
61
62 def __load_defaults(self):
62 def __load_defaults(self):
63 c.repo_groups = RepoGroup.groups_choices()
63 c.repo_groups = RepoGroup.groups_choices()
64 c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups)
64 c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups)
65
65
66 repo_model = RepoModel()
66 repo_model = RepoModel()
67 c.users_array = repo_model.get_users_js()
67 c.users_array = repo_model.get_users_js()
68 c.users_groups_array = repo_model.get_users_groups_js()
68 c.users_groups_array = repo_model.get_users_groups_js()
69
69
70 def __load_data(self, group_id):
70 def __load_data(self, group_id):
71 """
71 """
72 Load defaults settings for edit, and update
72 Load defaults settings for edit, and update
73
73
74 :param group_id:
74 :param group_id:
75 """
75 """
76 self.__load_defaults()
76 self.__load_defaults()
77
77
78 repo_group = RepoGroup.get_or_404(group_id)
78 repo_group = RepoGroup.get_or_404(group_id)
79
79
80 data = repo_group.get_dict()
80 data = repo_group.get_dict()
81
81
82 data['group_name'] = repo_group.name
82 data['group_name'] = repo_group.name
83
83
84 # fill repository users
84 # fill repository users
85 for p in repo_group.repo_group_to_perm:
85 for p in repo_group.repo_group_to_perm:
86 data.update({'u_perm_%s' % p.user.username:
86 data.update({'u_perm_%s' % p.user.username:
87 p.permission.permission_name})
87 p.permission.permission_name})
88
88
89 # fill repository groups
89 # fill repository groups
90 for p in repo_group.users_group_to_perm:
90 for p in repo_group.users_group_to_perm:
91 data.update({'g_perm_%s' % p.users_group.users_group_name:
91 data.update({'g_perm_%s' % p.users_group.users_group_name:
92 p.permission.permission_name})
92 p.permission.permission_name})
93
93
94 return data
94 return data
95
95
96 @HasPermissionAnyDecorator('hg.admin')
96 @HasPermissionAnyDecorator('hg.admin')
97 def index(self, format='html'):
97 def index(self, format='html'):
98 """GET /repos_groups: All items in the collection"""
98 """GET /repos_groups: All items in the collection"""
99 # url('repos_groups')
99 # url('repos_groups')
100 sk = lambda g: g.parents[0].group_name if g.parents else g.group_name
100 sk = lambda g: g.parents[0].group_name if g.parents else g.group_name
101 c.groups = sorted(RepoGroup.query().all(), key=sk)
101 c.groups = sorted(RepoGroup.query().all(), key=sk)
102 return render('admin/repos_groups/repos_groups_show.html')
102 return render('admin/repos_groups/repos_groups_show.html')
103
103
104 @HasPermissionAnyDecorator('hg.admin')
104 @HasPermissionAnyDecorator('hg.admin')
105 def create(self):
105 def create(self):
106 """POST /repos_groups: Create a new item"""
106 """POST /repos_groups: Create a new item"""
107 # url('repos_groups')
107 # url('repos_groups')
108 self.__load_defaults()
108 self.__load_defaults()
109 repos_group_form = ReposGroupForm(available_groups =
109 repos_group_form = ReposGroupForm(available_groups =
110 c.repo_groups_choices)()
110 c.repo_groups_choices)()
111 try:
111 try:
112 form_result = repos_group_form.to_python(dict(request.POST))
112 form_result = repos_group_form.to_python(dict(request.POST))
113 ReposGroupModel().create(
113 ReposGroupModel().create(
114 group_name=form_result['group_name'],
114 group_name=form_result['group_name'],
115 group_description=form_result['group_description'],
115 group_description=form_result['group_description'],
116 parent=form_result['group_parent_id']
116 parent=form_result['group_parent_id']
117 )
117 )
118 Session.commit()
118 Session.commit()
119 h.flash(_('created repos group %s') \
119 h.flash(_('created repos group %s') \
120 % form_result['group_name'], category='success')
120 % form_result['group_name'], category='success')
121 #TODO: in futureaction_logger(, '', '', '', self.sa)
121 #TODO: in futureaction_logger(, '', '', '', self.sa)
122 except formencode.Invalid, errors:
122 except formencode.Invalid, errors:
123
123
124 return htmlfill.render(
124 return htmlfill.render(
125 render('admin/repos_groups/repos_groups_add.html'),
125 render('admin/repos_groups/repos_groups_add.html'),
126 defaults=errors.value,
126 defaults=errors.value,
127 errors=errors.error_dict or {},
127 errors=errors.error_dict or {},
128 prefix_error=False,
128 prefix_error=False,
129 encoding="UTF-8")
129 encoding="UTF-8")
130 except Exception:
130 except Exception:
131 log.error(traceback.format_exc())
131 log.error(traceback.format_exc())
132 h.flash(_('error occurred during creation of repos group %s') \
132 h.flash(_('error occurred during creation of repos group %s') \
133 % request.POST.get('group_name'), category='error')
133 % request.POST.get('group_name'), category='error')
134
134
135 return redirect(url('repos_groups'))
135 return redirect(url('repos_groups'))
136
136
137 @HasPermissionAnyDecorator('hg.admin')
137 @HasPermissionAnyDecorator('hg.admin')
138 def new(self, format='html'):
138 def new(self, format='html'):
139 """GET /repos_groups/new: Form to create a new item"""
139 """GET /repos_groups/new: Form to create a new item"""
140 # url('new_repos_group')
140 # url('new_repos_group')
141 self.__load_defaults()
141 self.__load_defaults()
142 return render('admin/repos_groups/repos_groups_add.html')
142 return render('admin/repos_groups/repos_groups_add.html')
143
143
144 @HasPermissionAnyDecorator('hg.admin')
144 @HasPermissionAnyDecorator('hg.admin')
145 def update(self, id):
145 def update(self, id):
146 """PUT /repos_groups/id: Update an existing item"""
146 """PUT /repos_groups/id: Update an existing item"""
147 # Forms posted to this method should contain a hidden field:
147 # Forms posted to this method should contain a hidden field:
148 # <input type="hidden" name="_method" value="PUT" />
148 # <input type="hidden" name="_method" value="PUT" />
149 # Or using helpers:
149 # Or using helpers:
150 # h.form(url('repos_group', id=ID),
150 # h.form(url('repos_group', id=ID),
151 # method='put')
151 # method='put')
152 # url('repos_group', id=ID)
152 # url('repos_group', id=ID)
153
153
154 self.__load_defaults()
154 self.__load_defaults()
155 c.repos_group = RepoGroup.get(id)
155 c.repos_group = RepoGroup.get(id)
156
156
157 repos_group_form = ReposGroupForm(
157 repos_group_form = ReposGroupForm(
158 edit=True,
158 edit=True,
159 old_data=c.repos_group.get_dict(),
159 old_data=c.repos_group.get_dict(),
160 available_groups=c.repo_groups_choices
160 available_groups=c.repo_groups_choices
161 )()
161 )()
162 try:
162 try:
163 form_result = repos_group_form.to_python(dict(request.POST))
163 form_result = repos_group_form.to_python(dict(request.POST))
164 ReposGroupModel().update(id, form_result)
164 ReposGroupModel().update(id, form_result)
165 Session.commit()
165 Session.commit()
166 h.flash(_('updated repos group %s') \
166 h.flash(_('updated repos group %s') \
167 % form_result['group_name'], category='success')
167 % form_result['group_name'], category='success')
168 #TODO: in futureaction_logger(, '', '', '', self.sa)
168 #TODO: in futureaction_logger(, '', '', '', self.sa)
169 except formencode.Invalid, errors:
169 except formencode.Invalid, errors:
170
170
171 return htmlfill.render(
171 return htmlfill.render(
172 render('admin/repos_groups/repos_groups_edit.html'),
172 render('admin/repos_groups/repos_groups_edit.html'),
173 defaults=errors.value,
173 defaults=errors.value,
174 errors=errors.error_dict or {},
174 errors=errors.error_dict or {},
175 prefix_error=False,
175 prefix_error=False,
176 encoding="UTF-8")
176 encoding="UTF-8")
177 except Exception:
177 except Exception:
178 log.error(traceback.format_exc())
178 log.error(traceback.format_exc())
179 h.flash(_('error occurred during update of repos group %s') \
179 h.flash(_('error occurred during update of repos group %s') \
180 % request.POST.get('group_name'), category='error')
180 % request.POST.get('group_name'), category='error')
181
181
182 return redirect(url('repos_groups'))
182 return redirect(url('repos_groups'))
183
183
184 @HasPermissionAnyDecorator('hg.admin')
184 @HasPermissionAnyDecorator('hg.admin')
185 def delete(self, id):
185 def delete(self, id):
186 """DELETE /repos_groups/id: Delete an existing item"""
186 """DELETE /repos_groups/id: Delete an existing item"""
187 # Forms posted to this method should contain a hidden field:
187 # Forms posted to this method should contain a hidden field:
188 # <input type="hidden" name="_method" value="DELETE" />
188 # <input type="hidden" name="_method" value="DELETE" />
189 # Or using helpers:
189 # Or using helpers:
190 # h.form(url('repos_group', id=ID),
190 # h.form(url('repos_group', id=ID),
191 # method='delete')
191 # method='delete')
192 # url('repos_group', id=ID)
192 # url('repos_group', id=ID)
193
193
194 gr = RepoGroup.get(id)
194 gr = RepoGroup.get(id)
195 repos = gr.repositories.all()
195 repos = gr.repositories.all()
196 if repos:
196 if repos:
197 h.flash(_('This group contains %s repositores and cannot be '
197 h.flash(_('This group contains %s repositores and cannot be '
198 'deleted') % len(repos),
198 'deleted') % len(repos),
199 category='error')
199 category='error')
200 return redirect(url('repos_groups'))
200 return redirect(url('repos_groups'))
201
201
202 try:
202 try:
203 ReposGroupModel().delete(id)
203 ReposGroupModel().delete(id)
204 Session.commit()
204 Session.commit()
205 h.flash(_('removed repos group %s') % gr.group_name, category='success')
205 h.flash(_('removed repos group %s') % gr.group_name, category='success')
206 #TODO: in future action_logger(, '', '', '', self.sa)
206 #TODO: in future action_logger(, '', '', '', self.sa)
207 except IntegrityError, e:
207 except IntegrityError, e:
208 if e.message.find('groups_group_parent_id_fkey') != -1:
208 if e.message.find('groups_group_parent_id_fkey') != -1:
209 log.error(traceback.format_exc())
209 log.error(traceback.format_exc())
210 h.flash(_('Cannot delete this group it still contains '
210 h.flash(_('Cannot delete this group it still contains '
211 'subgroups'),
211 'subgroups'),
212 category='warning')
212 category='warning')
213 else:
213 else:
214 log.error(traceback.format_exc())
214 log.error(traceback.format_exc())
215 h.flash(_('error occurred during deletion of repos '
215 h.flash(_('error occurred during deletion of repos '
216 'group %s') % gr.group_name, category='error')
216 'group %s') % gr.group_name, category='error')
217
217
218 except Exception:
218 except Exception:
219 log.error(traceback.format_exc())
219 log.error(traceback.format_exc())
220 h.flash(_('error occurred during deletion of repos '
220 h.flash(_('error occurred during deletion of repos '
221 'group %s') % gr.group_name, category='error')
221 'group %s') % gr.group_name, category='error')
222
222
223 return redirect(url('repos_groups'))
223 return redirect(url('repos_groups'))
224
224
225 @HasReposGroupPermissionAnyDecorator('group.admin')
225 @HasReposGroupPermissionAnyDecorator('group.admin')
226 def delete_repos_group_user_perm(self, group_name):
226 def delete_repos_group_user_perm(self, group_name):
227 """
227 """
228 DELETE an existing repositories group permission user
228 DELETE an existing repositories group permission user
229
229
230 :param group_name:
230 :param group_name:
231 """
231 """
232
232
233 try:
233 try:
234 ReposGroupModel().revoke_user_permission(
234 ReposGroupModel().revoke_user_permission(
235 repos_group=group_name, user=request.POST['user_id']
235 repos_group=group_name, user=request.POST['user_id']
236 )
236 )
237 Session.commit()
237 Session.commit()
238 except Exception:
238 except Exception:
239 log.error(traceback.format_exc())
239 log.error(traceback.format_exc())
240 h.flash(_('An error occurred during deletion of group user'),
240 h.flash(_('An error occurred during deletion of group user'),
241 category='error')
241 category='error')
242 raise HTTPInternalServerError()
242 raise HTTPInternalServerError()
243
243
244 @HasReposGroupPermissionAnyDecorator('group.admin')
244 @HasReposGroupPermissionAnyDecorator('group.admin')
245 def delete_repos_group_users_group_perm(self, group_name):
245 def delete_repos_group_users_group_perm(self, group_name):
246 """
246 """
247 DELETE an existing repositories group permission users group
247 DELETE an existing repositories group permission users group
248
248
249 :param group_name:
249 :param group_name:
250 """
250 """
251
251
252 try:
252 try:
253 ReposGroupModel().revoke_users_group_permission(
253 ReposGroupModel().revoke_users_group_permission(
254 repos_group=group_name,
254 repos_group=group_name,
255 group_name=request.POST['users_group_id']
255 group_name=request.POST['users_group_id']
256 )
256 )
257 Session.commit()
257 Session.commit()
258 except Exception:
258 except Exception:
259 log.error(traceback.format_exc())
259 log.error(traceback.format_exc())
260 h.flash(_('An error occurred during deletion of group'
260 h.flash(_('An error occurred during deletion of group'
261 ' users groups'),
261 ' users groups'),
262 category='error')
262 category='error')
263 raise HTTPInternalServerError()
263 raise HTTPInternalServerError()
264
264
265 def show_by_name(self, group_name):
265 def show_by_name(self, group_name):
266 """
266 """
267 This is a proxy that does a lookup group_name -> id, and shows
267 This is a proxy that does a lookup group_name -> id, and shows
268 the group by id view instead
268 the group by id view instead
269 """
269 """
270 group_name = group_name.rstrip('/')
270 group_name = group_name.rstrip('/')
271 id_ = RepoGroup.get_by_group_name(group_name)
271 id_ = RepoGroup.get_by_group_name(group_name)
272 if id_:
272 if id_:
273 return self.show(id_.group_id)
273 return self.show(id_.group_id)
274 raise HTTPNotFound
274 raise HTTPNotFound
275
275
276 @HasReposGroupPermissionAnyDecorator('group.read', 'group.write',
276 @HasReposGroupPermissionAnyDecorator('group.read', 'group.write',
277 'group.admin')
277 'group.admin')
278 def show(self, id, format='html'):
278 def show(self, id, format='html'):
279 """GET /repos_groups/id: Show a specific item"""
279 """GET /repos_groups/id: Show a specific item"""
280 # url('repos_group', id=ID)
280 # url('repos_group', id=ID)
281
281
282 c.group = RepoGroup.get_or_404(id)
282 c.group = RepoGroup.get_or_404(id)
283
283
284 c.group_repos = c.group.repositories.all()
284 c.group_repos = c.group.repositories.all()
285
285
286 #overwrite our cached list with current filter
286 #overwrite our cached list with current filter
287 gr_filter = c.group_repos
287 gr_filter = c.group_repos
288 c.cached_repo_list = self.scm_model.get_repos(all_repos=gr_filter)
288 c.cached_repo_list = self.scm_model.get_repos(all_repos=gr_filter)
289
289
290 c.repos_list = c.cached_repo_list
290 c.repos_list = c.cached_repo_list
291
291
292 c.repo_cnt = 0
292 c.repo_cnt = 0
293
293
294 c.groups = self.sa.query(RepoGroup).order_by(RepoGroup.group_name)\
294 c.groups = self.sa.query(RepoGroup).order_by(RepoGroup.group_name)\
295 .filter(RepoGroup.group_parent_id == id).all()
295 .filter(RepoGroup.group_parent_id == id).all()
296
296
297 return render('admin/repos_groups/repos_groups.html')
297 return render('admin/repos_groups/repos_groups.html')
298
298
299 @HasPermissionAnyDecorator('hg.admin')
299 @HasPermissionAnyDecorator('hg.admin')
300 def edit(self, id, format='html'):
300 def edit(self, id, format='html'):
301 """GET /repos_groups/id/edit: Form to edit an existing item"""
301 """GET /repos_groups/id/edit: Form to edit an existing item"""
302 # url('edit_repos_group', id=ID)
302 # url('edit_repos_group', id=ID)
303
303
304 id_ = int(id)
304 c.repos_group = ReposGroupModel()._get_repos_group(id)
305
305 defaults = self.__load_data(c.repos_group.group_id)
306 c.repos_group = RepoGroup.get(id_)
307 defaults = self.__load_data(id_)
308
306
309 # we need to exclude this group from the group list for editing
307 # we need to exclude this group from the group list for editing
310 c.repo_groups = filter(lambda x: x[0] != id_, c.repo_groups)
308 c.repo_groups = filter(lambda x: x[0] != c.repos_group.group_id,
309 c.repo_groups)
311
310
312 return htmlfill.render(
311 return htmlfill.render(
313 render('admin/repos_groups/repos_groups_edit.html'),
312 render('admin/repos_groups/repos_groups_edit.html'),
314 defaults=defaults,
313 defaults=defaults,
315 encoding="UTF-8",
314 encoding="UTF-8",
316 force_defaults=False
315 force_defaults=False
317 )
316 )
@@ -1,523 +1,523
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.model.repo
3 rhodecode.model.repo
4 ~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~
5
5
6 Repository model for rhodecode
6 Repository model for rhodecode
7
7
8 :created_on: Jun 5, 2010
8 :created_on: Jun 5, 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 from __future__ import with_statement
25 from __future__ import with_statement
26 import os
26 import os
27 import shutil
27 import shutil
28 import logging
28 import logging
29 import traceback
29 import traceback
30 from datetime import datetime
30 from datetime import datetime
31
31
32 from rhodecode.lib.vcs.backends import get_backend
32 from rhodecode.lib.vcs.backends import get_backend
33 from rhodecode.lib.compat import json
33 from rhodecode.lib.compat import json
34 from rhodecode.lib.utils2 import LazyProperty, safe_str, safe_unicode
34 from rhodecode.lib.utils2 import LazyProperty, safe_str, safe_unicode
35 from rhodecode.lib.caching_query import FromCache
35 from rhodecode.lib.caching_query import FromCache
36 from rhodecode.lib.hooks import log_create_repository
36 from rhodecode.lib.hooks import log_create_repository
37
37
38 from rhodecode.model import BaseModel
38 from rhodecode.model import BaseModel
39 from rhodecode.model.db import Repository, UserRepoToPerm, User, Permission, \
39 from rhodecode.model.db import Repository, UserRepoToPerm, User, Permission, \
40 Statistics, UsersGroup, UsersGroupRepoToPerm, RhodeCodeUi, RepoGroup
40 Statistics, UsersGroup, UsersGroupRepoToPerm, RhodeCodeUi, RepoGroup
41 from rhodecode.lib import helpers as h
41 from rhodecode.lib import helpers as h
42
42
43
43
44 log = logging.getLogger(__name__)
44 log = logging.getLogger(__name__)
45
45
46
46
47 class RepoModel(BaseModel):
47 class RepoModel(BaseModel):
48
48
49 cls = Repository
49 cls = Repository
50 URL_SEPARATOR = Repository.url_sep()
50 URL_SEPARATOR = Repository.url_sep()
51
51
52 def __get_users_group(self, users_group):
52 def __get_users_group(self, users_group):
53 return self._get_instance(UsersGroup, users_group,
53 return self._get_instance(UsersGroup, users_group,
54 callback=UsersGroup.get_by_group_name)
54 callback=UsersGroup.get_by_group_name)
55
55
56 def __get_repos_group(self, repos_group):
56 def _get_repos_group(self, repos_group):
57 return self._get_instance(RepoGroup, repos_group,
57 return self._get_instance(RepoGroup, repos_group,
58 callback=RepoGroup.get_by_group_name)
58 callback=RepoGroup.get_by_group_name)
59
59
60 @LazyProperty
60 @LazyProperty
61 def repos_path(self):
61 def repos_path(self):
62 """
62 """
63 Get's the repositories root path from database
63 Get's the repositories root path from database
64 """
64 """
65
65
66 q = self.sa.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key == '/').one()
66 q = self.sa.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key == '/').one()
67 return q.ui_value
67 return q.ui_value
68
68
69 def get(self, repo_id, cache=False):
69 def get(self, repo_id, cache=False):
70 repo = self.sa.query(Repository)\
70 repo = self.sa.query(Repository)\
71 .filter(Repository.repo_id == repo_id)
71 .filter(Repository.repo_id == repo_id)
72
72
73 if cache:
73 if cache:
74 repo = repo.options(FromCache("sql_cache_short",
74 repo = repo.options(FromCache("sql_cache_short",
75 "get_repo_%s" % repo_id))
75 "get_repo_%s" % repo_id))
76 return repo.scalar()
76 return repo.scalar()
77
77
78 def get_repo(self, repository):
78 def get_repo(self, repository):
79 return self._get_repo(repository)
79 return self._get_repo(repository)
80
80
81 def get_by_repo_name(self, repo_name, cache=False):
81 def get_by_repo_name(self, repo_name, cache=False):
82 repo = self.sa.query(Repository)\
82 repo = self.sa.query(Repository)\
83 .filter(Repository.repo_name == repo_name)
83 .filter(Repository.repo_name == repo_name)
84
84
85 if cache:
85 if cache:
86 repo = repo.options(FromCache("sql_cache_short",
86 repo = repo.options(FromCache("sql_cache_short",
87 "get_repo_%s" % repo_name))
87 "get_repo_%s" % repo_name))
88 return repo.scalar()
88 return repo.scalar()
89
89
90 def get_users_js(self):
90 def get_users_js(self):
91 users = self.sa.query(User).filter(User.active == True).all()
91 users = self.sa.query(User).filter(User.active == True).all()
92 return json.dumps([
92 return json.dumps([
93 {
93 {
94 'id': u.user_id,
94 'id': u.user_id,
95 'fname': u.name,
95 'fname': u.name,
96 'lname': u.lastname,
96 'lname': u.lastname,
97 'nname': u.username,
97 'nname': u.username,
98 'gravatar_lnk': h.gravatar_url(u.email, 14)
98 'gravatar_lnk': h.gravatar_url(u.email, 14)
99 } for u in users]
99 } for u in users]
100 )
100 )
101
101
102 def get_users_groups_js(self):
102 def get_users_groups_js(self):
103 users_groups = self.sa.query(UsersGroup)\
103 users_groups = self.sa.query(UsersGroup)\
104 .filter(UsersGroup.users_group_active == True).all()
104 .filter(UsersGroup.users_group_active == True).all()
105
105
106 return json.dumps([
106 return json.dumps([
107 {
107 {
108 'id': gr.users_group_id,
108 'id': gr.users_group_id,
109 'grname': gr.users_group_name,
109 'grname': gr.users_group_name,
110 'grmembers': len(gr.members),
110 'grmembers': len(gr.members),
111 } for gr in users_groups]
111 } for gr in users_groups]
112 )
112 )
113
113
114 def _get_defaults(self, repo_name):
114 def _get_defaults(self, repo_name):
115 """
115 """
116 Get's information about repository, and returns a dict for
116 Get's information about repository, and returns a dict for
117 usage in forms
117 usage in forms
118
118
119 :param repo_name:
119 :param repo_name:
120 """
120 """
121
121
122 repo_info = Repository.get_by_repo_name(repo_name)
122 repo_info = Repository.get_by_repo_name(repo_name)
123
123
124 if repo_info is None:
124 if repo_info is None:
125 return None
125 return None
126
126
127 defaults = repo_info.get_dict()
127 defaults = repo_info.get_dict()
128 group, repo_name = repo_info.groups_and_repo
128 group, repo_name = repo_info.groups_and_repo
129 defaults['repo_name'] = repo_name
129 defaults['repo_name'] = repo_name
130 defaults['repo_group'] = getattr(group[-1] if group else None,
130 defaults['repo_group'] = getattr(group[-1] if group else None,
131 'group_id', None)
131 'group_id', None)
132
132
133 # fill owner
133 # fill owner
134 if repo_info.user:
134 if repo_info.user:
135 defaults.update({'user': repo_info.user.username})
135 defaults.update({'user': repo_info.user.username})
136 else:
136 else:
137 replacement_user = User.query().filter(User.admin ==
137 replacement_user = User.query().filter(User.admin ==
138 True).first().username
138 True).first().username
139 defaults.update({'user': replacement_user})
139 defaults.update({'user': replacement_user})
140
140
141 # fill repository users
141 # fill repository users
142 for p in repo_info.repo_to_perm:
142 for p in repo_info.repo_to_perm:
143 defaults.update({'u_perm_%s' % p.user.username:
143 defaults.update({'u_perm_%s' % p.user.username:
144 p.permission.permission_name})
144 p.permission.permission_name})
145
145
146 # fill repository groups
146 # fill repository groups
147 for p in repo_info.users_group_to_perm:
147 for p in repo_info.users_group_to_perm:
148 defaults.update({'g_perm_%s' % p.users_group.users_group_name:
148 defaults.update({'g_perm_%s' % p.users_group.users_group_name:
149 p.permission.permission_name})
149 p.permission.permission_name})
150
150
151 return defaults
151 return defaults
152
152
153 def update(self, repo_name, form_data):
153 def update(self, repo_name, form_data):
154 try:
154 try:
155 cur_repo = self.get_by_repo_name(repo_name, cache=False)
155 cur_repo = self.get_by_repo_name(repo_name, cache=False)
156
156
157 # update permissions
157 # update permissions
158 for member, perm, member_type in form_data['perms_updates']:
158 for member, perm, member_type in form_data['perms_updates']:
159 if member_type == 'user':
159 if member_type == 'user':
160 # this updates existing one
160 # this updates existing one
161 RepoModel().grant_user_permission(
161 RepoModel().grant_user_permission(
162 repo=cur_repo, user=member, perm=perm
162 repo=cur_repo, user=member, perm=perm
163 )
163 )
164 else:
164 else:
165 RepoModel().grant_users_group_permission(
165 RepoModel().grant_users_group_permission(
166 repo=cur_repo, group_name=member, perm=perm
166 repo=cur_repo, group_name=member, perm=perm
167 )
167 )
168 # set new permissions
168 # set new permissions
169 for member, perm, member_type in form_data['perms_new']:
169 for member, perm, member_type in form_data['perms_new']:
170 if member_type == 'user':
170 if member_type == 'user':
171 RepoModel().grant_user_permission(
171 RepoModel().grant_user_permission(
172 repo=cur_repo, user=member, perm=perm
172 repo=cur_repo, user=member, perm=perm
173 )
173 )
174 else:
174 else:
175 RepoModel().grant_users_group_permission(
175 RepoModel().grant_users_group_permission(
176 repo=cur_repo, group_name=member, perm=perm
176 repo=cur_repo, group_name=member, perm=perm
177 )
177 )
178
178
179 # update current repo
179 # update current repo
180 for k, v in form_data.items():
180 for k, v in form_data.items():
181 if k == 'user':
181 if k == 'user':
182 cur_repo.user = User.get_by_username(v)
182 cur_repo.user = User.get_by_username(v)
183 elif k == 'repo_name':
183 elif k == 'repo_name':
184 pass
184 pass
185 elif k == 'repo_group':
185 elif k == 'repo_group':
186 cur_repo.group = RepoGroup.get(v)
186 cur_repo.group = RepoGroup.get(v)
187
187
188 else:
188 else:
189 setattr(cur_repo, k, v)
189 setattr(cur_repo, k, v)
190
190
191 new_name = cur_repo.get_new_name(form_data['repo_name'])
191 new_name = cur_repo.get_new_name(form_data['repo_name'])
192 cur_repo.repo_name = new_name
192 cur_repo.repo_name = new_name
193
193
194 self.sa.add(cur_repo)
194 self.sa.add(cur_repo)
195
195
196 if repo_name != new_name:
196 if repo_name != new_name:
197 # rename repository
197 # rename repository
198 self.__rename_repo(old=repo_name, new=new_name)
198 self.__rename_repo(old=repo_name, new=new_name)
199
199
200 return cur_repo
200 return cur_repo
201 except:
201 except:
202 log.error(traceback.format_exc())
202 log.error(traceback.format_exc())
203 raise
203 raise
204
204
205 def create_repo(self, repo_name, repo_type, description, owner,
205 def create_repo(self, repo_name, repo_type, description, owner,
206 private=False, clone_uri=None, repos_group=None,
206 private=False, clone_uri=None, repos_group=None,
207 landing_rev='tip', just_db=False, fork_of=None,
207 landing_rev='tip', just_db=False, fork_of=None,
208 copy_fork_permissions=False):
208 copy_fork_permissions=False):
209 from rhodecode.model.scm import ScmModel
209 from rhodecode.model.scm import ScmModel
210
210
211 owner = self._get_user(owner)
211 owner = self._get_user(owner)
212 fork_of = self._get_repo(fork_of)
212 fork_of = self._get_repo(fork_of)
213 repos_group = self.__get_repos_group(repos_group)
213 repos_group = self._get_repos_group(repos_group)
214 try:
214 try:
215
215
216 # repo name is just a name of repository
216 # repo name is just a name of repository
217 # while repo_name_full is a full qualified name that is combined
217 # while repo_name_full is a full qualified name that is combined
218 # with name and path of group
218 # with name and path of group
219 repo_name_full = repo_name
219 repo_name_full = repo_name
220 repo_name = repo_name.split(self.URL_SEPARATOR)[-1]
220 repo_name = repo_name.split(self.URL_SEPARATOR)[-1]
221
221
222 new_repo = Repository()
222 new_repo = Repository()
223 new_repo.enable_statistics = False
223 new_repo.enable_statistics = False
224 new_repo.repo_name = repo_name_full
224 new_repo.repo_name = repo_name_full
225 new_repo.repo_type = repo_type
225 new_repo.repo_type = repo_type
226 new_repo.user = owner
226 new_repo.user = owner
227 new_repo.group = repos_group
227 new_repo.group = repos_group
228 new_repo.description = description or repo_name
228 new_repo.description = description or repo_name
229 new_repo.private = private
229 new_repo.private = private
230 new_repo.clone_uri = clone_uri
230 new_repo.clone_uri = clone_uri
231 new_repo.landing_rev = landing_rev
231 new_repo.landing_rev = landing_rev
232
232
233 if fork_of:
233 if fork_of:
234 parent_repo = fork_of
234 parent_repo = fork_of
235 new_repo.fork = parent_repo
235 new_repo.fork = parent_repo
236
236
237 self.sa.add(new_repo)
237 self.sa.add(new_repo)
238
238
239 def _create_default_perms():
239 def _create_default_perms():
240 # create default permission
240 # create default permission
241 repo_to_perm = UserRepoToPerm()
241 repo_to_perm = UserRepoToPerm()
242 default = 'repository.read'
242 default = 'repository.read'
243 for p in User.get_by_username('default').user_perms:
243 for p in User.get_by_username('default').user_perms:
244 if p.permission.permission_name.startswith('repository.'):
244 if p.permission.permission_name.startswith('repository.'):
245 default = p.permission.permission_name
245 default = p.permission.permission_name
246 break
246 break
247
247
248 default_perm = 'repository.none' if private else default
248 default_perm = 'repository.none' if private else default
249
249
250 repo_to_perm.permission_id = self.sa.query(Permission)\
250 repo_to_perm.permission_id = self.sa.query(Permission)\
251 .filter(Permission.permission_name == default_perm)\
251 .filter(Permission.permission_name == default_perm)\
252 .one().permission_id
252 .one().permission_id
253
253
254 repo_to_perm.repository = new_repo
254 repo_to_perm.repository = new_repo
255 repo_to_perm.user_id = User.get_by_username('default').user_id
255 repo_to_perm.user_id = User.get_by_username('default').user_id
256
256
257 self.sa.add(repo_to_perm)
257 self.sa.add(repo_to_perm)
258
258
259 if fork_of:
259 if fork_of:
260 if copy_fork_permissions:
260 if copy_fork_permissions:
261 repo = fork_of
261 repo = fork_of
262 user_perms = UserRepoToPerm.query()\
262 user_perms = UserRepoToPerm.query()\
263 .filter(UserRepoToPerm.repository == repo).all()
263 .filter(UserRepoToPerm.repository == repo).all()
264 group_perms = UsersGroupRepoToPerm.query()\
264 group_perms = UsersGroupRepoToPerm.query()\
265 .filter(UsersGroupRepoToPerm.repository == repo).all()
265 .filter(UsersGroupRepoToPerm.repository == repo).all()
266
266
267 for perm in user_perms:
267 for perm in user_perms:
268 UserRepoToPerm.create(perm.user, new_repo,
268 UserRepoToPerm.create(perm.user, new_repo,
269 perm.permission)
269 perm.permission)
270
270
271 for perm in group_perms:
271 for perm in group_perms:
272 UsersGroupRepoToPerm.create(perm.users_group, new_repo,
272 UsersGroupRepoToPerm.create(perm.users_group, new_repo,
273 perm.permission)
273 perm.permission)
274 else:
274 else:
275 _create_default_perms()
275 _create_default_perms()
276 else:
276 else:
277 _create_default_perms()
277 _create_default_perms()
278
278
279 if not just_db:
279 if not just_db:
280 self.__create_repo(repo_name, repo_type,
280 self.__create_repo(repo_name, repo_type,
281 repos_group,
281 repos_group,
282 clone_uri)
282 clone_uri)
283 log_create_repository(new_repo.get_dict(),
283 log_create_repository(new_repo.get_dict(),
284 created_by=owner.username)
284 created_by=owner.username)
285
285
286 # now automatically start following this repository as owner
286 # now automatically start following this repository as owner
287 ScmModel(self.sa).toggle_following_repo(new_repo.repo_id,
287 ScmModel(self.sa).toggle_following_repo(new_repo.repo_id,
288 owner.user_id)
288 owner.user_id)
289 return new_repo
289 return new_repo
290 except:
290 except:
291 log.error(traceback.format_exc())
291 log.error(traceback.format_exc())
292 raise
292 raise
293
293
294 def create(self, form_data, cur_user, just_db=False, fork=None):
294 def create(self, form_data, cur_user, just_db=False, fork=None):
295
295
296 repo_name = form_data['repo_name_full']
296 repo_name = form_data['repo_name_full']
297 repo_type = form_data['repo_type']
297 repo_type = form_data['repo_type']
298 description = form_data['description']
298 description = form_data['description']
299 owner = cur_user
299 owner = cur_user
300 private = form_data['private']
300 private = form_data['private']
301 clone_uri = form_data.get('clone_uri')
301 clone_uri = form_data.get('clone_uri')
302 repos_group = form_data['repo_group']
302 repos_group = form_data['repo_group']
303 landing_rev = form_data['landing_rev']
303 landing_rev = form_data['landing_rev']
304 copy_fork_permissions = form_data.get('copy_permissions')
304 copy_fork_permissions = form_data.get('copy_permissions')
305 fork_of = form_data.get('fork_parent_id')
305 fork_of = form_data.get('fork_parent_id')
306 return self.create_repo(
306 return self.create_repo(
307 repo_name, repo_type, description, owner, private, clone_uri,
307 repo_name, repo_type, description, owner, private, clone_uri,
308 repos_group, landing_rev, just_db, fork_of, copy_fork_permissions
308 repos_group, landing_rev, just_db, fork_of, copy_fork_permissions
309 )
309 )
310
310
311 def create_fork(self, form_data, cur_user):
311 def create_fork(self, form_data, cur_user):
312 """
312 """
313 Simple wrapper into executing celery task for fork creation
313 Simple wrapper into executing celery task for fork creation
314
314
315 :param form_data:
315 :param form_data:
316 :param cur_user:
316 :param cur_user:
317 """
317 """
318 from rhodecode.lib.celerylib import tasks, run_task
318 from rhodecode.lib.celerylib import tasks, run_task
319 run_task(tasks.create_repo_fork, form_data, cur_user)
319 run_task(tasks.create_repo_fork, form_data, cur_user)
320
320
321 def delete(self, repo):
321 def delete(self, repo):
322 repo = self._get_repo(repo)
322 repo = self._get_repo(repo)
323 if repo:
323 if repo:
324 try:
324 try:
325 self.sa.delete(repo)
325 self.sa.delete(repo)
326 self.__delete_repo(repo)
326 self.__delete_repo(repo)
327 except:
327 except:
328 log.error(traceback.format_exc())
328 log.error(traceback.format_exc())
329 raise
329 raise
330
330
331 def grant_user_permission(self, repo, user, perm):
331 def grant_user_permission(self, repo, user, perm):
332 """
332 """
333 Grant permission for user on given repository, or update existing one
333 Grant permission for user on given repository, or update existing one
334 if found
334 if found
335
335
336 :param repo: Instance of Repository, repository_id, or repository name
336 :param repo: Instance of Repository, repository_id, or repository name
337 :param user: Instance of User, user_id or username
337 :param user: Instance of User, user_id or username
338 :param perm: Instance of Permission, or permission_name
338 :param perm: Instance of Permission, or permission_name
339 """
339 """
340 user = self._get_user(user)
340 user = self._get_user(user)
341 repo = self._get_repo(repo)
341 repo = self._get_repo(repo)
342 permission = self._get_perm(perm)
342 permission = self._get_perm(perm)
343
343
344 # check if we have that permission already
344 # check if we have that permission already
345 obj = self.sa.query(UserRepoToPerm)\
345 obj = self.sa.query(UserRepoToPerm)\
346 .filter(UserRepoToPerm.user == user)\
346 .filter(UserRepoToPerm.user == user)\
347 .filter(UserRepoToPerm.repository == repo)\
347 .filter(UserRepoToPerm.repository == repo)\
348 .scalar()
348 .scalar()
349 if obj is None:
349 if obj is None:
350 # create new !
350 # create new !
351 obj = UserRepoToPerm()
351 obj = UserRepoToPerm()
352 obj.repository = repo
352 obj.repository = repo
353 obj.user = user
353 obj.user = user
354 obj.permission = permission
354 obj.permission = permission
355 self.sa.add(obj)
355 self.sa.add(obj)
356
356
357 def revoke_user_permission(self, repo, user):
357 def revoke_user_permission(self, repo, user):
358 """
358 """
359 Revoke permission for user on given repository
359 Revoke permission for user on given repository
360
360
361 :param repo: Instance of Repository, repository_id, or repository name
361 :param repo: Instance of Repository, repository_id, or repository name
362 :param user: Instance of User, user_id or username
362 :param user: Instance of User, user_id or username
363 """
363 """
364
364
365 user = self._get_user(user)
365 user = self._get_user(user)
366 repo = self._get_repo(repo)
366 repo = self._get_repo(repo)
367
367
368 obj = self.sa.query(UserRepoToPerm)\
368 obj = self.sa.query(UserRepoToPerm)\
369 .filter(UserRepoToPerm.repository == repo)\
369 .filter(UserRepoToPerm.repository == repo)\
370 .filter(UserRepoToPerm.user == user)\
370 .filter(UserRepoToPerm.user == user)\
371 .one()
371 .one()
372 self.sa.delete(obj)
372 self.sa.delete(obj)
373
373
374 def grant_users_group_permission(self, repo, group_name, perm):
374 def grant_users_group_permission(self, repo, group_name, perm):
375 """
375 """
376 Grant permission for users group on given repository, or update
376 Grant permission for users group on given repository, or update
377 existing one if found
377 existing one if found
378
378
379 :param repo: Instance of Repository, repository_id, or repository name
379 :param repo: Instance of Repository, repository_id, or repository name
380 :param group_name: Instance of UserGroup, users_group_id,
380 :param group_name: Instance of UserGroup, users_group_id,
381 or users group name
381 or users group name
382 :param perm: Instance of Permission, or permission_name
382 :param perm: Instance of Permission, or permission_name
383 """
383 """
384 repo = self._get_repo(repo)
384 repo = self._get_repo(repo)
385 group_name = self.__get_users_group(group_name)
385 group_name = self.__get_users_group(group_name)
386 permission = self._get_perm(perm)
386 permission = self._get_perm(perm)
387
387
388 # check if we have that permission already
388 # check if we have that permission already
389 obj = self.sa.query(UsersGroupRepoToPerm)\
389 obj = self.sa.query(UsersGroupRepoToPerm)\
390 .filter(UsersGroupRepoToPerm.users_group == group_name)\
390 .filter(UsersGroupRepoToPerm.users_group == group_name)\
391 .filter(UsersGroupRepoToPerm.repository == repo)\
391 .filter(UsersGroupRepoToPerm.repository == repo)\
392 .scalar()
392 .scalar()
393
393
394 if obj is None:
394 if obj is None:
395 # create new
395 # create new
396 obj = UsersGroupRepoToPerm()
396 obj = UsersGroupRepoToPerm()
397
397
398 obj.repository = repo
398 obj.repository = repo
399 obj.users_group = group_name
399 obj.users_group = group_name
400 obj.permission = permission
400 obj.permission = permission
401 self.sa.add(obj)
401 self.sa.add(obj)
402
402
403 def revoke_users_group_permission(self, repo, group_name):
403 def revoke_users_group_permission(self, repo, group_name):
404 """
404 """
405 Revoke permission for users group on given repository
405 Revoke permission for users group on given repository
406
406
407 :param repo: Instance of Repository, repository_id, or repository name
407 :param repo: Instance of Repository, repository_id, or repository name
408 :param group_name: Instance of UserGroup, users_group_id,
408 :param group_name: Instance of UserGroup, users_group_id,
409 or users group name
409 or users group name
410 """
410 """
411 repo = self._get_repo(repo)
411 repo = self._get_repo(repo)
412 group_name = self.__get_users_group(group_name)
412 group_name = self.__get_users_group(group_name)
413
413
414 obj = self.sa.query(UsersGroupRepoToPerm)\
414 obj = self.sa.query(UsersGroupRepoToPerm)\
415 .filter(UsersGroupRepoToPerm.repository == repo)\
415 .filter(UsersGroupRepoToPerm.repository == repo)\
416 .filter(UsersGroupRepoToPerm.users_group == group_name)\
416 .filter(UsersGroupRepoToPerm.users_group == group_name)\
417 .one()
417 .one()
418 self.sa.delete(obj)
418 self.sa.delete(obj)
419
419
420 def delete_stats(self, repo_name):
420 def delete_stats(self, repo_name):
421 """
421 """
422 removes stats for given repo
422 removes stats for given repo
423
423
424 :param repo_name:
424 :param repo_name:
425 """
425 """
426 try:
426 try:
427 obj = self.sa.query(Statistics)\
427 obj = self.sa.query(Statistics)\
428 .filter(Statistics.repository ==
428 .filter(Statistics.repository ==
429 self.get_by_repo_name(repo_name))\
429 self.get_by_repo_name(repo_name))\
430 .one()
430 .one()
431 self.sa.delete(obj)
431 self.sa.delete(obj)
432 except:
432 except:
433 log.error(traceback.format_exc())
433 log.error(traceback.format_exc())
434 raise
434 raise
435
435
436 def __create_repo(self, repo_name, alias, parent, clone_uri=False):
436 def __create_repo(self, repo_name, alias, parent, clone_uri=False):
437 """
437 """
438 makes repository on filesystem. It's group aware means it'll create
438 makes repository on filesystem. It's group aware means it'll create
439 a repository within a group, and alter the paths accordingly of
439 a repository within a group, and alter the paths accordingly of
440 group location
440 group location
441
441
442 :param repo_name:
442 :param repo_name:
443 :param alias:
443 :param alias:
444 :param parent_id:
444 :param parent_id:
445 :param clone_uri:
445 :param clone_uri:
446 """
446 """
447 from rhodecode.lib.utils import is_valid_repo, is_valid_repos_group
447 from rhodecode.lib.utils import is_valid_repo, is_valid_repos_group
448 from rhodecode.model.scm import ScmModel
448 from rhodecode.model.scm import ScmModel
449
449
450 if parent:
450 if parent:
451 new_parent_path = os.sep.join(parent.full_path_splitted)
451 new_parent_path = os.sep.join(parent.full_path_splitted)
452 else:
452 else:
453 new_parent_path = ''
453 new_parent_path = ''
454
454
455 # we need to make it str for mercurial
455 # we need to make it str for mercurial
456 repo_path = os.path.join(*map(lambda x: safe_str(x),
456 repo_path = os.path.join(*map(lambda x: safe_str(x),
457 [self.repos_path, new_parent_path, repo_name]))
457 [self.repos_path, new_parent_path, repo_name]))
458
458
459 # check if this path is not a repository
459 # check if this path is not a repository
460 if is_valid_repo(repo_path, self.repos_path):
460 if is_valid_repo(repo_path, self.repos_path):
461 raise Exception('This path %s is a valid repository' % repo_path)
461 raise Exception('This path %s is a valid repository' % repo_path)
462
462
463 # check if this path is a group
463 # check if this path is a group
464 if is_valid_repos_group(repo_path, self.repos_path):
464 if is_valid_repos_group(repo_path, self.repos_path):
465 raise Exception('This path %s is a valid group' % repo_path)
465 raise Exception('This path %s is a valid group' % repo_path)
466
466
467 log.info('creating repo %s in %s @ %s' % (
467 log.info('creating repo %s in %s @ %s' % (
468 repo_name, safe_unicode(repo_path), clone_uri
468 repo_name, safe_unicode(repo_path), clone_uri
469 )
469 )
470 )
470 )
471 backend = get_backend(alias)
471 backend = get_backend(alias)
472 if alias == 'hg':
472 if alias == 'hg':
473 backend(repo_path, create=True, src_url=clone_uri)
473 backend(repo_path, create=True, src_url=clone_uri)
474 elif alias == 'git':
474 elif alias == 'git':
475 r = backend(repo_path, create=True, src_url=clone_uri, bare=True)
475 r = backend(repo_path, create=True, src_url=clone_uri, bare=True)
476 # add rhodecode hook into this repo
476 # add rhodecode hook into this repo
477 ScmModel().install_git_hook(repo=r)
477 ScmModel().install_git_hook(repo=r)
478 else:
478 else:
479 raise Exception('Undefined alias %s' % alias)
479 raise Exception('Undefined alias %s' % alias)
480
480
481 def __rename_repo(self, old, new):
481 def __rename_repo(self, old, new):
482 """
482 """
483 renames repository on filesystem
483 renames repository on filesystem
484
484
485 :param old: old name
485 :param old: old name
486 :param new: new name
486 :param new: new name
487 """
487 """
488 log.info('renaming repo from %s to %s' % (old, new))
488 log.info('renaming repo from %s to %s' % (old, new))
489
489
490 old_path = os.path.join(self.repos_path, old)
490 old_path = os.path.join(self.repos_path, old)
491 new_path = os.path.join(self.repos_path, new)
491 new_path = os.path.join(self.repos_path, new)
492 if os.path.isdir(new_path):
492 if os.path.isdir(new_path):
493 raise Exception(
493 raise Exception(
494 'Was trying to rename to already existing dir %s' % new_path
494 'Was trying to rename to already existing dir %s' % new_path
495 )
495 )
496 shutil.move(old_path, new_path)
496 shutil.move(old_path, new_path)
497
497
498 def __delete_repo(self, repo):
498 def __delete_repo(self, repo):
499 """
499 """
500 removes repo from filesystem, the removal is acctually made by
500 removes repo from filesystem, the removal is acctually made by
501 added rm__ prefix into dir, and rename internat .hg/.git dirs so this
501 added rm__ prefix into dir, and rename internat .hg/.git dirs so this
502 repository is no longer valid for rhodecode, can be undeleted later on
502 repository is no longer valid for rhodecode, can be undeleted later on
503 by reverting the renames on this repository
503 by reverting the renames on this repository
504
504
505 :param repo: repo object
505 :param repo: repo object
506 """
506 """
507 rm_path = os.path.join(self.repos_path, repo.repo_name)
507 rm_path = os.path.join(self.repos_path, repo.repo_name)
508 log.info("Removing %s" % (rm_path))
508 log.info("Removing %s" % (rm_path))
509 # disable hg/git internal that it doesn't get detected as repo
509 # disable hg/git internal that it doesn't get detected as repo
510 alias = repo.repo_type
510 alias = repo.repo_type
511
511
512 bare = getattr(repo.scm_instance, 'bare', False)
512 bare = getattr(repo.scm_instance, 'bare', False)
513
513
514 if not bare:
514 if not bare:
515 # skip this for bare git repos
515 # skip this for bare git repos
516 shutil.move(os.path.join(rm_path, '.%s' % alias),
516 shutil.move(os.path.join(rm_path, '.%s' % alias),
517 os.path.join(rm_path, 'rm__.%s' % alias))
517 os.path.join(rm_path, 'rm__.%s' % alias))
518 # disable repo
518 # disable repo
519 _now = datetime.now()
519 _now = datetime.now()
520 _ms = str(_now.microsecond).rjust(6, '0')
520 _ms = str(_now.microsecond).rjust(6, '0')
521 _d = 'rm__%s__%s' % (_now.strftime('%Y%m%d_%H%M%S_' + _ms),
521 _d = 'rm__%s__%s' % (_now.strftime('%Y%m%d_%H%M%S_' + _ms),
522 repo.repo_name)
522 repo.repo_name)
523 shutil.move(rm_path, os.path.join(self.repos_path, _d))
523 shutil.move(rm_path, os.path.join(self.repos_path, _d))
@@ -1,305 +1,305
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.model.user_group
3 rhodecode.model.user_group
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~
5
5
6 users groups model for RhodeCode
6 users groups model for RhodeCode
7
7
8 :created_on: Jan 25, 2011
8 :created_on: Jan 25, 2011
9 :author: marcink
9 :author: marcink
10 :copyright: (C) 2011-2012 Marcin Kuzminski <marcin@python-works.com>
10 :copyright: (C) 2011-2012 Marcin Kuzminski <marcin@python-works.com>
11 :license: GPLv3, see COPYING for more details.
11 :license: GPLv3, see COPYING for more details.
12 """
12 """
13 # This program is free software: you can redistribute it and/or modify
13 # This program is free software: you can redistribute it and/or modify
14 # it under the terms of the GNU General Public License as published by
14 # it under the terms of the GNU General Public License as published by
15 # the Free Software Foundation, either version 3 of the License, or
15 # the Free Software Foundation, either version 3 of the License, or
16 # (at your option) any later version.
16 # (at your option) any later version.
17 #
17 #
18 # This program is distributed in the hope that it will be useful,
18 # This program is distributed in the hope that it will be useful,
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # GNU General Public License for more details.
21 # GNU General Public License for more details.
22 #
22 #
23 # You should have received a copy of the GNU General Public License
23 # You should have received a copy of the GNU General Public License
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25
25
26 import os
26 import os
27 import logging
27 import logging
28 import traceback
28 import traceback
29 import shutil
29 import shutil
30
30
31 from rhodecode.lib.utils2 import LazyProperty
31 from rhodecode.lib.utils2 import LazyProperty
32
32
33 from rhodecode.model import BaseModel
33 from rhodecode.model import BaseModel
34 from rhodecode.model.db import RepoGroup, RhodeCodeUi, UserRepoGroupToPerm, \
34 from rhodecode.model.db import RepoGroup, RhodeCodeUi, UserRepoGroupToPerm, \
35 User, Permission, UsersGroupRepoGroupToPerm, UsersGroup
35 User, Permission, UsersGroupRepoGroupToPerm, UsersGroup
36
36
37 log = logging.getLogger(__name__)
37 log = logging.getLogger(__name__)
38
38
39
39
40 class ReposGroupModel(BaseModel):
40 class ReposGroupModel(BaseModel):
41
41
42 cls = RepoGroup
42 cls = RepoGroup
43
43
44 def __get_users_group(self, users_group):
44 def __get_users_group(self, users_group):
45 return self._get_instance(UsersGroup, users_group,
45 return self._get_instance(UsersGroup, users_group,
46 callback=UsersGroup.get_by_group_name)
46 callback=UsersGroup.get_by_group_name)
47
47
48 def __get_repos_group(self, repos_group):
48 def _get_repos_group(self, repos_group):
49 return self._get_instance(RepoGroup, repos_group,
49 return self._get_instance(RepoGroup, repos_group,
50 callback=RepoGroup.get_by_group_name)
50 callback=RepoGroup.get_by_group_name)
51
51
52 @LazyProperty
52 @LazyProperty
53 def repos_path(self):
53 def repos_path(self):
54 """
54 """
55 Get's the repositories root path from database
55 Get's the repositories root path from database
56 """
56 """
57
57
58 q = RhodeCodeUi.get_by_key('/').one()
58 q = RhodeCodeUi.get_by_key('/').one()
59 return q.ui_value
59 return q.ui_value
60
60
61 def _create_default_perms(self, new_group):
61 def _create_default_perms(self, new_group):
62 # create default permission
62 # create default permission
63 repo_group_to_perm = UserRepoGroupToPerm()
63 repo_group_to_perm = UserRepoGroupToPerm()
64 default_perm = 'group.read'
64 default_perm = 'group.read'
65 for p in User.get_by_username('default').user_perms:
65 for p in User.get_by_username('default').user_perms:
66 if p.permission.permission_name.startswith('group.'):
66 if p.permission.permission_name.startswith('group.'):
67 default_perm = p.permission.permission_name
67 default_perm = p.permission.permission_name
68 break
68 break
69
69
70 repo_group_to_perm.permission_id = self.sa.query(Permission)\
70 repo_group_to_perm.permission_id = self.sa.query(Permission)\
71 .filter(Permission.permission_name == default_perm)\
71 .filter(Permission.permission_name == default_perm)\
72 .one().permission_id
72 .one().permission_id
73
73
74 repo_group_to_perm.group = new_group
74 repo_group_to_perm.group = new_group
75 repo_group_to_perm.user_id = User.get_by_username('default').user_id
75 repo_group_to_perm.user_id = User.get_by_username('default').user_id
76
76
77 self.sa.add(repo_group_to_perm)
77 self.sa.add(repo_group_to_perm)
78
78
79 def __create_group(self, group_name):
79 def __create_group(self, group_name):
80 """
80 """
81 makes repositories group on filesystem
81 makes repositories group on filesystem
82
82
83 :param repo_name:
83 :param repo_name:
84 :param parent_id:
84 :param parent_id:
85 """
85 """
86
86
87 create_path = os.path.join(self.repos_path, group_name)
87 create_path = os.path.join(self.repos_path, group_name)
88 log.debug('creating new group in %s' % create_path)
88 log.debug('creating new group in %s' % create_path)
89
89
90 if os.path.isdir(create_path):
90 if os.path.isdir(create_path):
91 raise Exception('That directory already exists !')
91 raise Exception('That directory already exists !')
92
92
93 os.makedirs(create_path)
93 os.makedirs(create_path)
94
94
95 def __rename_group(self, old, new):
95 def __rename_group(self, old, new):
96 """
96 """
97 Renames a group on filesystem
97 Renames a group on filesystem
98
98
99 :param group_name:
99 :param group_name:
100 """
100 """
101
101
102 if old == new:
102 if old == new:
103 log.debug('skipping group rename')
103 log.debug('skipping group rename')
104 return
104 return
105
105
106 log.debug('renaming repos group from %s to %s' % (old, new))
106 log.debug('renaming repos group from %s to %s' % (old, new))
107
107
108 old_path = os.path.join(self.repos_path, old)
108 old_path = os.path.join(self.repos_path, old)
109 new_path = os.path.join(self.repos_path, new)
109 new_path = os.path.join(self.repos_path, new)
110
110
111 log.debug('renaming repos paths from %s to %s' % (old_path, new_path))
111 log.debug('renaming repos paths from %s to %s' % (old_path, new_path))
112
112
113 if os.path.isdir(new_path):
113 if os.path.isdir(new_path):
114 raise Exception('Was trying to rename to already '
114 raise Exception('Was trying to rename to already '
115 'existing dir %s' % new_path)
115 'existing dir %s' % new_path)
116 shutil.move(old_path, new_path)
116 shutil.move(old_path, new_path)
117
117
118 def __delete_group(self, group):
118 def __delete_group(self, group):
119 """
119 """
120 Deletes a group from a filesystem
120 Deletes a group from a filesystem
121
121
122 :param group: instance of group from database
122 :param group: instance of group from database
123 """
123 """
124 paths = group.full_path.split(RepoGroup.url_sep())
124 paths = group.full_path.split(RepoGroup.url_sep())
125 paths = os.sep.join(paths)
125 paths = os.sep.join(paths)
126
126
127 rm_path = os.path.join(self.repos_path, paths)
127 rm_path = os.path.join(self.repos_path, paths)
128 if os.path.isdir(rm_path):
128 if os.path.isdir(rm_path):
129 # delete only if that path really exists
129 # delete only if that path really exists
130 os.rmdir(rm_path)
130 os.rmdir(rm_path)
131
131
132 def create(self, group_name, group_description, parent=None, just_db=False):
132 def create(self, group_name, group_description, parent=None, just_db=False):
133 try:
133 try:
134 new_repos_group = RepoGroup()
134 new_repos_group = RepoGroup()
135 new_repos_group.group_description = group_description
135 new_repos_group.group_description = group_description
136 new_repos_group.parent_group = self.__get_repos_group(parent)
136 new_repos_group.parent_group = self._get_repos_group(parent)
137 new_repos_group.group_name = new_repos_group.get_new_name(group_name)
137 new_repos_group.group_name = new_repos_group.get_new_name(group_name)
138
138
139 self.sa.add(new_repos_group)
139 self.sa.add(new_repos_group)
140 self._create_default_perms(new_repos_group)
140 self._create_default_perms(new_repos_group)
141
141
142 if not just_db:
142 if not just_db:
143 # we need to flush here, in order to check if database won't
143 # we need to flush here, in order to check if database won't
144 # throw any exceptions, create filesystem dirs at the very end
144 # throw any exceptions, create filesystem dirs at the very end
145 self.sa.flush()
145 self.sa.flush()
146 self.__create_group(new_repos_group.group_name)
146 self.__create_group(new_repos_group.group_name)
147
147
148 return new_repos_group
148 return new_repos_group
149 except:
149 except:
150 log.error(traceback.format_exc())
150 log.error(traceback.format_exc())
151 raise
151 raise
152
152
153 def update(self, repos_group_id, form_data):
153 def update(self, repos_group_id, form_data):
154
154
155 try:
155 try:
156 repos_group = RepoGroup.get(repos_group_id)
156 repos_group = RepoGroup.get(repos_group_id)
157
157
158 # update permissions
158 # update permissions
159 for member, perm, member_type in form_data['perms_updates']:
159 for member, perm, member_type in form_data['perms_updates']:
160 if member_type == 'user':
160 if member_type == 'user':
161 # this updates also current one if found
161 # this updates also current one if found
162 ReposGroupModel().grant_user_permission(
162 ReposGroupModel().grant_user_permission(
163 repos_group=repos_group, user=member, perm=perm
163 repos_group=repos_group, user=member, perm=perm
164 )
164 )
165 else:
165 else:
166 ReposGroupModel().grant_users_group_permission(
166 ReposGroupModel().grant_users_group_permission(
167 repos_group=repos_group, group_name=member, perm=perm
167 repos_group=repos_group, group_name=member, perm=perm
168 )
168 )
169 # set new permissions
169 # set new permissions
170 for member, perm, member_type in form_data['perms_new']:
170 for member, perm, member_type in form_data['perms_new']:
171 if member_type == 'user':
171 if member_type == 'user':
172 ReposGroupModel().grant_user_permission(
172 ReposGroupModel().grant_user_permission(
173 repos_group=repos_group, user=member, perm=perm
173 repos_group=repos_group, user=member, perm=perm
174 )
174 )
175 else:
175 else:
176 ReposGroupModel().grant_users_group_permission(
176 ReposGroupModel().grant_users_group_permission(
177 repos_group=repos_group, group_name=member, perm=perm
177 repos_group=repos_group, group_name=member, perm=perm
178 )
178 )
179
179
180 old_path = repos_group.full_path
180 old_path = repos_group.full_path
181
181
182 # change properties
182 # change properties
183 repos_group.group_description = form_data['group_description']
183 repos_group.group_description = form_data['group_description']
184 repos_group.parent_group = RepoGroup.get(form_data['group_parent_id'])
184 repos_group.parent_group = RepoGroup.get(form_data['group_parent_id'])
185 repos_group.group_parent_id = form_data['group_parent_id']
185 repos_group.group_parent_id = form_data['group_parent_id']
186 repos_group.group_name = repos_group.get_new_name(form_data['group_name'])
186 repos_group.group_name = repos_group.get_new_name(form_data['group_name'])
187 new_path = repos_group.full_path
187 new_path = repos_group.full_path
188
188
189 self.sa.add(repos_group)
189 self.sa.add(repos_group)
190
190
191 # we need to get all repositories from this new group and
191 # we need to get all repositories from this new group and
192 # rename them accordingly to new group path
192 # rename them accordingly to new group path
193 for r in repos_group.repositories:
193 for r in repos_group.repositories:
194 r.repo_name = r.get_new_name(r.just_name)
194 r.repo_name = r.get_new_name(r.just_name)
195 self.sa.add(r)
195 self.sa.add(r)
196
196
197 self.__rename_group(old_path, new_path)
197 self.__rename_group(old_path, new_path)
198
198
199 return repos_group
199 return repos_group
200 except:
200 except:
201 log.error(traceback.format_exc())
201 log.error(traceback.format_exc())
202 raise
202 raise
203
203
204 def delete(self, repos_group):
204 def delete(self, repos_group):
205 repos_group = self.__get_repos_group(repos_group)
205 repos_group = self._get_repos_group(repos_group)
206 try:
206 try:
207 self.sa.delete(repos_group)
207 self.sa.delete(repos_group)
208 self.__delete_group(repos_group)
208 self.__delete_group(repos_group)
209 except:
209 except:
210 log.exception('Error removing repos_group %s' % repos_group)
210 log.exception('Error removing repos_group %s' % repos_group)
211 raise
211 raise
212
212
213 def grant_user_permission(self, repos_group, user, perm):
213 def grant_user_permission(self, repos_group, user, perm):
214 """
214 """
215 Grant permission for user on given repositories group, or update
215 Grant permission for user on given repositories group, or update
216 existing one if found
216 existing one if found
217
217
218 :param repos_group: Instance of ReposGroup, repositories_group_id,
218 :param repos_group: Instance of ReposGroup, repositories_group_id,
219 or repositories_group name
219 or repositories_group name
220 :param user: Instance of User, user_id or username
220 :param user: Instance of User, user_id or username
221 :param perm: Instance of Permission, or permission_name
221 :param perm: Instance of Permission, or permission_name
222 """
222 """
223
223
224 repos_group = self.__get_repos_group(repos_group)
224 repos_group = self._get_repos_group(repos_group)
225 user = self._get_user(user)
225 user = self._get_user(user)
226 permission = self._get_perm(perm)
226 permission = self._get_perm(perm)
227
227
228 # check if we have that permission already
228 # check if we have that permission already
229 obj = self.sa.query(UserRepoGroupToPerm)\
229 obj = self.sa.query(UserRepoGroupToPerm)\
230 .filter(UserRepoGroupToPerm.user == user)\
230 .filter(UserRepoGroupToPerm.user == user)\
231 .filter(UserRepoGroupToPerm.group == repos_group)\
231 .filter(UserRepoGroupToPerm.group == repos_group)\
232 .scalar()
232 .scalar()
233 if obj is None:
233 if obj is None:
234 # create new !
234 # create new !
235 obj = UserRepoGroupToPerm()
235 obj = UserRepoGroupToPerm()
236 obj.group = repos_group
236 obj.group = repos_group
237 obj.user = user
237 obj.user = user
238 obj.permission = permission
238 obj.permission = permission
239 self.sa.add(obj)
239 self.sa.add(obj)
240
240
241 def revoke_user_permission(self, repos_group, user):
241 def revoke_user_permission(self, repos_group, user):
242 """
242 """
243 Revoke permission for user on given repositories group
243 Revoke permission for user on given repositories group
244
244
245 :param repos_group: Instance of ReposGroup, repositories_group_id,
245 :param repos_group: Instance of ReposGroup, repositories_group_id,
246 or repositories_group name
246 or repositories_group name
247 :param user: Instance of User, user_id or username
247 :param user: Instance of User, user_id or username
248 """
248 """
249
249
250 repos_group = self.__get_repos_group(repos_group)
250 repos_group = self._get_repos_group(repos_group)
251 user = self._get_user(user)
251 user = self._get_user(user)
252
252
253 obj = self.sa.query(UserRepoGroupToPerm)\
253 obj = self.sa.query(UserRepoGroupToPerm)\
254 .filter(UserRepoGroupToPerm.user == user)\
254 .filter(UserRepoGroupToPerm.user == user)\
255 .filter(UserRepoGroupToPerm.group == repos_group)\
255 .filter(UserRepoGroupToPerm.group == repos_group)\
256 .one()
256 .one()
257 self.sa.delete(obj)
257 self.sa.delete(obj)
258
258
259 def grant_users_group_permission(self, repos_group, group_name, perm):
259 def grant_users_group_permission(self, repos_group, group_name, perm):
260 """
260 """
261 Grant permission for users group on given repositories group, or update
261 Grant permission for users group on given repositories group, or update
262 existing one if found
262 existing one if found
263
263
264 :param repos_group: Instance of ReposGroup, repositories_group_id,
264 :param repos_group: Instance of ReposGroup, repositories_group_id,
265 or repositories_group name
265 or repositories_group name
266 :param group_name: Instance of UserGroup, users_group_id,
266 :param group_name: Instance of UserGroup, users_group_id,
267 or users group name
267 or users group name
268 :param perm: Instance of Permission, or permission_name
268 :param perm: Instance of Permission, or permission_name
269 """
269 """
270 repos_group = self.__get_repos_group(repos_group)
270 repos_group = self._get_repos_group(repos_group)
271 group_name = self.__get_users_group(group_name)
271 group_name = self.__get_users_group(group_name)
272 permission = self._get_perm(perm)
272 permission = self._get_perm(perm)
273
273
274 # check if we have that permission already
274 # check if we have that permission already
275 obj = self.sa.query(UsersGroupRepoGroupToPerm)\
275 obj = self.sa.query(UsersGroupRepoGroupToPerm)\
276 .filter(UsersGroupRepoGroupToPerm.group == repos_group)\
276 .filter(UsersGroupRepoGroupToPerm.group == repos_group)\
277 .filter(UsersGroupRepoGroupToPerm.users_group == group_name)\
277 .filter(UsersGroupRepoGroupToPerm.users_group == group_name)\
278 .scalar()
278 .scalar()
279
279
280 if obj is None:
280 if obj is None:
281 # create new
281 # create new
282 obj = UsersGroupRepoGroupToPerm()
282 obj = UsersGroupRepoGroupToPerm()
283
283
284 obj.group = repos_group
284 obj.group = repos_group
285 obj.users_group = group_name
285 obj.users_group = group_name
286 obj.permission = permission
286 obj.permission = permission
287 self.sa.add(obj)
287 self.sa.add(obj)
288
288
289 def revoke_users_group_permission(self, repos_group, group_name):
289 def revoke_users_group_permission(self, repos_group, group_name):
290 """
290 """
291 Revoke permission for users group on given repositories group
291 Revoke permission for users group on given repositories group
292
292
293 :param repos_group: Instance of ReposGroup, repositories_group_id,
293 :param repos_group: Instance of ReposGroup, repositories_group_id,
294 or repositories_group name
294 or repositories_group name
295 :param group_name: Instance of UserGroup, users_group_id,
295 :param group_name: Instance of UserGroup, users_group_id,
296 or users group name
296 or users group name
297 """
297 """
298 repos_group = self.__get_repos_group(repos_group)
298 repos_group = self._get_repos_group(repos_group)
299 group_name = self.__get_users_group(group_name)
299 group_name = self.__get_users_group(group_name)
300
300
301 obj = self.sa.query(UsersGroupRepoGroupToPerm)\
301 obj = self.sa.query(UsersGroupRepoGroupToPerm)\
302 .filter(UsersGroupRepoGroupToPerm.group == repos_group)\
302 .filter(UsersGroupRepoGroupToPerm.group == repos_group)\
303 .filter(UsersGroupRepoGroupToPerm.users_group == group_name)\
303 .filter(UsersGroupRepoGroupToPerm.users_group == group_name)\
304 .one()
304 .one()
305 self.sa.delete(obj)
305 self.sa.delete(obj)
@@ -1,251 +1,261
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2 <%inherit file="/base/base.html"/>
2 <%inherit file="/base/base.html"/>
3
3
4 <%def name="title()">
4 <%def name="title()">
5 ${_('Edit user')} ${c.user.username} - ${c.rhodecode_name}
5 ${_('Edit user')} ${c.user.username} - ${c.rhodecode_name}
6 </%def>
6 </%def>
7
7
8 <%def name="breadcrumbs_links()">
8 <%def name="breadcrumbs_links()">
9 ${h.link_to(_('Admin'),h.url('admin_home'))}
9 ${h.link_to(_('Admin'),h.url('admin_home'))}
10 &raquo;
10 &raquo;
11 ${h.link_to(_('Users'),h.url('users'))}
11 ${h.link_to(_('Users'),h.url('users'))}
12 &raquo;
12 &raquo;
13 ${_('edit')} "${c.user.username}"
13 ${_('edit')} "${c.user.username}"
14 </%def>
14 </%def>
15
15
16 <%def name="page_nav()">
16 <%def name="page_nav()">
17 ${self.menu('admin')}
17 ${self.menu('admin')}
18 </%def>
18 </%def>
19
19
20 <%def name="main()">
20 <%def name="main()">
21 <div class="box box-left">
21 <div class="box box-left">
22 <!-- box / title -->
22 <!-- box / title -->
23 <div class="title">
23 <div class="title">
24 ${self.breadcrumbs()}
24 ${self.breadcrumbs()}
25 </div>
25 </div>
26 <!-- end box / title -->
26 <!-- end box / title -->
27 ${h.form(url('update_user', id=c.user.user_id),method='put')}
27 ${h.form(url('update_user', id=c.user.user_id),method='put')}
28 <div class="form">
28 <div class="form">
29 <div class="field">
29 <div class="field">
30 <div class="gravatar_box">
30 <div class="gravatar_box">
31 <div class="gravatar"><img alt="gravatar" src="${h.gravatar_url(c.user.email)}"/></div>
31 <div class="gravatar"><img alt="gravatar" src="${h.gravatar_url(c.user.email)}"/></div>
32 <p>
32 <p>
33 %if c.use_gravatar:
33 %if c.use_gravatar:
34 <strong>${_('Change your avatar at')} <a href="http://gravatar.com">gravatar.com</a></strong>
34 <strong>${_('Change your avatar at')} <a href="http://gravatar.com">gravatar.com</a></strong>
35 <br/>${_('Using')} ${c.user.email}
35 <br/>${_('Using')} ${c.user.email}
36 %else:
36 %else:
37 <br/>${c.user.email}
37 <br/>${c.user.email}
38 %endif
38 %endif
39 </div>
39 </div>
40 </div>
40 </div>
41 <div class="field">
41 <div class="field">
42 <div class="label">
42 <div class="label">
43 <label>${_('API key')}</label> ${c.user.api_key}
43 <label>${_('API key')}</label> ${c.user.api_key}
44 </div>
44 </div>
45 </div>
45 </div>
46
46
47 <div class="fields">
47 <div class="fields">
48 <div class="field">
48 <div class="field">
49 <div class="label">
49 <div class="label">
50 <label for="username">${_('Username')}:</label>
50 <label for="username">${_('Username')}:</label>
51 </div>
51 </div>
52 <div class="input">
52 <div class="input">
53 ${h.text('username',class_='medium')}
53 ${h.text('username',class_='medium')}
54 </div>
54 </div>
55 </div>
55 </div>
56
56
57 <div class="field">
57 <div class="field">
58 <div class="label">
58 <div class="label">
59 <label for="ldap_dn">${_('LDAP DN')}:</label>
59 <label for="ldap_dn">${_('LDAP DN')}:</label>
60 </div>
60 </div>
61 <div class="input">
61 <div class="input">
62 ${h.text('ldap_dn',class_='medium disabled',readonly="readonly")}
62 ${h.text('ldap_dn',class_='medium disabled',readonly="readonly")}
63 </div>
63 </div>
64 </div>
64 </div>
65
65
66 <div class="field">
66 <div class="field">
67 <div class="label">
67 <div class="label">
68 <label for="new_password">${_('New password')}:</label>
68 <label for="new_password">${_('New password')}:</label>
69 </div>
69 </div>
70 <div class="input">
70 <div class="input">
71 ${h.password('new_password',class_='medium',autocomplete="off")}
71 ${h.password('new_password',class_='medium',autocomplete="off")}
72 </div>
72 </div>
73 </div>
73 </div>
74
74
75 <div class="field">
75 <div class="field">
76 <div class="label">
76 <div class="label">
77 <label for="password_confirmation">${_('New password confirmation')}:</label>
77 <label for="password_confirmation">${_('New password confirmation')}:</label>
78 </div>
78 </div>
79 <div class="input">
79 <div class="input">
80 ${h.password('password_confirmation',class_="medium",autocomplete="off")}
80 ${h.password('password_confirmation',class_="medium",autocomplete="off")}
81 </div>
81 </div>
82 </div>
82 </div>
83
83
84 <div class="field">
84 <div class="field">
85 <div class="label">
85 <div class="label">
86 <label for="firstname">${_('First Name')}:</label>
86 <label for="firstname">${_('First Name')}:</label>
87 </div>
87 </div>
88 <div class="input">
88 <div class="input">
89 ${h.text('firstname',class_='medium')}
89 ${h.text('firstname',class_='medium')}
90 </div>
90 </div>
91 </div>
91 </div>
92
92
93 <div class="field">
93 <div class="field">
94 <div class="label">
94 <div class="label">
95 <label for="lastname">${_('Last Name')}:</label>
95 <label for="lastname">${_('Last Name')}:</label>
96 </div>
96 </div>
97 <div class="input">
97 <div class="input">
98 ${h.text('lastname',class_='medium')}
98 ${h.text('lastname',class_='medium')}
99 </div>
99 </div>
100 </div>
100 </div>
101
101
102 <div class="field">
102 <div class="field">
103 <div class="label">
103 <div class="label">
104 <label for="email">${_('Email')}:</label>
104 <label for="email">${_('Email')}:</label>
105 </div>
105 </div>
106 <div class="input">
106 <div class="input">
107 ${h.text('email',class_='medium')}
107 ${h.text('email',class_='medium')}
108 </div>
108 </div>
109 </div>
109 </div>
110
110
111 <div class="field">
111 <div class="field">
112 <div class="label label-checkbox">
112 <div class="label label-checkbox">
113 <label for="active">${_('Active')}:</label>
113 <label for="active">${_('Active')}:</label>
114 </div>
114 </div>
115 <div class="checkboxes">
115 <div class="checkboxes">
116 ${h.checkbox('active',value=True)}
116 ${h.checkbox('active',value=True)}
117 </div>
117 </div>
118 </div>
118 </div>
119
119
120 <div class="field">
120 <div class="field">
121 <div class="label label-checkbox">
121 <div class="label label-checkbox">
122 <label for="admin">${_('Admin')}:</label>
122 <label for="admin">${_('Admin')}:</label>
123 </div>
123 </div>
124 <div class="checkboxes">
124 <div class="checkboxes">
125 ${h.checkbox('admin',value=True)}
125 ${h.checkbox('admin',value=True)}
126 </div>
126 </div>
127 </div>
127 </div>
128 <div class="buttons">
128 <div class="buttons">
129 ${h.submit('save',_('Save'),class_="ui-btn large")}
129 ${h.submit('save',_('Save'),class_="ui-btn large")}
130 ${h.reset('reset',_('Reset'),class_="ui-btn large")}
130 ${h.reset('reset',_('Reset'),class_="ui-btn large")}
131 </div>
131 </div>
132 </div>
132 </div>
133 </div>
133 </div>
134 ${h.end_form()}
134 ${h.end_form()}
135 </div>
135 </div>
136 <div class="box box-right">
136 <div class="box box-right">
137 <!-- box / title -->
137 <!-- box / title -->
138 <div class="title">
138 <div class="title">
139 <h5>${_('Permissions')}</h5>
139 <h5>${_('Permissions')}</h5>
140 </div>
140 </div>
141 ${h.form(url('user_perm', id=c.user.user_id),method='put')}
141 ${h.form(url('user_perm', id=c.user.user_id),method='put')}
142 <div class="form">
142 <div class="form">
143 <!-- fields -->
143 <!-- fields -->
144 <div class="fields">
144 <div class="fields">
145 <div class="field">
145 <div class="field">
146 <div class="label label-checkbox">
146 <div class="label label-checkbox">
147 <label for="create_repo_perm">${_('Create repositories')}:</label>
147 <label for="create_repo_perm">${_('Create repositories')}:</label>
148 </div>
148 </div>
149 <div class="checkboxes">
149 <div class="checkboxes">
150 ${h.checkbox('create_repo_perm',value=True)}
150 ${h.checkbox('create_repo_perm',value=True)}
151 </div>
151 </div>
152 </div>
152 </div>
153 <div class="buttons">
153 <div class="buttons">
154 ${h.submit('save',_('Save'),class_="ui-btn large")}
154 ${h.submit('save',_('Save'),class_="ui-btn large")}
155 ${h.reset('reset',_('Reset'),class_="ui-btn large")}
155 ${h.reset('reset',_('Reset'),class_="ui-btn large")}
156 </div>
156 </div>
157 </div>
157 </div>
158 </div>
158 </div>
159 ${h.end_form()}
159 ${h.end_form()}
160
160
161 ## permissions overview
161 ## permissions overview
162 <div id="perms" class="table">
162 <div id="perms" class="table">
163 %for section in sorted(c.perm_user.permissions.keys()):
163 %for section in sorted(c.perm_user.permissions.keys()):
164 <div class="perms_section_head">${section.replace("_"," ").capitalize()}</div>
164 <div class="perms_section_head">${section.replace("_"," ").capitalize()}</div>
165
165
166 <div id='tbl_list_wrap_${section}' class="yui-skin-sam">
166 <div id='tbl_list_wrap_${section}' class="yui-skin-sam">
167 <table id="tbl_list_${section}">
167 <table id="tbl_list_${section}">
168 <thead>
168 <thead>
169 <tr>
169 <tr>
170 <th class="left">${_('Name')}</th>
170 <th class="left">${_('Name')}</th>
171 <th class="left">${_('Permission')}</th>
171 <th class="left">${_('Permission')}</th>
172 <th class="left">${_('Edit Permission')}</th>
172 </thead>
173 </thead>
173 <tbody>
174 <tbody>
174 %for k in c.perm_user.permissions[section]:
175 %for k in c.perm_user.permissions[section]:
175 <%
176 <%
176 if section != 'global':
177 if section != 'global':
177 section_perm = c.perm_user.permissions[section].get(k)
178 section_perm = c.perm_user.permissions[section].get(k)
178 _perm = section_perm.split('.')[-1]
179 _perm = section_perm.split('.')[-1]
179 else:
180 else:
180 _perm = section_perm = None
181 _perm = section_perm = None
181 %>
182 %>
182 <tr>
183 <tr>
183 <td>
184 <td>
184 %if section == 'repositories':
185 %if section == 'repositories':
185 <a href="${h.url('summary_home',repo_name=k)}">${k}</a>
186 <a href="${h.url('summary_home',repo_name=k)}">${k}</a>
186 %elif section == 'repositories_groups':
187 %elif section == 'repositories_groups':
187 <a href="${h.url('repos_group_home',group_name=k)}">${k}</a>
188 <a href="${h.url('repos_group_home',group_name=k)}">${k}</a>
188 %else:
189 %else:
189 ${h.get_permission_name(k)}
190 ${h.get_permission_name(k)}
190 %endif
191 %endif
191 </td>
192 </td>
192 <td>
193 <td>
193 %if section == 'global':
194 %if section == 'global':
194 ${h.bool2icon(k.split('.')[-1] != 'none')}
195 ${h.bool2icon(k.split('.')[-1] != 'none')}
195 %else:
196 %else:
196 <span class="perm_tag ${_perm}">${section_perm}</span>
197 <span class="perm_tag ${_perm}">${section_perm}</span>
197 %endif
198 %endif
198 </td>
199 </td>
200 <td>
201 %if section == 'repositories':
202 <a href="${h.url('edit_repo',repo_name=k,anchor='permissions_manage')}">${_('edit')}</a>
203 %elif section == 'repositories_groups':
204 <a href="${h.url('edit_repos_group',id=k,anchor='permissions_manage')}">${_('edit')}</a>
205 %else:
206 --
207 %endif
208 </td>
199 </tr>
209 </tr>
200 %endfor
210 %endfor
201 </tbody>
211 </tbody>
202 </table>
212 </table>
203 </div>
213 </div>
204 %endfor
214 %endfor
205 </div>
215 </div>
206 </div>
216 </div>
207 <div class="box box-left">
217 <div class="box box-left">
208 <!-- box / title -->
218 <!-- box / title -->
209 <div class="title">
219 <div class="title">
210 <h5>${_('Email addresses')}</h5>
220 <h5>${_('Email addresses')}</h5>
211 </div>
221 </div>
212
222
213 <div class="emails_wrap">
223 <div class="emails_wrap">
214 <table class="noborder">
224 <table class="noborder">
215 %for em in c.user_email_map:
225 %for em in c.user_email_map:
216 <tr>
226 <tr>
217 <td><div class="gravatar"><img alt="gravatar" src="${h.gravatar_url(em.user.email,16)}"/> </div></td>
227 <td><div class="gravatar"><img alt="gravatar" src="${h.gravatar_url(em.user.email,16)}"/> </div></td>
218 <td><div class="email">${em.email}</div></td>
228 <td><div class="email">${em.email}</div></td>
219 <td>
229 <td>
220 ${h.form(url('user_emails_delete', id=c.user.user_id),method='delete')}
230 ${h.form(url('user_emails_delete', id=c.user.user_id),method='delete')}
221 ${h.hidden('del_email',em.email_id)}
231 ${h.hidden('del_email',em.email_id)}
222 ${h.submit('remove_',_('delete'),id="remove_email_%s" % em.email_id,
232 ${h.submit('remove_',_('delete'),id="remove_email_%s" % em.email_id,
223 class_="delete_icon action_button", onclick="return confirm('"+_('Confirm to delete this email: %s') % em.email+"');")}
233 class_="delete_icon action_button", onclick="return confirm('"+_('Confirm to delete this email: %s') % em.email+"');")}
224 ${h.end_form()}
234 ${h.end_form()}
225 </td>
235 </td>
226 </tr>
236 </tr>
227 %endfor
237 %endfor
228 </table>
238 </table>
229 </div>
239 </div>
230
240
231 ${h.form(url('user_emails', id=c.user.user_id),method='put')}
241 ${h.form(url('user_emails', id=c.user.user_id),method='put')}
232 <div class="form">
242 <div class="form">
233 <!-- fields -->
243 <!-- fields -->
234 <div class="fields">
244 <div class="fields">
235 <div class="field">
245 <div class="field">
236 <div class="label">
246 <div class="label">
237 <label for="email">${_('New email address')}:</label>
247 <label for="email">${_('New email address')}:</label>
238 </div>
248 </div>
239 <div class="input">
249 <div class="input">
240 ${h.text('new_email', class_='medium')}
250 ${h.text('new_email', class_='medium')}
241 </div>
251 </div>
242 </div>
252 </div>
243 <div class="buttons">
253 <div class="buttons">
244 ${h.submit('save',_('Add'),class_="ui-btn large")}
254 ${h.submit('save',_('Add'),class_="ui-btn large")}
245 ${h.reset('reset',_('Reset'),class_="ui-btn large")}
255 ${h.reset('reset',_('Reset'),class_="ui-btn large")}
246 </div>
256 </div>
247 </div>
257 </div>
248 </div>
258 </div>
249 ${h.end_form()}
259 ${h.end_form()}
250 </div>
260 </div>
251 </%def>
261 </%def>
General Comments 0
You need to be logged in to leave comments. Login now