##// END OF EJS Templates
moved permission management into separate entity....
marcink -
r3628:c734686b beta
parent child Browse files
Show More
@@ -1,665 +1,670 b''
1 """
1 """
2 Routes configuration
2 Routes configuration
3
3
4 The more specific and detailed routes should be defined first so they
4 The more specific and detailed routes should be defined first so they
5 may take precedent over the more generic routes. For more information
5 may take precedent over the more generic routes. For more information
6 refer to the routes manual at http://routes.groovie.org/docs/
6 refer to the routes manual at http://routes.groovie.org/docs/
7 """
7 """
8 from __future__ import with_statement
8 from __future__ import with_statement
9 from routes import Mapper
9 from routes import Mapper
10
10
11 # prefix for non repository related links needs to be prefixed with `/`
11 # prefix for non repository related links needs to be prefixed with `/`
12 ADMIN_PREFIX = '/_admin'
12 ADMIN_PREFIX = '/_admin'
13
13
14
14
15 def make_map(config):
15 def make_map(config):
16 """Create, configure and return the routes Mapper"""
16 """Create, configure and return the routes Mapper"""
17 rmap = Mapper(directory=config['pylons.paths']['controllers'],
17 rmap = Mapper(directory=config['pylons.paths']['controllers'],
18 always_scan=config['debug'])
18 always_scan=config['debug'])
19 rmap.minimization = False
19 rmap.minimization = False
20 rmap.explicit = False
20 rmap.explicit = False
21
21
22 from rhodecode.lib.utils import is_valid_repo
22 from rhodecode.lib.utils import is_valid_repo
23 from rhodecode.lib.utils import is_valid_repos_group
23 from rhodecode.lib.utils import is_valid_repos_group
24
24
25 def check_repo(environ, match_dict):
25 def check_repo(environ, match_dict):
26 """
26 """
27 check for valid repository for proper 404 handling
27 check for valid repository for proper 404 handling
28
28
29 :param environ:
29 :param environ:
30 :param match_dict:
30 :param match_dict:
31 """
31 """
32 from rhodecode.model.db import Repository
32 from rhodecode.model.db import Repository
33 repo_name = match_dict.get('repo_name')
33 repo_name = match_dict.get('repo_name')
34
34
35 if match_dict.get('f_path'):
35 if match_dict.get('f_path'):
36 #fix for multiple initial slashes that causes errors
36 #fix for multiple initial slashes that causes errors
37 match_dict['f_path'] = match_dict['f_path'].lstrip('/')
37 match_dict['f_path'] = match_dict['f_path'].lstrip('/')
38
38
39 try:
39 try:
40 by_id = repo_name.split('_')
40 by_id = repo_name.split('_')
41 if len(by_id) == 2 and by_id[1].isdigit() and by_id[0] == '':
41 if len(by_id) == 2 and by_id[1].isdigit() and by_id[0] == '':
42 repo_name = Repository.get(by_id[1]).repo_name
42 repo_name = Repository.get(by_id[1]).repo_name
43 match_dict['repo_name'] = repo_name
43 match_dict['repo_name'] = repo_name
44 except:
44 except:
45 pass
45 pass
46
46
47 return is_valid_repo(repo_name, config['base_path'])
47 return is_valid_repo(repo_name, config['base_path'])
48
48
49 def check_group(environ, match_dict):
49 def check_group(environ, match_dict):
50 """
50 """
51 check for valid repository group for proper 404 handling
51 check for valid repository group for proper 404 handling
52
52
53 :param environ:
53 :param environ:
54 :param match_dict:
54 :param match_dict:
55 """
55 """
56 repos_group_name = match_dict.get('group_name')
56 repos_group_name = match_dict.get('group_name')
57 return is_valid_repos_group(repos_group_name, config['base_path'])
57 return is_valid_repos_group(repos_group_name, config['base_path'])
58
58
59 def check_group_skip_path(environ, match_dict):
59 def check_group_skip_path(environ, match_dict):
60 """
60 """
61 check for valid repository group for proper 404 handling, but skips
61 check for valid repository group for proper 404 handling, but skips
62 verification of existing path
62 verification of existing path
63
63
64 :param environ:
64 :param environ:
65 :param match_dict:
65 :param match_dict:
66 """
66 """
67 repos_group_name = match_dict.get('group_name')
67 repos_group_name = match_dict.get('group_name')
68 return is_valid_repos_group(repos_group_name, config['base_path'],
68 return is_valid_repos_group(repos_group_name, config['base_path'],
69 skip_path_check=True)
69 skip_path_check=True)
70
70
71 def check_int(environ, match_dict):
71 def check_int(environ, match_dict):
72 return match_dict.get('id').isdigit()
72 return match_dict.get('id').isdigit()
73
73
74 # The ErrorController route (handles 404/500 error pages); it should
74 # The ErrorController route (handles 404/500 error pages); it should
75 # likely stay at the top, ensuring it can always be resolved
75 # likely stay at the top, ensuring it can always be resolved
76 rmap.connect('/error/{action}', controller='error')
76 rmap.connect('/error/{action}', controller='error')
77 rmap.connect('/error/{action}/{id}', controller='error')
77 rmap.connect('/error/{action}/{id}', controller='error')
78
78
79 #==========================================================================
79 #==========================================================================
80 # CUSTOM ROUTES HERE
80 # CUSTOM ROUTES HERE
81 #==========================================================================
81 #==========================================================================
82
82
83 #MAIN PAGE
83 #MAIN PAGE
84 rmap.connect('home', '/', controller='home', action='index')
84 rmap.connect('home', '/', controller='home', action='index')
85 rmap.connect('repo_switcher', '/repos', controller='home',
85 rmap.connect('repo_switcher', '/repos', controller='home',
86 action='repo_switcher')
86 action='repo_switcher')
87 rmap.connect('branch_tag_switcher', '/branches-tags/{repo_name:.*?}',
87 rmap.connect('branch_tag_switcher', '/branches-tags/{repo_name:.*?}',
88 controller='home', action='branch_tag_switcher')
88 controller='home', action='branch_tag_switcher')
89 rmap.connect('bugtracker',
89 rmap.connect('bugtracker',
90 "http://bitbucket.org/marcinkuzminski/rhodecode/issues",
90 "http://bitbucket.org/marcinkuzminski/rhodecode/issues",
91 _static=True)
91 _static=True)
92 rmap.connect('rst_help',
92 rmap.connect('rst_help',
93 "http://docutils.sourceforge.net/docs/user/rst/quickref.html",
93 "http://docutils.sourceforge.net/docs/user/rst/quickref.html",
94 _static=True)
94 _static=True)
95 rmap.connect('rhodecode_official', "http://rhodecode.org", _static=True)
95 rmap.connect('rhodecode_official', "http://rhodecode.org", _static=True)
96
96
97 #ADMIN REPOSITORY REST ROUTES
97 #ADMIN REPOSITORY REST ROUTES
98 with rmap.submapper(path_prefix=ADMIN_PREFIX,
98 with rmap.submapper(path_prefix=ADMIN_PREFIX,
99 controller='admin/repos') as m:
99 controller='admin/repos') as m:
100 m.connect("repos", "/repos",
100 m.connect("repos", "/repos",
101 action="create", conditions=dict(method=["POST"]))
101 action="create", conditions=dict(method=["POST"]))
102 m.connect("repos", "/repos",
102 m.connect("repos", "/repos",
103 action="index", conditions=dict(method=["GET"]))
103 action="index", conditions=dict(method=["GET"]))
104 m.connect("formatted_repos", "/repos.{format}",
104 m.connect("formatted_repos", "/repos.{format}",
105 action="index",
105 action="index",
106 conditions=dict(method=["GET"]))
106 conditions=dict(method=["GET"]))
107 m.connect("new_repo", "/repos/new",
107 m.connect("new_repo", "/repos/new",
108 action="new", conditions=dict(method=["GET"]))
108 action="new", conditions=dict(method=["GET"]))
109 m.connect("formatted_new_repo", "/repos/new.{format}",
109 m.connect("formatted_new_repo", "/repos/new.{format}",
110 action="new", conditions=dict(method=["GET"]))
110 action="new", conditions=dict(method=["GET"]))
111 m.connect("/repos/{repo_name:.*?}",
111 m.connect("/repos/{repo_name:.*?}",
112 action="update", conditions=dict(method=["PUT"],
112 action="update", conditions=dict(method=["PUT"],
113 function=check_repo))
113 function=check_repo))
114 m.connect("/repos/{repo_name:.*?}",
114 m.connect("/repos/{repo_name:.*?}",
115 action="delete", conditions=dict(method=["DELETE"],
115 action="delete", conditions=dict(method=["DELETE"],
116 function=check_repo))
116 function=check_repo))
117 # no longer used:
117 # no longer used:
118 m.connect("edit_repo_admin", "/repos/{repo_name:.*?}/edit",
118 m.connect("edit_repo_admin", "/repos/{repo_name:.*?}/edit",
119 action="edit", conditions=dict(method=["GET"],
119 action="edit", conditions=dict(method=["GET"],
120 function=check_repo))
120 function=check_repo))
121 m.connect("formatted_edit_repo", "/repos/{repo_name:.*?}.{format}/edit",
121 m.connect("formatted_edit_repo", "/repos/{repo_name:.*?}.{format}/edit",
122 action="edit", conditions=dict(method=["GET"],
122 action="edit", conditions=dict(method=["GET"],
123 function=check_repo))
123 function=check_repo))
124 m.connect("repo", "/repos/{repo_name:.*?}",
124 m.connect("repo", "/repos/{repo_name:.*?}",
125 action="show", conditions=dict(method=["GET"],
125 action="show", conditions=dict(method=["GET"],
126 function=check_repo))
126 function=check_repo))
127 m.connect("formatted_repo", "/repos/{repo_name:.*?}.{format}",
127 m.connect("formatted_repo", "/repos/{repo_name:.*?}.{format}",
128 action="show", conditions=dict(method=["GET"],
128 action="show", conditions=dict(method=["GET"],
129 function=check_repo))
129 function=check_repo))
130 #add repo perm member
131 m.connect('set_repo_perm_member', "/set_repo_perm_member/{repo_name:.*?}",
132 action="set_repo_perm_member",
133 conditions=dict(method=["POST"], function=check_repo))
134
130 #ajax delete repo perm user
135 #ajax delete repo perm user
131 m.connect('delete_repo_user', "/repos_delete_user/{repo_name:.*?}",
136 m.connect('delete_repo_user', "/repos_delete_user/{repo_name:.*?}",
132 action="delete_perm_user",
137 action="delete_perm_user",
133 conditions=dict(method=["DELETE"], function=check_repo))
138 conditions=dict(method=["DELETE"], function=check_repo))
134
139
135 #ajax delete repo perm users_group
140 #ajax delete repo perm users_group
136 m.connect('delete_repo_users_group',
141 m.connect('delete_repo_users_group',
137 "/repos_delete_users_group/{repo_name:.*?}",
142 "/repos_delete_users_group/{repo_name:.*?}",
138 action="delete_perm_users_group",
143 action="delete_perm_users_group",
139 conditions=dict(method=["DELETE"], function=check_repo))
144 conditions=dict(method=["DELETE"], function=check_repo))
140
145
141 #settings actions
146 #settings actions
142 m.connect('repo_stats', "/repos_stats/{repo_name:.*?}",
147 m.connect('repo_stats', "/repos_stats/{repo_name:.*?}",
143 action="repo_stats", conditions=dict(method=["DELETE"],
148 action="repo_stats", conditions=dict(method=["DELETE"],
144 function=check_repo))
149 function=check_repo))
145 m.connect('repo_cache', "/repos_cache/{repo_name:.*?}",
150 m.connect('repo_cache', "/repos_cache/{repo_name:.*?}",
146 action="repo_cache", conditions=dict(method=["DELETE"],
151 action="repo_cache", conditions=dict(method=["DELETE"],
147 function=check_repo))
152 function=check_repo))
148 m.connect('repo_public_journal', "/repos_public_journal/{repo_name:.*?}",
153 m.connect('repo_public_journal', "/repos_public_journal/{repo_name:.*?}",
149 action="repo_public_journal", conditions=dict(method=["PUT"],
154 action="repo_public_journal", conditions=dict(method=["PUT"],
150 function=check_repo))
155 function=check_repo))
151 m.connect('repo_pull', "/repo_pull/{repo_name:.*?}",
156 m.connect('repo_pull', "/repo_pull/{repo_name:.*?}",
152 action="repo_pull", conditions=dict(method=["PUT"],
157 action="repo_pull", conditions=dict(method=["PUT"],
153 function=check_repo))
158 function=check_repo))
154 m.connect('repo_as_fork', "/repo_as_fork/{repo_name:.*?}",
159 m.connect('repo_as_fork', "/repo_as_fork/{repo_name:.*?}",
155 action="repo_as_fork", conditions=dict(method=["PUT"],
160 action="repo_as_fork", conditions=dict(method=["PUT"],
156 function=check_repo))
161 function=check_repo))
157 m.connect('repo_locking', "/repo_locking/{repo_name:.*?}",
162 m.connect('repo_locking', "/repo_locking/{repo_name:.*?}",
158 action="repo_locking", conditions=dict(method=["PUT"],
163 action="repo_locking", conditions=dict(method=["PUT"],
159 function=check_repo))
164 function=check_repo))
160 #repo fields
165 #repo fields
161 m.connect('create_repo_fields', "/repo_fields/{repo_name:.*?}/new",
166 m.connect('create_repo_fields', "/repo_fields/{repo_name:.*?}/new",
162 action="create_repo_field", conditions=dict(method=["PUT"],
167 action="create_repo_field", conditions=dict(method=["PUT"],
163 function=check_repo))
168 function=check_repo))
164
169
165 m.connect('delete_repo_fields', "/repo_fields/{repo_name:.*?}/{field_id}",
170 m.connect('delete_repo_fields', "/repo_fields/{repo_name:.*?}/{field_id}",
166 action="delete_repo_field", conditions=dict(method=["DELETE"],
171 action="delete_repo_field", conditions=dict(method=["DELETE"],
167 function=check_repo))
172 function=check_repo))
168
173
169 with rmap.submapper(path_prefix=ADMIN_PREFIX,
174 with rmap.submapper(path_prefix=ADMIN_PREFIX,
170 controller='admin/repos_groups') as m:
175 controller='admin/repos_groups') as m:
171 m.connect("repos_groups", "/repos_groups",
176 m.connect("repos_groups", "/repos_groups",
172 action="create", conditions=dict(method=["POST"]))
177 action="create", conditions=dict(method=["POST"]))
173 m.connect("repos_groups", "/repos_groups",
178 m.connect("repos_groups", "/repos_groups",
174 action="index", conditions=dict(method=["GET"]))
179 action="index", conditions=dict(method=["GET"]))
175 m.connect("formatted_repos_groups", "/repos_groups.{format}",
180 m.connect("formatted_repos_groups", "/repos_groups.{format}",
176 action="index", conditions=dict(method=["GET"]))
181 action="index", conditions=dict(method=["GET"]))
177 m.connect("new_repos_group", "/repos_groups/new",
182 m.connect("new_repos_group", "/repos_groups/new",
178 action="new", conditions=dict(method=["GET"]))
183 action="new", conditions=dict(method=["GET"]))
179 m.connect("formatted_new_repos_group", "/repos_groups/new.{format}",
184 m.connect("formatted_new_repos_group", "/repos_groups/new.{format}",
180 action="new", conditions=dict(method=["GET"]))
185 action="new", conditions=dict(method=["GET"]))
181 m.connect("update_repos_group", "/repos_groups/{group_name:.*?}",
186 m.connect("update_repos_group", "/repos_groups/{group_name:.*?}",
182 action="update", conditions=dict(method=["PUT"],
187 action="update", conditions=dict(method=["PUT"],
183 function=check_group))
188 function=check_group))
184 m.connect("delete_repos_group", "/repos_groups/{group_name:.*?}",
189 m.connect("delete_repos_group", "/repos_groups/{group_name:.*?}",
185 action="delete", conditions=dict(method=["DELETE"],
190 action="delete", conditions=dict(method=["DELETE"],
186 function=check_group_skip_path))
191 function=check_group_skip_path))
187 m.connect("edit_repos_group", "/repos_groups/{group_name:.*?}/edit",
192 m.connect("edit_repos_group", "/repos_groups/{group_name:.*?}/edit",
188 action="edit", conditions=dict(method=["GET"],
193 action="edit", conditions=dict(method=["GET"],
189 function=check_group))
194 function=check_group))
190 m.connect("formatted_edit_repos_group",
195 m.connect("formatted_edit_repos_group",
191 "/repos_groups/{group_name:.*?}.{format}/edit",
196 "/repos_groups/{group_name:.*?}.{format}/edit",
192 action="edit", conditions=dict(method=["GET"],
197 action="edit", conditions=dict(method=["GET"],
193 function=check_group))
198 function=check_group))
194 m.connect("repos_group", "/repos_groups/{group_name:.*?}",
199 m.connect("repos_group", "/repos_groups/{group_name:.*?}",
195 action="show", conditions=dict(method=["GET"],
200 action="show", conditions=dict(method=["GET"],
196 function=check_group))
201 function=check_group))
197 m.connect("formatted_repos_group", "/repos_groups/{group_name:.*?}.{format}",
202 m.connect("formatted_repos_group", "/repos_groups/{group_name:.*?}.{format}",
198 action="show", conditions=dict(method=["GET"],
203 action="show", conditions=dict(method=["GET"],
199 function=check_group))
204 function=check_group))
200 # ajax delete repos group perm user
205 # ajax delete repos group perm user
201 m.connect('delete_repos_group_user_perm',
206 m.connect('delete_repos_group_user_perm',
202 "/delete_repos_group_user_perm/{group_name:.*?}",
207 "/delete_repos_group_user_perm/{group_name:.*?}",
203 action="delete_repos_group_user_perm",
208 action="delete_repos_group_user_perm",
204 conditions=dict(method=["DELETE"], function=check_group))
209 conditions=dict(method=["DELETE"], function=check_group))
205
210
206 # ajax delete repos group perm users_group
211 # ajax delete repos group perm users_group
207 m.connect('delete_repos_group_users_group_perm',
212 m.connect('delete_repos_group_users_group_perm',
208 "/delete_repos_group_users_group_perm/{group_name:.*?}",
213 "/delete_repos_group_users_group_perm/{group_name:.*?}",
209 action="delete_repos_group_users_group_perm",
214 action="delete_repos_group_users_group_perm",
210 conditions=dict(method=["DELETE"], function=check_group))
215 conditions=dict(method=["DELETE"], function=check_group))
211
216
212 #ADMIN USER REST ROUTES
217 #ADMIN USER REST ROUTES
213 with rmap.submapper(path_prefix=ADMIN_PREFIX,
218 with rmap.submapper(path_prefix=ADMIN_PREFIX,
214 controller='admin/users') as m:
219 controller='admin/users') as m:
215 m.connect("users", "/users",
220 m.connect("users", "/users",
216 action="create", conditions=dict(method=["POST"]))
221 action="create", conditions=dict(method=["POST"]))
217 m.connect("users", "/users",
222 m.connect("users", "/users",
218 action="index", conditions=dict(method=["GET"]))
223 action="index", conditions=dict(method=["GET"]))
219 m.connect("formatted_users", "/users.{format}",
224 m.connect("formatted_users", "/users.{format}",
220 action="index", conditions=dict(method=["GET"]))
225 action="index", conditions=dict(method=["GET"]))
221 m.connect("new_user", "/users/new",
226 m.connect("new_user", "/users/new",
222 action="new", conditions=dict(method=["GET"]))
227 action="new", conditions=dict(method=["GET"]))
223 m.connect("formatted_new_user", "/users/new.{format}",
228 m.connect("formatted_new_user", "/users/new.{format}",
224 action="new", conditions=dict(method=["GET"]))
229 action="new", conditions=dict(method=["GET"]))
225 m.connect("update_user", "/users/{id}",
230 m.connect("update_user", "/users/{id}",
226 action="update", conditions=dict(method=["PUT"]))
231 action="update", conditions=dict(method=["PUT"]))
227 m.connect("delete_user", "/users/{id}",
232 m.connect("delete_user", "/users/{id}",
228 action="delete", conditions=dict(method=["DELETE"]))
233 action="delete", conditions=dict(method=["DELETE"]))
229 m.connect("edit_user", "/users/{id}/edit",
234 m.connect("edit_user", "/users/{id}/edit",
230 action="edit", conditions=dict(method=["GET"]))
235 action="edit", conditions=dict(method=["GET"]))
231 m.connect("formatted_edit_user",
236 m.connect("formatted_edit_user",
232 "/users/{id}.{format}/edit",
237 "/users/{id}.{format}/edit",
233 action="edit", conditions=dict(method=["GET"]))
238 action="edit", conditions=dict(method=["GET"]))
234 m.connect("user", "/users/{id}",
239 m.connect("user", "/users/{id}",
235 action="show", conditions=dict(method=["GET"]))
240 action="show", conditions=dict(method=["GET"]))
236 m.connect("formatted_user", "/users/{id}.{format}",
241 m.connect("formatted_user", "/users/{id}.{format}",
237 action="show", conditions=dict(method=["GET"]))
242 action="show", conditions=dict(method=["GET"]))
238
243
239 #EXTRAS USER ROUTES
244 #EXTRAS USER ROUTES
240 m.connect("user_perm", "/users_perm/{id}",
245 m.connect("user_perm", "/users_perm/{id}",
241 action="update_perm", conditions=dict(method=["PUT"]))
246 action="update_perm", conditions=dict(method=["PUT"]))
242 m.connect("user_emails", "/users_emails/{id}",
247 m.connect("user_emails", "/users_emails/{id}",
243 action="add_email", conditions=dict(method=["PUT"]))
248 action="add_email", conditions=dict(method=["PUT"]))
244 m.connect("user_emails_delete", "/users_emails/{id}",
249 m.connect("user_emails_delete", "/users_emails/{id}",
245 action="delete_email", conditions=dict(method=["DELETE"]))
250 action="delete_email", conditions=dict(method=["DELETE"]))
246 m.connect("user_ips", "/users_ips/{id}",
251 m.connect("user_ips", "/users_ips/{id}",
247 action="add_ip", conditions=dict(method=["PUT"]))
252 action="add_ip", conditions=dict(method=["PUT"]))
248 m.connect("user_ips_delete", "/users_ips/{id}",
253 m.connect("user_ips_delete", "/users_ips/{id}",
249 action="delete_ip", conditions=dict(method=["DELETE"]))
254 action="delete_ip", conditions=dict(method=["DELETE"]))
250
255
251 #ADMIN USER GROUPS REST ROUTES
256 #ADMIN USER GROUPS REST ROUTES
252 with rmap.submapper(path_prefix=ADMIN_PREFIX,
257 with rmap.submapper(path_prefix=ADMIN_PREFIX,
253 controller='admin/users_groups') as m:
258 controller='admin/users_groups') as m:
254 m.connect("users_groups", "/users_groups",
259 m.connect("users_groups", "/users_groups",
255 action="create", conditions=dict(method=["POST"]))
260 action="create", conditions=dict(method=["POST"]))
256 m.connect("users_groups", "/users_groups",
261 m.connect("users_groups", "/users_groups",
257 action="index", conditions=dict(method=["GET"]))
262 action="index", conditions=dict(method=["GET"]))
258 m.connect("formatted_users_groups", "/users_groups.{format}",
263 m.connect("formatted_users_groups", "/users_groups.{format}",
259 action="index", conditions=dict(method=["GET"]))
264 action="index", conditions=dict(method=["GET"]))
260 m.connect("new_users_group", "/users_groups/new",
265 m.connect("new_users_group", "/users_groups/new",
261 action="new", conditions=dict(method=["GET"]))
266 action="new", conditions=dict(method=["GET"]))
262 m.connect("formatted_new_users_group", "/users_groups/new.{format}",
267 m.connect("formatted_new_users_group", "/users_groups/new.{format}",
263 action="new", conditions=dict(method=["GET"]))
268 action="new", conditions=dict(method=["GET"]))
264 m.connect("update_users_group", "/users_groups/{id}",
269 m.connect("update_users_group", "/users_groups/{id}",
265 action="update", conditions=dict(method=["PUT"]))
270 action="update", conditions=dict(method=["PUT"]))
266 m.connect("delete_users_group", "/users_groups/{id}",
271 m.connect("delete_users_group", "/users_groups/{id}",
267 action="delete", conditions=dict(method=["DELETE"]))
272 action="delete", conditions=dict(method=["DELETE"]))
268 m.connect("edit_users_group", "/users_groups/{id}/edit",
273 m.connect("edit_users_group", "/users_groups/{id}/edit",
269 action="edit", conditions=dict(method=["GET"]))
274 action="edit", conditions=dict(method=["GET"]))
270 m.connect("formatted_edit_users_group",
275 m.connect("formatted_edit_users_group",
271 "/users_groups/{id}.{format}/edit",
276 "/users_groups/{id}.{format}/edit",
272 action="edit", conditions=dict(method=["GET"]))
277 action="edit", conditions=dict(method=["GET"]))
273 m.connect("users_group", "/users_groups/{id}",
278 m.connect("users_group", "/users_groups/{id}",
274 action="show", conditions=dict(method=["GET"]))
279 action="show", conditions=dict(method=["GET"]))
275 m.connect("formatted_users_group", "/users_groups/{id}.{format}",
280 m.connect("formatted_users_group", "/users_groups/{id}.{format}",
276 action="show", conditions=dict(method=["GET"]))
281 action="show", conditions=dict(method=["GET"]))
277
282
278 #EXTRAS USER ROUTES
283 #EXTRAS USER ROUTES
279 m.connect("users_group_perm", "/users_groups_perm/{id}",
284 m.connect("users_group_perm", "/users_groups_perm/{id}",
280 action="update_perm", conditions=dict(method=["PUT"]))
285 action="update_perm", conditions=dict(method=["PUT"]))
281
286
282 #ADMIN GROUP REST ROUTES
287 #ADMIN GROUP REST ROUTES
283 rmap.resource('group', 'groups',
288 rmap.resource('group', 'groups',
284 controller='admin/groups', path_prefix=ADMIN_PREFIX)
289 controller='admin/groups', path_prefix=ADMIN_PREFIX)
285
290
286 #ADMIN PERMISSIONS REST ROUTES
291 #ADMIN PERMISSIONS REST ROUTES
287 rmap.resource('permission', 'permissions',
292 rmap.resource('permission', 'permissions',
288 controller='admin/permissions', path_prefix=ADMIN_PREFIX)
293 controller='admin/permissions', path_prefix=ADMIN_PREFIX)
289
294
290 #ADMIN DEFAULTS REST ROUTES
295 #ADMIN DEFAULTS REST ROUTES
291 rmap.resource('default', 'defaults',
296 rmap.resource('default', 'defaults',
292 controller='admin/defaults', path_prefix=ADMIN_PREFIX)
297 controller='admin/defaults', path_prefix=ADMIN_PREFIX)
293
298
294 ##ADMIN LDAP SETTINGS
299 ##ADMIN LDAP SETTINGS
295 rmap.connect('ldap_settings', '%s/ldap' % ADMIN_PREFIX,
300 rmap.connect('ldap_settings', '%s/ldap' % ADMIN_PREFIX,
296 controller='admin/ldap_settings', action='ldap_settings',
301 controller='admin/ldap_settings', action='ldap_settings',
297 conditions=dict(method=["POST"]))
302 conditions=dict(method=["POST"]))
298
303
299 rmap.connect('ldap_home', '%s/ldap' % ADMIN_PREFIX,
304 rmap.connect('ldap_home', '%s/ldap' % ADMIN_PREFIX,
300 controller='admin/ldap_settings')
305 controller='admin/ldap_settings')
301
306
302 #ADMIN SETTINGS REST ROUTES
307 #ADMIN SETTINGS REST ROUTES
303 with rmap.submapper(path_prefix=ADMIN_PREFIX,
308 with rmap.submapper(path_prefix=ADMIN_PREFIX,
304 controller='admin/settings') as m:
309 controller='admin/settings') as m:
305 m.connect("admin_settings", "/settings",
310 m.connect("admin_settings", "/settings",
306 action="create", conditions=dict(method=["POST"]))
311 action="create", conditions=dict(method=["POST"]))
307 m.connect("admin_settings", "/settings",
312 m.connect("admin_settings", "/settings",
308 action="index", conditions=dict(method=["GET"]))
313 action="index", conditions=dict(method=["GET"]))
309 m.connect("formatted_admin_settings", "/settings.{format}",
314 m.connect("formatted_admin_settings", "/settings.{format}",
310 action="index", conditions=dict(method=["GET"]))
315 action="index", conditions=dict(method=["GET"]))
311 m.connect("admin_new_setting", "/settings/new",
316 m.connect("admin_new_setting", "/settings/new",
312 action="new", conditions=dict(method=["GET"]))
317 action="new", conditions=dict(method=["GET"]))
313 m.connect("formatted_admin_new_setting", "/settings/new.{format}",
318 m.connect("formatted_admin_new_setting", "/settings/new.{format}",
314 action="new", conditions=dict(method=["GET"]))
319 action="new", conditions=dict(method=["GET"]))
315 m.connect("/settings/{setting_id}",
320 m.connect("/settings/{setting_id}",
316 action="update", conditions=dict(method=["PUT"]))
321 action="update", conditions=dict(method=["PUT"]))
317 m.connect("/settings/{setting_id}",
322 m.connect("/settings/{setting_id}",
318 action="delete", conditions=dict(method=["DELETE"]))
323 action="delete", conditions=dict(method=["DELETE"]))
319 m.connect("admin_edit_setting", "/settings/{setting_id}/edit",
324 m.connect("admin_edit_setting", "/settings/{setting_id}/edit",
320 action="edit", conditions=dict(method=["GET"]))
325 action="edit", conditions=dict(method=["GET"]))
321 m.connect("formatted_admin_edit_setting",
326 m.connect("formatted_admin_edit_setting",
322 "/settings/{setting_id}.{format}/edit",
327 "/settings/{setting_id}.{format}/edit",
323 action="edit", conditions=dict(method=["GET"]))
328 action="edit", conditions=dict(method=["GET"]))
324 m.connect("admin_setting", "/settings/{setting_id}",
329 m.connect("admin_setting", "/settings/{setting_id}",
325 action="show", conditions=dict(method=["GET"]))
330 action="show", conditions=dict(method=["GET"]))
326 m.connect("formatted_admin_setting", "/settings/{setting_id}.{format}",
331 m.connect("formatted_admin_setting", "/settings/{setting_id}.{format}",
327 action="show", conditions=dict(method=["GET"]))
332 action="show", conditions=dict(method=["GET"]))
328 m.connect("admin_settings_my_account", "/my_account",
333 m.connect("admin_settings_my_account", "/my_account",
329 action="my_account", conditions=dict(method=["GET"]))
334 action="my_account", conditions=dict(method=["GET"]))
330 m.connect("admin_settings_my_account_update", "/my_account_update",
335 m.connect("admin_settings_my_account_update", "/my_account_update",
331 action="my_account_update", conditions=dict(method=["PUT"]))
336 action="my_account_update", conditions=dict(method=["PUT"]))
332 m.connect("admin_settings_create_repository", "/create_repository",
337 m.connect("admin_settings_create_repository", "/create_repository",
333 action="create_repository", conditions=dict(method=["GET"]))
338 action="create_repository", conditions=dict(method=["GET"]))
334 m.connect("admin_settings_my_repos", "/my_account/repos",
339 m.connect("admin_settings_my_repos", "/my_account/repos",
335 action="my_account_my_repos", conditions=dict(method=["GET"]))
340 action="my_account_my_repos", conditions=dict(method=["GET"]))
336 m.connect("admin_settings_my_pullrequests", "/my_account/pull_requests",
341 m.connect("admin_settings_my_pullrequests", "/my_account/pull_requests",
337 action="my_account_my_pullrequests", conditions=dict(method=["GET"]))
342 action="my_account_my_pullrequests", conditions=dict(method=["GET"]))
338
343
339 #NOTIFICATION REST ROUTES
344 #NOTIFICATION REST ROUTES
340 with rmap.submapper(path_prefix=ADMIN_PREFIX,
345 with rmap.submapper(path_prefix=ADMIN_PREFIX,
341 controller='admin/notifications') as m:
346 controller='admin/notifications') as m:
342 m.connect("notifications", "/notifications",
347 m.connect("notifications", "/notifications",
343 action="create", conditions=dict(method=["POST"]))
348 action="create", conditions=dict(method=["POST"]))
344 m.connect("notifications", "/notifications",
349 m.connect("notifications", "/notifications",
345 action="index", conditions=dict(method=["GET"]))
350 action="index", conditions=dict(method=["GET"]))
346 m.connect("notifications_mark_all_read", "/notifications/mark_all_read",
351 m.connect("notifications_mark_all_read", "/notifications/mark_all_read",
347 action="mark_all_read", conditions=dict(method=["GET"]))
352 action="mark_all_read", conditions=dict(method=["GET"]))
348 m.connect("formatted_notifications", "/notifications.{format}",
353 m.connect("formatted_notifications", "/notifications.{format}",
349 action="index", conditions=dict(method=["GET"]))
354 action="index", conditions=dict(method=["GET"]))
350 m.connect("new_notification", "/notifications/new",
355 m.connect("new_notification", "/notifications/new",
351 action="new", conditions=dict(method=["GET"]))
356 action="new", conditions=dict(method=["GET"]))
352 m.connect("formatted_new_notification", "/notifications/new.{format}",
357 m.connect("formatted_new_notification", "/notifications/new.{format}",
353 action="new", conditions=dict(method=["GET"]))
358 action="new", conditions=dict(method=["GET"]))
354 m.connect("/notification/{notification_id}",
359 m.connect("/notification/{notification_id}",
355 action="update", conditions=dict(method=["PUT"]))
360 action="update", conditions=dict(method=["PUT"]))
356 m.connect("/notification/{notification_id}",
361 m.connect("/notification/{notification_id}",
357 action="delete", conditions=dict(method=["DELETE"]))
362 action="delete", conditions=dict(method=["DELETE"]))
358 m.connect("edit_notification", "/notification/{notification_id}/edit",
363 m.connect("edit_notification", "/notification/{notification_id}/edit",
359 action="edit", conditions=dict(method=["GET"]))
364 action="edit", conditions=dict(method=["GET"]))
360 m.connect("formatted_edit_notification",
365 m.connect("formatted_edit_notification",
361 "/notification/{notification_id}.{format}/edit",
366 "/notification/{notification_id}.{format}/edit",
362 action="edit", conditions=dict(method=["GET"]))
367 action="edit", conditions=dict(method=["GET"]))
363 m.connect("notification", "/notification/{notification_id}",
368 m.connect("notification", "/notification/{notification_id}",
364 action="show", conditions=dict(method=["GET"]))
369 action="show", conditions=dict(method=["GET"]))
365 m.connect("formatted_notification", "/notifications/{notification_id}.{format}",
370 m.connect("formatted_notification", "/notifications/{notification_id}.{format}",
366 action="show", conditions=dict(method=["GET"]))
371 action="show", conditions=dict(method=["GET"]))
367
372
368 #ADMIN MAIN PAGES
373 #ADMIN MAIN PAGES
369 with rmap.submapper(path_prefix=ADMIN_PREFIX,
374 with rmap.submapper(path_prefix=ADMIN_PREFIX,
370 controller='admin/admin') as m:
375 controller='admin/admin') as m:
371 m.connect('admin_home', '', action='index')
376 m.connect('admin_home', '', action='index')
372 m.connect('admin_add_repo', '/add_repo/{new_repo:[a-z0-9\. _-]*}',
377 m.connect('admin_add_repo', '/add_repo/{new_repo:[a-z0-9\. _-]*}',
373 action='add_repo')
378 action='add_repo')
374
379
375 #==========================================================================
380 #==========================================================================
376 # API V2
381 # API V2
377 #==========================================================================
382 #==========================================================================
378 with rmap.submapper(path_prefix=ADMIN_PREFIX,
383 with rmap.submapper(path_prefix=ADMIN_PREFIX,
379 controller='api/api') as m:
384 controller='api/api') as m:
380 m.connect('api', '/api')
385 m.connect('api', '/api')
381
386
382 #USER JOURNAL
387 #USER JOURNAL
383 rmap.connect('journal', '%s/journal' % ADMIN_PREFIX,
388 rmap.connect('journal', '%s/journal' % ADMIN_PREFIX,
384 controller='journal', action='index')
389 controller='journal', action='index')
385 rmap.connect('journal_rss', '%s/journal/rss' % ADMIN_PREFIX,
390 rmap.connect('journal_rss', '%s/journal/rss' % ADMIN_PREFIX,
386 controller='journal', action='journal_rss')
391 controller='journal', action='journal_rss')
387 rmap.connect('journal_atom', '%s/journal/atom' % ADMIN_PREFIX,
392 rmap.connect('journal_atom', '%s/journal/atom' % ADMIN_PREFIX,
388 controller='journal', action='journal_atom')
393 controller='journal', action='journal_atom')
389
394
390 rmap.connect('public_journal', '%s/public_journal' % ADMIN_PREFIX,
395 rmap.connect('public_journal', '%s/public_journal' % ADMIN_PREFIX,
391 controller='journal', action="public_journal")
396 controller='journal', action="public_journal")
392
397
393 rmap.connect('public_journal_rss', '%s/public_journal/rss' % ADMIN_PREFIX,
398 rmap.connect('public_journal_rss', '%s/public_journal/rss' % ADMIN_PREFIX,
394 controller='journal', action="public_journal_rss")
399 controller='journal', action="public_journal_rss")
395
400
396 rmap.connect('public_journal_rss_old', '%s/public_journal_rss' % ADMIN_PREFIX,
401 rmap.connect('public_journal_rss_old', '%s/public_journal_rss' % ADMIN_PREFIX,
397 controller='journal', action="public_journal_rss")
402 controller='journal', action="public_journal_rss")
398
403
399 rmap.connect('public_journal_atom',
404 rmap.connect('public_journal_atom',
400 '%s/public_journal/atom' % ADMIN_PREFIX, controller='journal',
405 '%s/public_journal/atom' % ADMIN_PREFIX, controller='journal',
401 action="public_journal_atom")
406 action="public_journal_atom")
402
407
403 rmap.connect('public_journal_atom_old',
408 rmap.connect('public_journal_atom_old',
404 '%s/public_journal_atom' % ADMIN_PREFIX, controller='journal',
409 '%s/public_journal_atom' % ADMIN_PREFIX, controller='journal',
405 action="public_journal_atom")
410 action="public_journal_atom")
406
411
407 rmap.connect('toggle_following', '%s/toggle_following' % ADMIN_PREFIX,
412 rmap.connect('toggle_following', '%s/toggle_following' % ADMIN_PREFIX,
408 controller='journal', action='toggle_following',
413 controller='journal', action='toggle_following',
409 conditions=dict(method=["POST"]))
414 conditions=dict(method=["POST"]))
410
415
411 #SEARCH
416 #SEARCH
412 rmap.connect('search', '%s/search' % ADMIN_PREFIX, controller='search',)
417 rmap.connect('search', '%s/search' % ADMIN_PREFIX, controller='search',)
413 rmap.connect('search_repo_admin', '%s/search/{repo_name:.*}' % ADMIN_PREFIX,
418 rmap.connect('search_repo_admin', '%s/search/{repo_name:.*}' % ADMIN_PREFIX,
414 controller='search',
419 controller='search',
415 conditions=dict(function=check_repo))
420 conditions=dict(function=check_repo))
416 rmap.connect('search_repo', '/{repo_name:.*?}/search',
421 rmap.connect('search_repo', '/{repo_name:.*?}/search',
417 controller='search',
422 controller='search',
418 conditions=dict(function=check_repo),
423 conditions=dict(function=check_repo),
419 )
424 )
420
425
421 #LOGIN/LOGOUT/REGISTER/SIGN IN
426 #LOGIN/LOGOUT/REGISTER/SIGN IN
422 rmap.connect('login_home', '%s/login' % ADMIN_PREFIX, controller='login')
427 rmap.connect('login_home', '%s/login' % ADMIN_PREFIX, controller='login')
423 rmap.connect('logout_home', '%s/logout' % ADMIN_PREFIX, controller='login',
428 rmap.connect('logout_home', '%s/logout' % ADMIN_PREFIX, controller='login',
424 action='logout')
429 action='logout')
425
430
426 rmap.connect('register', '%s/register' % ADMIN_PREFIX, controller='login',
431 rmap.connect('register', '%s/register' % ADMIN_PREFIX, controller='login',
427 action='register')
432 action='register')
428
433
429 rmap.connect('reset_password', '%s/password_reset' % ADMIN_PREFIX,
434 rmap.connect('reset_password', '%s/password_reset' % ADMIN_PREFIX,
430 controller='login', action='password_reset')
435 controller='login', action='password_reset')
431
436
432 rmap.connect('reset_password_confirmation',
437 rmap.connect('reset_password_confirmation',
433 '%s/password_reset_confirmation' % ADMIN_PREFIX,
438 '%s/password_reset_confirmation' % ADMIN_PREFIX,
434 controller='login', action='password_reset_confirmation')
439 controller='login', action='password_reset_confirmation')
435
440
436 #FEEDS
441 #FEEDS
437 rmap.connect('rss_feed_home', '/{repo_name:.*?}/feed/rss',
442 rmap.connect('rss_feed_home', '/{repo_name:.*?}/feed/rss',
438 controller='feed', action='rss',
443 controller='feed', action='rss',
439 conditions=dict(function=check_repo))
444 conditions=dict(function=check_repo))
440
445
441 rmap.connect('atom_feed_home', '/{repo_name:.*?}/feed/atom',
446 rmap.connect('atom_feed_home', '/{repo_name:.*?}/feed/atom',
442 controller='feed', action='atom',
447 controller='feed', action='atom',
443 conditions=dict(function=check_repo))
448 conditions=dict(function=check_repo))
444
449
445 #==========================================================================
450 #==========================================================================
446 # REPOSITORY ROUTES
451 # REPOSITORY ROUTES
447 #==========================================================================
452 #==========================================================================
448 rmap.connect('summary_home', '/{repo_name:.*?}',
453 rmap.connect('summary_home', '/{repo_name:.*?}',
449 controller='summary',
454 controller='summary',
450 conditions=dict(function=check_repo))
455 conditions=dict(function=check_repo))
451
456
452 rmap.connect('repo_size', '/{repo_name:.*?}/repo_size',
457 rmap.connect('repo_size', '/{repo_name:.*?}/repo_size',
453 controller='summary', action='repo_size',
458 controller='summary', action='repo_size',
454 conditions=dict(function=check_repo))
459 conditions=dict(function=check_repo))
455
460
456 rmap.connect('repos_group_home', '/{group_name:.*}',
461 rmap.connect('repos_group_home', '/{group_name:.*}',
457 controller='admin/repos_groups', action="show_by_name",
462 controller='admin/repos_groups', action="show_by_name",
458 conditions=dict(function=check_group))
463 conditions=dict(function=check_group))
459
464
460 rmap.connect('changeset_home', '/{repo_name:.*?}/changeset/{revision}',
465 rmap.connect('changeset_home', '/{repo_name:.*?}/changeset/{revision}',
461 controller='changeset', revision='tip',
466 controller='changeset', revision='tip',
462 conditions=dict(function=check_repo))
467 conditions=dict(function=check_repo))
463
468
464 rmap.connect("edit_repo", "/{repo_name:.*?}/edit",
469 rmap.connect("edit_repo", "/{repo_name:.*?}/edit",
465 controller='admin/repos', action="edit",
470 controller='admin/repos', action="edit",
466 conditions=dict(method=["GET"], function=check_repo)
471 conditions=dict(method=["GET"], function=check_repo)
467 )
472 )
468
473
469 #still working url for backward compat.
474 #still working url for backward compat.
470 rmap.connect('raw_changeset_home_depraced',
475 rmap.connect('raw_changeset_home_depraced',
471 '/{repo_name:.*?}/raw-changeset/{revision}',
476 '/{repo_name:.*?}/raw-changeset/{revision}',
472 controller='changeset', action='changeset_raw',
477 controller='changeset', action='changeset_raw',
473 revision='tip', conditions=dict(function=check_repo))
478 revision='tip', conditions=dict(function=check_repo))
474
479
475 ## new URLs
480 ## new URLs
476 rmap.connect('changeset_raw_home',
481 rmap.connect('changeset_raw_home',
477 '/{repo_name:.*?}/changeset-diff/{revision}',
482 '/{repo_name:.*?}/changeset-diff/{revision}',
478 controller='changeset', action='changeset_raw',
483 controller='changeset', action='changeset_raw',
479 revision='tip', conditions=dict(function=check_repo))
484 revision='tip', conditions=dict(function=check_repo))
480
485
481 rmap.connect('changeset_patch_home',
486 rmap.connect('changeset_patch_home',
482 '/{repo_name:.*?}/changeset-patch/{revision}',
487 '/{repo_name:.*?}/changeset-patch/{revision}',
483 controller='changeset', action='changeset_patch',
488 controller='changeset', action='changeset_patch',
484 revision='tip', conditions=dict(function=check_repo))
489 revision='tip', conditions=dict(function=check_repo))
485
490
486 rmap.connect('changeset_download_home',
491 rmap.connect('changeset_download_home',
487 '/{repo_name:.*?}/changeset-download/{revision}',
492 '/{repo_name:.*?}/changeset-download/{revision}',
488 controller='changeset', action='changeset_download',
493 controller='changeset', action='changeset_download',
489 revision='tip', conditions=dict(function=check_repo))
494 revision='tip', conditions=dict(function=check_repo))
490
495
491 rmap.connect('changeset_comment',
496 rmap.connect('changeset_comment',
492 '/{repo_name:.*?}/changeset/{revision}/comment',
497 '/{repo_name:.*?}/changeset/{revision}/comment',
493 controller='changeset', revision='tip', action='comment',
498 controller='changeset', revision='tip', action='comment',
494 conditions=dict(function=check_repo))
499 conditions=dict(function=check_repo))
495
500
496 rmap.connect('changeset_comment_delete',
501 rmap.connect('changeset_comment_delete',
497 '/{repo_name:.*?}/changeset/comment/{comment_id}/delete',
502 '/{repo_name:.*?}/changeset/comment/{comment_id}/delete',
498 controller='changeset', action='delete_comment',
503 controller='changeset', action='delete_comment',
499 conditions=dict(function=check_repo, method=["DELETE"]))
504 conditions=dict(function=check_repo, method=["DELETE"]))
500
505
501 rmap.connect('changeset_info', '/changeset_info/{repo_name:.*?}/{revision}',
506 rmap.connect('changeset_info', '/changeset_info/{repo_name:.*?}/{revision}',
502 controller='changeset', action='changeset_info')
507 controller='changeset', action='changeset_info')
503
508
504 rmap.connect('compare_url',
509 rmap.connect('compare_url',
505 '/{repo_name:.*?}/compare/{org_ref_type}@{org_ref:.*?}...{other_ref_type}@{other_ref:.*?}',
510 '/{repo_name:.*?}/compare/{org_ref_type}@{org_ref:.*?}...{other_ref_type}@{other_ref:.*?}',
506 controller='compare', action='index',
511 controller='compare', action='index',
507 conditions=dict(function=check_repo),
512 conditions=dict(function=check_repo),
508 requirements=dict(
513 requirements=dict(
509 org_ref_type='(branch|book|tag|rev|__other_ref_type__)',
514 org_ref_type='(branch|book|tag|rev|__other_ref_type__)',
510 other_ref_type='(branch|book|tag|rev|__org_ref_type__)')
515 other_ref_type='(branch|book|tag|rev|__org_ref_type__)')
511 )
516 )
512
517
513 rmap.connect('pullrequest_home',
518 rmap.connect('pullrequest_home',
514 '/{repo_name:.*?}/pull-request/new', controller='pullrequests',
519 '/{repo_name:.*?}/pull-request/new', controller='pullrequests',
515 action='index', conditions=dict(function=check_repo,
520 action='index', conditions=dict(function=check_repo,
516 method=["GET"]))
521 method=["GET"]))
517
522
518 rmap.connect('pullrequest',
523 rmap.connect('pullrequest',
519 '/{repo_name:.*?}/pull-request/new', controller='pullrequests',
524 '/{repo_name:.*?}/pull-request/new', controller='pullrequests',
520 action='create', conditions=dict(function=check_repo,
525 action='create', conditions=dict(function=check_repo,
521 method=["POST"]))
526 method=["POST"]))
522
527
523 rmap.connect('pullrequest_show',
528 rmap.connect('pullrequest_show',
524 '/{repo_name:.*?}/pull-request/{pull_request_id}',
529 '/{repo_name:.*?}/pull-request/{pull_request_id}',
525 controller='pullrequests',
530 controller='pullrequests',
526 action='show', conditions=dict(function=check_repo,
531 action='show', conditions=dict(function=check_repo,
527 method=["GET"]))
532 method=["GET"]))
528 rmap.connect('pullrequest_update',
533 rmap.connect('pullrequest_update',
529 '/{repo_name:.*?}/pull-request/{pull_request_id}',
534 '/{repo_name:.*?}/pull-request/{pull_request_id}',
530 controller='pullrequests',
535 controller='pullrequests',
531 action='update', conditions=dict(function=check_repo,
536 action='update', conditions=dict(function=check_repo,
532 method=["PUT"]))
537 method=["PUT"]))
533 rmap.connect('pullrequest_delete',
538 rmap.connect('pullrequest_delete',
534 '/{repo_name:.*?}/pull-request/{pull_request_id}',
539 '/{repo_name:.*?}/pull-request/{pull_request_id}',
535 controller='pullrequests',
540 controller='pullrequests',
536 action='delete', conditions=dict(function=check_repo,
541 action='delete', conditions=dict(function=check_repo,
537 method=["DELETE"]))
542 method=["DELETE"]))
538
543
539 rmap.connect('pullrequest_show_all',
544 rmap.connect('pullrequest_show_all',
540 '/{repo_name:.*?}/pull-request',
545 '/{repo_name:.*?}/pull-request',
541 controller='pullrequests',
546 controller='pullrequests',
542 action='show_all', conditions=dict(function=check_repo,
547 action='show_all', conditions=dict(function=check_repo,
543 method=["GET"]))
548 method=["GET"]))
544
549
545 rmap.connect('pullrequest_comment',
550 rmap.connect('pullrequest_comment',
546 '/{repo_name:.*?}/pull-request-comment/{pull_request_id}',
551 '/{repo_name:.*?}/pull-request-comment/{pull_request_id}',
547 controller='pullrequests',
552 controller='pullrequests',
548 action='comment', conditions=dict(function=check_repo,
553 action='comment', conditions=dict(function=check_repo,
549 method=["POST"]))
554 method=["POST"]))
550
555
551 rmap.connect('pullrequest_comment_delete',
556 rmap.connect('pullrequest_comment_delete',
552 '/{repo_name:.*?}/pull-request-comment/{comment_id}/delete',
557 '/{repo_name:.*?}/pull-request-comment/{comment_id}/delete',
553 controller='pullrequests', action='delete_comment',
558 controller='pullrequests', action='delete_comment',
554 conditions=dict(function=check_repo, method=["DELETE"]))
559 conditions=dict(function=check_repo, method=["DELETE"]))
555
560
556 rmap.connect('summary_home_summary', '/{repo_name:.*?}/summary',
561 rmap.connect('summary_home_summary', '/{repo_name:.*?}/summary',
557 controller='summary', conditions=dict(function=check_repo))
562 controller='summary', conditions=dict(function=check_repo))
558
563
559 rmap.connect('shortlog_home', '/{repo_name:.*?}/shortlog',
564 rmap.connect('shortlog_home', '/{repo_name:.*?}/shortlog',
560 controller='shortlog', conditions=dict(function=check_repo))
565 controller='shortlog', conditions=dict(function=check_repo))
561
566
562 rmap.connect('shortlog_file_home', '/{repo_name:.*?}/shortlog/{revision}/{f_path:.*}',
567 rmap.connect('shortlog_file_home', '/{repo_name:.*?}/shortlog/{revision}/{f_path:.*}',
563 controller='shortlog', f_path=None,
568 controller='shortlog', f_path=None,
564 conditions=dict(function=check_repo))
569 conditions=dict(function=check_repo))
565
570
566 rmap.connect('branches_home', '/{repo_name:.*?}/branches',
571 rmap.connect('branches_home', '/{repo_name:.*?}/branches',
567 controller='branches', conditions=dict(function=check_repo))
572 controller='branches', conditions=dict(function=check_repo))
568
573
569 rmap.connect('tags_home', '/{repo_name:.*?}/tags',
574 rmap.connect('tags_home', '/{repo_name:.*?}/tags',
570 controller='tags', conditions=dict(function=check_repo))
575 controller='tags', conditions=dict(function=check_repo))
571
576
572 rmap.connect('bookmarks_home', '/{repo_name:.*?}/bookmarks',
577 rmap.connect('bookmarks_home', '/{repo_name:.*?}/bookmarks',
573 controller='bookmarks', conditions=dict(function=check_repo))
578 controller='bookmarks', conditions=dict(function=check_repo))
574
579
575 rmap.connect('changelog_home', '/{repo_name:.*?}/changelog',
580 rmap.connect('changelog_home', '/{repo_name:.*?}/changelog',
576 controller='changelog', conditions=dict(function=check_repo))
581 controller='changelog', conditions=dict(function=check_repo))
577
582
578 rmap.connect('changelog_details', '/{repo_name:.*?}/changelog_details/{cs}',
583 rmap.connect('changelog_details', '/{repo_name:.*?}/changelog_details/{cs}',
579 controller='changelog', action='changelog_details',
584 controller='changelog', action='changelog_details',
580 conditions=dict(function=check_repo))
585 conditions=dict(function=check_repo))
581
586
582 rmap.connect('files_home', '/{repo_name:.*?}/files/{revision}/{f_path:.*}',
587 rmap.connect('files_home', '/{repo_name:.*?}/files/{revision}/{f_path:.*}',
583 controller='files', revision='tip', f_path='',
588 controller='files', revision='tip', f_path='',
584 conditions=dict(function=check_repo))
589 conditions=dict(function=check_repo))
585
590
586 rmap.connect('files_home_nopath', '/{repo_name:.*?}/files/{revision}',
591 rmap.connect('files_home_nopath', '/{repo_name:.*?}/files/{revision}',
587 controller='files', revision='tip', f_path='',
592 controller='files', revision='tip', f_path='',
588 conditions=dict(function=check_repo))
593 conditions=dict(function=check_repo))
589
594
590 rmap.connect('files_history_home',
595 rmap.connect('files_history_home',
591 '/{repo_name:.*?}/history/{revision}/{f_path:.*}',
596 '/{repo_name:.*?}/history/{revision}/{f_path:.*}',
592 controller='files', action='history', revision='tip', f_path='',
597 controller='files', action='history', revision='tip', f_path='',
593 conditions=dict(function=check_repo))
598 conditions=dict(function=check_repo))
594
599
595 rmap.connect('files_diff_home', '/{repo_name:.*?}/diff/{f_path:.*}',
600 rmap.connect('files_diff_home', '/{repo_name:.*?}/diff/{f_path:.*}',
596 controller='files', action='diff', revision='tip', f_path='',
601 controller='files', action='diff', revision='tip', f_path='',
597 conditions=dict(function=check_repo))
602 conditions=dict(function=check_repo))
598
603
599 rmap.connect('files_rawfile_home',
604 rmap.connect('files_rawfile_home',
600 '/{repo_name:.*?}/rawfile/{revision}/{f_path:.*}',
605 '/{repo_name:.*?}/rawfile/{revision}/{f_path:.*}',
601 controller='files', action='rawfile', revision='tip',
606 controller='files', action='rawfile', revision='tip',
602 f_path='', conditions=dict(function=check_repo))
607 f_path='', conditions=dict(function=check_repo))
603
608
604 rmap.connect('files_raw_home',
609 rmap.connect('files_raw_home',
605 '/{repo_name:.*?}/raw/{revision}/{f_path:.*}',
610 '/{repo_name:.*?}/raw/{revision}/{f_path:.*}',
606 controller='files', action='raw', revision='tip', f_path='',
611 controller='files', action='raw', revision='tip', f_path='',
607 conditions=dict(function=check_repo))
612 conditions=dict(function=check_repo))
608
613
609 rmap.connect('files_annotate_home',
614 rmap.connect('files_annotate_home',
610 '/{repo_name:.*?}/annotate/{revision}/{f_path:.*}',
615 '/{repo_name:.*?}/annotate/{revision}/{f_path:.*}',
611 controller='files', action='index', revision='tip',
616 controller='files', action='index', revision='tip',
612 f_path='', annotate=True, conditions=dict(function=check_repo))
617 f_path='', annotate=True, conditions=dict(function=check_repo))
613
618
614 rmap.connect('files_edit_home',
619 rmap.connect('files_edit_home',
615 '/{repo_name:.*?}/edit/{revision}/{f_path:.*}',
620 '/{repo_name:.*?}/edit/{revision}/{f_path:.*}',
616 controller='files', action='edit', revision='tip',
621 controller='files', action='edit', revision='tip',
617 f_path='', conditions=dict(function=check_repo))
622 f_path='', conditions=dict(function=check_repo))
618
623
619 rmap.connect('files_add_home',
624 rmap.connect('files_add_home',
620 '/{repo_name:.*?}/add/{revision}/{f_path:.*}',
625 '/{repo_name:.*?}/add/{revision}/{f_path:.*}',
621 controller='files', action='add', revision='tip',
626 controller='files', action='add', revision='tip',
622 f_path='', conditions=dict(function=check_repo))
627 f_path='', conditions=dict(function=check_repo))
623
628
624 rmap.connect('files_archive_home', '/{repo_name:.*?}/archive/{fname}',
629 rmap.connect('files_archive_home', '/{repo_name:.*?}/archive/{fname}',
625 controller='files', action='archivefile',
630 controller='files', action='archivefile',
626 conditions=dict(function=check_repo))
631 conditions=dict(function=check_repo))
627
632
628 rmap.connect('files_nodelist_home',
633 rmap.connect('files_nodelist_home',
629 '/{repo_name:.*?}/nodelist/{revision}/{f_path:.*}',
634 '/{repo_name:.*?}/nodelist/{revision}/{f_path:.*}',
630 controller='files', action='nodelist',
635 controller='files', action='nodelist',
631 conditions=dict(function=check_repo))
636 conditions=dict(function=check_repo))
632
637
633 rmap.connect('repo_settings_delete', '/{repo_name:.*?}/settings',
638 rmap.connect('repo_settings_delete', '/{repo_name:.*?}/settings',
634 controller='settings', action="delete",
639 controller='settings', action="delete",
635 conditions=dict(method=["DELETE"], function=check_repo))
640 conditions=dict(method=["DELETE"], function=check_repo))
636
641
637 rmap.connect('repo_settings_update', '/{repo_name:.*?}/settings',
642 rmap.connect('repo_settings_update', '/{repo_name:.*?}/settings',
638 controller='settings', action="update",
643 controller='settings', action="update",
639 conditions=dict(method=["PUT"], function=check_repo))
644 conditions=dict(method=["PUT"], function=check_repo))
640
645
641 rmap.connect('repo_settings_home', '/{repo_name:.*?}/settings',
646 rmap.connect('repo_settings_home', '/{repo_name:.*?}/settings',
642 controller='settings', action='index',
647 controller='settings', action='index',
643 conditions=dict(function=check_repo))
648 conditions=dict(function=check_repo))
644
649
645 rmap.connect('toggle_locking', "/{repo_name:.*?}/locking_toggle",
650 rmap.connect('toggle_locking', "/{repo_name:.*?}/locking_toggle",
646 controller='settings', action="toggle_locking",
651 controller='settings', action="toggle_locking",
647 conditions=dict(method=["GET"], function=check_repo))
652 conditions=dict(method=["GET"], function=check_repo))
648
653
649 rmap.connect('repo_fork_create_home', '/{repo_name:.*?}/fork',
654 rmap.connect('repo_fork_create_home', '/{repo_name:.*?}/fork',
650 controller='forks', action='fork_create',
655 controller='forks', action='fork_create',
651 conditions=dict(function=check_repo, method=["POST"]))
656 conditions=dict(function=check_repo, method=["POST"]))
652
657
653 rmap.connect('repo_fork_home', '/{repo_name:.*?}/fork',
658 rmap.connect('repo_fork_home', '/{repo_name:.*?}/fork',
654 controller='forks', action='fork',
659 controller='forks', action='fork',
655 conditions=dict(function=check_repo))
660 conditions=dict(function=check_repo))
656
661
657 rmap.connect('repo_forks_home', '/{repo_name:.*?}/forks',
662 rmap.connect('repo_forks_home', '/{repo_name:.*?}/forks',
658 controller='forks', action='forks',
663 controller='forks', action='forks',
659 conditions=dict(function=check_repo))
664 conditions=dict(function=check_repo))
660
665
661 rmap.connect('repo_followers_home', '/{repo_name:.*?}/followers',
666 rmap.connect('repo_followers_home', '/{repo_name:.*?}/followers',
662 controller='followers', action='followers',
667 controller='followers', action='followers',
663 conditions=dict(function=check_repo))
668 conditions=dict(function=check_repo))
664
669
665 return rmap
670 return rmap
@@ -1,540 +1,579 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.controllers.admin.repos
3 rhodecode.controllers.admin.repos
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5
5
6 Repositories controller for RhodeCode
6 Repositories controller for RhodeCode
7
7
8 :created_on: Apr 7, 2010
8 :created_on: Apr 7, 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 from formencode import htmlfill
29 from formencode import htmlfill
30
30
31 from webob.exc import HTTPInternalServerError, HTTPForbidden
31 from webob.exc import HTTPInternalServerError, HTTPForbidden
32 from pylons import request, session, tmpl_context as c, url
32 from pylons import request, session, 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 from sqlalchemy.exc import IntegrityError
35 from sqlalchemy.exc import IntegrityError
36
36
37 import rhodecode
37 import rhodecode
38 from rhodecode.lib import helpers as h
38 from rhodecode.lib import helpers as h
39 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator, \
39 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator, \
40 HasPermissionAnyDecorator, HasRepoPermissionAllDecorator, NotAnonymous,\
40 HasPermissionAnyDecorator, HasRepoPermissionAllDecorator, NotAnonymous,\
41 HasPermissionAny, HasReposGroupPermissionAny
41 HasPermissionAny, HasReposGroupPermissionAny
42 from rhodecode.lib.base import BaseRepoController, render
42 from rhodecode.lib.base import BaseRepoController, render
43 from rhodecode.lib.utils import invalidate_cache, action_logger, repo_name_slug
43 from rhodecode.lib.utils import invalidate_cache, action_logger, repo_name_slug
44 from rhodecode.lib.helpers import get_token
44 from rhodecode.lib.helpers import get_token
45 from rhodecode.model.meta import Session
45 from rhodecode.model.meta import Session
46 from rhodecode.model.db import User, Repository, UserFollowing, RepoGroup,\
46 from rhodecode.model.db import User, Repository, UserFollowing, RepoGroup,\
47 RhodeCodeSetting, RepositoryField
47 RhodeCodeSetting, RepositoryField
48 from rhodecode.model.forms import RepoForm, RepoFieldForm
48 from rhodecode.model.forms import RepoForm, RepoFieldForm, RepoPermsForm
49 from rhodecode.model.scm import ScmModel, GroupList
49 from rhodecode.model.scm import ScmModel, GroupList
50 from rhodecode.model.repo import RepoModel
50 from rhodecode.model.repo import RepoModel
51 from rhodecode.lib.compat import json
51 from rhodecode.lib.compat import json
52 from sqlalchemy.sql.expression import func
52 from sqlalchemy.sql.expression import func
53
53
54 log = logging.getLogger(__name__)
54 log = logging.getLogger(__name__)
55
55
56
56
57 class ReposController(BaseRepoController):
57 class ReposController(BaseRepoController):
58 """
58 """
59 REST Controller styled on the Atom Publishing Protocol"""
59 REST Controller styled on the Atom Publishing Protocol"""
60 # To properly map this controller, ensure your config/routing.py
60 # To properly map this controller, ensure your config/routing.py
61 # file has a resource setup:
61 # file has a resource setup:
62 # map.resource('repo', 'repos')
62 # map.resource('repo', 'repos')
63
63
64 @LoginRequired()
64 @LoginRequired()
65 def __before__(self):
65 def __before__(self):
66 c.admin_user = session.get('admin_user')
66 c.admin_user = session.get('admin_user')
67 c.admin_username = session.get('admin_username')
67 c.admin_username = session.get('admin_username')
68 super(ReposController, self).__before__()
68 super(ReposController, self).__before__()
69
69
70 def __load_defaults(self):
70 def __load_defaults(self):
71 acl_groups = GroupList(RepoGroup.query().all(),
71 acl_groups = GroupList(RepoGroup.query().all(),
72 perm_set=['group.write', 'group.admin'])
72 perm_set=['group.write', 'group.admin'])
73 c.repo_groups = RepoGroup.groups_choices(groups=acl_groups)
73 c.repo_groups = RepoGroup.groups_choices(groups=acl_groups)
74 c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups)
74 c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups)
75
75
76 repo_model = RepoModel()
76 repo_model = RepoModel()
77 c.users_array = repo_model.get_users_js()
77 c.users_array = repo_model.get_users_js()
78 c.users_groups_array = repo_model.get_users_groups_js()
78 c.users_groups_array = repo_model.get_users_groups_js()
79 choices, c.landing_revs = ScmModel().get_repo_landing_revs()
79 choices, c.landing_revs = ScmModel().get_repo_landing_revs()
80 c.landing_revs_choices = choices
80 c.landing_revs_choices = choices
81
81
82 def __load_data(self, repo_name=None):
82 def __load_data(self, repo_name=None):
83 """
83 """
84 Load defaults settings for edit, and update
84 Load defaults settings for edit, and update
85
85
86 :param repo_name:
86 :param repo_name:
87 """
87 """
88 self.__load_defaults()
88 self.__load_defaults()
89
89
90 c.repo_info = db_repo = Repository.get_by_repo_name(repo_name)
90 c.repo_info = db_repo = Repository.get_by_repo_name(repo_name)
91 repo = db_repo.scm_instance
91 repo = db_repo.scm_instance
92
92
93 if c.repo_info is None:
93 if c.repo_info is None:
94 h.not_mapped_error(repo_name)
94 h.not_mapped_error(repo_name)
95 return redirect(url('repos'))
95 return redirect(url('repos'))
96
96
97 ##override defaults for exact repo info here git/hg etc
97 ##override defaults for exact repo info here git/hg etc
98 choices, c.landing_revs = ScmModel().get_repo_landing_revs(c.repo_info)
98 choices, c.landing_revs = ScmModel().get_repo_landing_revs(c.repo_info)
99 c.landing_revs_choices = choices
99 c.landing_revs_choices = choices
100
100
101 c.default_user_id = User.get_by_username('default').user_id
101 c.default_user_id = User.get_by_username('default').user_id
102 c.in_public_journal = UserFollowing.query()\
102 c.in_public_journal = UserFollowing.query()\
103 .filter(UserFollowing.user_id == c.default_user_id)\
103 .filter(UserFollowing.user_id == c.default_user_id)\
104 .filter(UserFollowing.follows_repository == c.repo_info).scalar()
104 .filter(UserFollowing.follows_repository == c.repo_info).scalar()
105
105
106 if c.repo_info.stats:
106 if c.repo_info.stats:
107 # this is on what revision we ended up so we add +1 for count
107 # this is on what revision we ended up so we add +1 for count
108 last_rev = c.repo_info.stats.stat_on_revision + 1
108 last_rev = c.repo_info.stats.stat_on_revision + 1
109 else:
109 else:
110 last_rev = 0
110 last_rev = 0
111 c.stats_revision = last_rev
111 c.stats_revision = last_rev
112
112
113 c.repo_last_rev = repo.count() if repo.revisions else 0
113 c.repo_last_rev = repo.count() if repo.revisions else 0
114
114
115 if last_rev == 0 or c.repo_last_rev == 0:
115 if last_rev == 0 or c.repo_last_rev == 0:
116 c.stats_percentage = 0
116 c.stats_percentage = 0
117 else:
117 else:
118 c.stats_percentage = '%.2f' % ((float((last_rev)) /
118 c.stats_percentage = '%.2f' % ((float((last_rev)) /
119 c.repo_last_rev) * 100)
119 c.repo_last_rev) * 100)
120
120
121 c.repo_fields = RepositoryField.query()\
121 c.repo_fields = RepositoryField.query()\
122 .filter(RepositoryField.repository == db_repo).all()
122 .filter(RepositoryField.repository == db_repo).all()
123
123
124 defaults = RepoModel()._get_defaults(repo_name)
124 defaults = RepoModel()._get_defaults(repo_name)
125
125
126 c.repos_list = [('', _('--REMOVE FORK--'))]
126 c.repos_list = [('', _('--REMOVE FORK--'))]
127 c.repos_list += [(x.repo_id, x.repo_name) for x in
127 c.repos_list += [(x.repo_id, x.repo_name) for x in
128 Repository.query().order_by(Repository.repo_name).all()
128 Repository.query().order_by(Repository.repo_name).all()
129 if x.repo_id != c.repo_info.repo_id]
129 if x.repo_id != c.repo_info.repo_id]
130
130
131 defaults['id_fork_of'] = db_repo.fork.repo_id if db_repo.fork else ''
131 defaults['id_fork_of'] = db_repo.fork.repo_id if db_repo.fork else ''
132 return defaults
132 return defaults
133
133
134 @HasPermissionAllDecorator('hg.admin')
134 @HasPermissionAllDecorator('hg.admin')
135 def index(self, format='html'):
135 def index(self, format='html'):
136 """GET /repos: All items in the collection"""
136 """GET /repos: All items in the collection"""
137 # url('repos')
137 # url('repos')
138
138
139 c.repos_list = Repository.query()\
139 c.repos_list = Repository.query()\
140 .order_by(func.lower(Repository.repo_name))\
140 .order_by(func.lower(Repository.repo_name))\
141 .all()
141 .all()
142
142
143 repos_data = RepoModel().get_repos_as_dict(repos_list=c.repos_list,
143 repos_data = RepoModel().get_repos_as_dict(repos_list=c.repos_list,
144 admin=True,
144 admin=True,
145 super_user_actions=True)
145 super_user_actions=True)
146 #json used to render the grid
146 #json used to render the grid
147 c.data = json.dumps(repos_data)
147 c.data = json.dumps(repos_data)
148
148
149 return render('admin/repos/repos.html')
149 return render('admin/repos/repos.html')
150
150
151 @NotAnonymous()
151 @NotAnonymous()
152 def create(self):
152 def create(self):
153 """
153 """
154 POST /repos: Create a new item"""
154 POST /repos: Create a new item"""
155 # url('repos')
155 # url('repos')
156
156
157 self.__load_defaults()
157 self.__load_defaults()
158 form_result = {}
158 form_result = {}
159 try:
159 try:
160 form_result = RepoForm(repo_groups=c.repo_groups_choices,
160 form_result = RepoForm(repo_groups=c.repo_groups_choices,
161 landing_revs=c.landing_revs_choices)()\
161 landing_revs=c.landing_revs_choices)()\
162 .to_python(dict(request.POST))
162 .to_python(dict(request.POST))
163
163
164 new_repo = RepoModel().create(form_result,
164 new_repo = RepoModel().create(form_result,
165 self.rhodecode_user.user_id)
165 self.rhodecode_user.user_id)
166 if form_result['clone_uri']:
166 if form_result['clone_uri']:
167 h.flash(_('Created repository %s from %s') \
167 h.flash(_('Created repository %s from %s') \
168 % (form_result['repo_name'], form_result['clone_uri']),
168 % (form_result['repo_name'], form_result['clone_uri']),
169 category='success')
169 category='success')
170 else:
170 else:
171 repo_url = h.link_to(form_result['repo_name'],
171 repo_url = h.link_to(form_result['repo_name'],
172 h.url('summary_home', repo_name=form_result['repo_name']))
172 h.url('summary_home', repo_name=form_result['repo_name']))
173 h.flash(h.literal(_('Created repository %s') % repo_url),
173 h.flash(h.literal(_('Created repository %s') % repo_url),
174 category='success')
174 category='success')
175
175
176 if request.POST.get('user_created'):
176 if request.POST.get('user_created'):
177 # created by regular non admin user
177 # created by regular non admin user
178 action_logger(self.rhodecode_user, 'user_created_repo',
178 action_logger(self.rhodecode_user, 'user_created_repo',
179 form_result['repo_name_full'], self.ip_addr,
179 form_result['repo_name_full'], self.ip_addr,
180 self.sa)
180 self.sa)
181 else:
181 else:
182 action_logger(self.rhodecode_user, 'admin_created_repo',
182 action_logger(self.rhodecode_user, 'admin_created_repo',
183 form_result['repo_name_full'], self.ip_addr,
183 form_result['repo_name_full'], self.ip_addr,
184 self.sa)
184 self.sa)
185 Session().commit()
185 Session().commit()
186 except formencode.Invalid, errors:
186 except formencode.Invalid, errors:
187 return htmlfill.render(
187 return htmlfill.render(
188 render('admin/repos/repo_add.html'),
188 render('admin/repos/repo_add.html'),
189 defaults=errors.value,
189 defaults=errors.value,
190 errors=errors.error_dict or {},
190 errors=errors.error_dict or {},
191 prefix_error=False,
191 prefix_error=False,
192 encoding="UTF-8")
192 encoding="UTF-8")
193
193
194 except Exception:
194 except Exception:
195 log.error(traceback.format_exc())
195 log.error(traceback.format_exc())
196 msg = _('error occurred during creation of repository %s') \
196 msg = _('error occurred during creation of repository %s') \
197 % form_result.get('repo_name')
197 % form_result.get('repo_name')
198 h.flash(msg, category='error')
198 h.flash(msg, category='error')
199 if c.rhodecode_user.is_admin:
199 if c.rhodecode_user.is_admin:
200 return redirect(url('repos'))
200 return redirect(url('repos'))
201 return redirect(url('home'))
201 return redirect(url('home'))
202 #redirect to our new repo !
202 #redirect to our new repo !
203 return redirect(url('summary_home', repo_name=new_repo.repo_name))
203 return redirect(url('summary_home', repo_name=new_repo.repo_name))
204
204
205 @HasPermissionAllDecorator('hg.admin')
205 @HasPermissionAllDecorator('hg.admin')
206 def new(self, format='html'):
206 def new(self, format='html'):
207 """
207 """
208 WARNING: this function is depracated see settings.create_repo !!
208 WARNING: this function is depracated see settings.create_repo !!
209
209
210 GET /repos/new: Form to create a new item
210 GET /repos/new: Form to create a new item
211 """
211 """
212
212
213 parent_group = request.GET.get('parent_group')
213 parent_group = request.GET.get('parent_group')
214 self.__load_defaults()
214 self.__load_defaults()
215 ## apply the defaults from defaults page
215 ## apply the defaults from defaults page
216 defaults = RhodeCodeSetting.get_default_repo_settings(strip_prefix=True)
216 defaults = RhodeCodeSetting.get_default_repo_settings(strip_prefix=True)
217 if parent_group:
217 if parent_group:
218 defaults.update({'repo_group': parent_group})
218 defaults.update({'repo_group': parent_group})
219
219
220 return htmlfill.render(
220 return htmlfill.render(
221 render('admin/repos/repo_add.html'),
221 render('admin/repos/repo_add.html'),
222 defaults=defaults,
222 defaults=defaults,
223 errors={},
223 errors={},
224 prefix_error=False,
224 prefix_error=False,
225 encoding="UTF-8"
225 encoding="UTF-8"
226 )
226 )
227
227
228 @HasPermissionAllDecorator('hg.admin')
228 @HasPermissionAllDecorator('hg.admin')
229 def update(self, repo_name):
229 def update(self, repo_name):
230 """
230 """
231 PUT /repos/repo_name: Update an existing item"""
231 PUT /repos/repo_name: Update an existing item"""
232 # Forms posted to this method should contain a hidden field:
232 # Forms posted to this method should contain a hidden field:
233 # <input type="hidden" name="_method" value="PUT" />
233 # <input type="hidden" name="_method" value="PUT" />
234 # Or using helpers:
234 # Or using helpers:
235 # h.form(url('repo', repo_name=ID),
235 # h.form(url('repo', repo_name=ID),
236 # method='put')
236 # method='put')
237 # url('repo', repo_name=ID)
237 # url('repo', repo_name=ID)
238 self.__load_defaults()
238 self.__load_defaults()
239 repo_model = RepoModel()
239 repo_model = RepoModel()
240 changed_name = repo_name
240 changed_name = repo_name
241 #override the choices with extracted revisions !
241 #override the choices with extracted revisions !
242 choices, c.landing_revs = ScmModel().get_repo_landing_revs(repo_name)
242 choices, c.landing_revs = ScmModel().get_repo_landing_revs(repo_name)
243 c.landing_revs_choices = choices
243 c.landing_revs_choices = choices
244 repo = Repository.get_by_repo_name(repo_name)
244 repo = Repository.get_by_repo_name(repo_name)
245 _form = RepoForm(edit=True, old_data={'repo_name': repo_name,
245 _form = RepoForm(edit=True, old_data={'repo_name': repo_name,
246 'repo_group': repo.group.get_dict() \
246 'repo_group': repo.group.get_dict() \
247 if repo.group else {}},
247 if repo.group else {}},
248 repo_groups=c.repo_groups_choices,
248 repo_groups=c.repo_groups_choices,
249 landing_revs=c.landing_revs_choices)()
249 landing_revs=c.landing_revs_choices)()
250 try:
250 try:
251 form_result = _form.to_python(dict(request.POST))
251 form_result = _form.to_python(dict(request.POST))
252 repo = repo_model.update(repo_name, **form_result)
252 repo = repo_model.update(repo_name, **form_result)
253 invalidate_cache('get_repo_cached_%s' % repo_name)
253 invalidate_cache('get_repo_cached_%s' % repo_name)
254 h.flash(_('Repository %s updated successfully') % repo_name,
254 h.flash(_('Repository %s updated successfully') % repo_name,
255 category='success')
255 category='success')
256 changed_name = repo.repo_name
256 changed_name = repo.repo_name
257 action_logger(self.rhodecode_user, 'admin_updated_repo',
257 action_logger(self.rhodecode_user, 'admin_updated_repo',
258 changed_name, self.ip_addr, self.sa)
258 changed_name, self.ip_addr, self.sa)
259 Session().commit()
259 Session().commit()
260 except formencode.Invalid, errors:
260 except formencode.Invalid, errors:
261 defaults = self.__load_data(repo_name)
261 defaults = self.__load_data(repo_name)
262 defaults.update(errors.value)
262 defaults.update(errors.value)
263 return htmlfill.render(
263 return htmlfill.render(
264 render('admin/repos/repo_edit.html'),
264 render('admin/repos/repo_edit.html'),
265 defaults=defaults,
265 defaults=defaults,
266 errors=errors.error_dict or {},
266 errors=errors.error_dict or {},
267 prefix_error=False,
267 prefix_error=False,
268 encoding="UTF-8")
268 encoding="UTF-8")
269
269
270 except Exception:
270 except Exception:
271 log.error(traceback.format_exc())
271 log.error(traceback.format_exc())
272 h.flash(_('Error occurred during update of repository %s') \
272 h.flash(_('Error occurred during update of repository %s') \
273 % repo_name, category='error')
273 % repo_name, category='error')
274 return redirect(url('edit_repo', repo_name=changed_name))
274 return redirect(url('edit_repo', repo_name=changed_name))
275
275
276 @HasPermissionAllDecorator('hg.admin')
276 @HasPermissionAllDecorator('hg.admin')
277 def delete(self, repo_name):
277 def delete(self, repo_name):
278 """
278 """
279 DELETE /repos/repo_name: Delete an existing item"""
279 DELETE /repos/repo_name: Delete an existing item"""
280 # Forms posted to this method should contain a hidden field:
280 # Forms posted to this method should contain a hidden field:
281 # <input type="hidden" name="_method" value="DELETE" />
281 # <input type="hidden" name="_method" value="DELETE" />
282 # Or using helpers:
282 # Or using helpers:
283 # h.form(url('repo', repo_name=ID),
283 # h.form(url('repo', repo_name=ID),
284 # method='delete')
284 # method='delete')
285 # url('repo', repo_name=ID)
285 # url('repo', repo_name=ID)
286
286
287 repo_model = RepoModel()
287 repo_model = RepoModel()
288 repo = repo_model.get_by_repo_name(repo_name)
288 repo = repo_model.get_by_repo_name(repo_name)
289 if not repo:
289 if not repo:
290 h.not_mapped_error(repo_name)
290 h.not_mapped_error(repo_name)
291 return redirect(url('repos'))
291 return redirect(url('repos'))
292 try:
292 try:
293 _forks = repo.forks.count()
293 _forks = repo.forks.count()
294 if _forks and request.POST.get('forks'):
294 if _forks and request.POST.get('forks'):
295 do = request.POST['forks']
295 do = request.POST['forks']
296 if do == 'detach_forks':
296 if do == 'detach_forks':
297 for r in repo.forks:
297 for r in repo.forks:
298 log.debug('Detaching fork %s from repo %s' % (r, repo))
298 log.debug('Detaching fork %s from repo %s' % (r, repo))
299 r.fork = None
299 r.fork = None
300 Session().add(r)
300 Session().add(r)
301 h.flash(_('Detached %s forks') % _forks, category='success')
301 h.flash(_('Detached %s forks') % _forks, category='success')
302 elif do == 'delete_forks':
302 elif do == 'delete_forks':
303 for r in repo.forks:
303 for r in repo.forks:
304 log.debug('Deleting fork %s of repo %s' % (r, repo))
304 log.debug('Deleting fork %s of repo %s' % (r, repo))
305 repo_model.delete(r)
305 repo_model.delete(r)
306 h.flash(_('Deleted %s forks') % _forks, category='success')
306 h.flash(_('Deleted %s forks') % _forks, category='success')
307 action_logger(self.rhodecode_user, 'admin_deleted_repo',
307 action_logger(self.rhodecode_user, 'admin_deleted_repo',
308 repo_name, self.ip_addr, self.sa)
308 repo_name, self.ip_addr, self.sa)
309 repo_model.delete(repo)
309 repo_model.delete(repo)
310 invalidate_cache('get_repo_cached_%s' % repo_name)
310 invalidate_cache('get_repo_cached_%s' % repo_name)
311 h.flash(_('Deleted repository %s') % repo_name, category='success')
311 h.flash(_('Deleted repository %s') % repo_name, category='success')
312 Session().commit()
312 Session().commit()
313 except IntegrityError, e:
313 except IntegrityError, e:
314 if e.message.find('repositories_fork_id_fkey') != -1:
314 if e.message.find('repositories_fork_id_fkey') != -1:
315 log.error(traceback.format_exc())
315 log.error(traceback.format_exc())
316 h.flash(_('Cannot delete %s it still contains attached '
316 h.flash(_('Cannot delete %s it still contains attached '
317 'forks') % repo_name,
317 'forks') % repo_name,
318 category='warning')
318 category='warning')
319 else:
319 else:
320 log.error(traceback.format_exc())
320 log.error(traceback.format_exc())
321 h.flash(_('An error occurred during '
321 h.flash(_('An error occurred during '
322 'deletion of %s') % repo_name,
322 'deletion of %s') % repo_name,
323 category='error')
323 category='error')
324
324
325 except Exception, e:
325 except Exception, e:
326 log.error(traceback.format_exc())
326 log.error(traceback.format_exc())
327 h.flash(_('An error occurred during deletion of %s') % repo_name,
327 h.flash(_('An error occurred during deletion of %s') % repo_name,
328 category='error')
328 category='error')
329
329
330 return redirect(url('repos'))
330 return redirect(url('repos'))
331
331
332 @HasRepoPermissionAllDecorator('repository.admin')
332 @HasRepoPermissionAllDecorator('repository.admin')
333 def set_repo_perm_member(self, repo_name):
334 form = RepoPermsForm()().to_python(request.POST)
335
336 perms_new = form['perms_new']
337 perms_updates = form['perms_updates']
338 cur_repo = repo_name
339
340 # update permissions
341 for member, perm, member_type in perms_updates:
342 if member_type == 'user':
343 # this updates existing one
344 RepoModel().grant_user_permission(
345 repo=cur_repo, user=member, perm=perm
346 )
347 else:
348 RepoModel().grant_users_group_permission(
349 repo=cur_repo, group_name=member, perm=perm
350 )
351 # set new permissions
352 for member, perm, member_type in perms_new:
353 if member_type == 'user':
354 RepoModel().grant_user_permission(
355 repo=cur_repo, user=member, perm=perm
356 )
357 else:
358 RepoModel().grant_users_group_permission(
359 repo=cur_repo, group_name=member, perm=perm
360 )
361 #TODO: implement this
362 #action_logger(self.rhodecode_user, 'admin_changed_repo_permissions',
363 # repo_name, self.ip_addr, self.sa)
364 Session().commit()
365 h.flash(_('updated repository permissions'), category='success')
366 return redirect(url('edit_repo', repo_name=repo_name))
367
368 @HasRepoPermissionAllDecorator('repository.admin')
333 def delete_perm_user(self, repo_name):
369 def delete_perm_user(self, repo_name):
334 """
370 """
335 DELETE an existing repository permission user
371 DELETE an existing repository permission user
336
372
337 :param repo_name:
373 :param repo_name:
338 """
374 """
339 try:
375 try:
340 RepoModel().revoke_user_permission(repo=repo_name,
376 RepoModel().revoke_user_permission(repo=repo_name,
341 user=request.POST['user_id'])
377 user=request.POST['user_id'])
378 #TODO: implement this
379 #action_logger(self.rhodecode_user, 'admin_revoked_repo_permissions',
380 # repo_name, self.ip_addr, self.sa)
342 Session().commit()
381 Session().commit()
343 except Exception:
382 except Exception:
344 log.error(traceback.format_exc())
383 log.error(traceback.format_exc())
345 h.flash(_('An error occurred during deletion of repository user'),
384 h.flash(_('An error occurred during deletion of repository user'),
346 category='error')
385 category='error')
347 raise HTTPInternalServerError()
386 raise HTTPInternalServerError()
348
387
349 @HasRepoPermissionAllDecorator('repository.admin')
388 @HasRepoPermissionAllDecorator('repository.admin')
350 def delete_perm_users_group(self, repo_name):
389 def delete_perm_users_group(self, repo_name):
351 """
390 """
352 DELETE an existing repository permission user group
391 DELETE an existing repository permission user group
353
392
354 :param repo_name:
393 :param repo_name:
355 """
394 """
356
395
357 try:
396 try:
358 RepoModel().revoke_users_group_permission(
397 RepoModel().revoke_users_group_permission(
359 repo=repo_name, group_name=request.POST['users_group_id']
398 repo=repo_name, group_name=request.POST['users_group_id']
360 )
399 )
361 Session().commit()
400 Session().commit()
362 except Exception:
401 except Exception:
363 log.error(traceback.format_exc())
402 log.error(traceback.format_exc())
364 h.flash(_('An error occurred during deletion of repository'
403 h.flash(_('An error occurred during deletion of repository'
365 ' user groups'),
404 ' user groups'),
366 category='error')
405 category='error')
367 raise HTTPInternalServerError()
406 raise HTTPInternalServerError()
368
407
369 @HasPermissionAllDecorator('hg.admin')
408 @HasPermissionAllDecorator('hg.admin')
370 def repo_stats(self, repo_name):
409 def repo_stats(self, repo_name):
371 """
410 """
372 DELETE an existing repository statistics
411 DELETE an existing repository statistics
373
412
374 :param repo_name:
413 :param repo_name:
375 """
414 """
376
415
377 try:
416 try:
378 RepoModel().delete_stats(repo_name)
417 RepoModel().delete_stats(repo_name)
379 Session().commit()
418 Session().commit()
380 except Exception, e:
419 except Exception, e:
381 log.error(traceback.format_exc())
420 log.error(traceback.format_exc())
382 h.flash(_('An error occurred during deletion of repository stats'),
421 h.flash(_('An error occurred during deletion of repository stats'),
383 category='error')
422 category='error')
384 return redirect(url('edit_repo', repo_name=repo_name))
423 return redirect(url('edit_repo', repo_name=repo_name))
385
424
386 @HasPermissionAllDecorator('hg.admin')
425 @HasPermissionAllDecorator('hg.admin')
387 def repo_cache(self, repo_name):
426 def repo_cache(self, repo_name):
388 """
427 """
389 INVALIDATE existing repository cache
428 INVALIDATE existing repository cache
390
429
391 :param repo_name:
430 :param repo_name:
392 """
431 """
393
432
394 try:
433 try:
395 ScmModel().mark_for_invalidation(repo_name)
434 ScmModel().mark_for_invalidation(repo_name)
396 Session().commit()
435 Session().commit()
397 except Exception, e:
436 except Exception, e:
398 log.error(traceback.format_exc())
437 log.error(traceback.format_exc())
399 h.flash(_('An error occurred during cache invalidation'),
438 h.flash(_('An error occurred during cache invalidation'),
400 category='error')
439 category='error')
401 return redirect(url('edit_repo', repo_name=repo_name))
440 return redirect(url('edit_repo', repo_name=repo_name))
402
441
403 @HasPermissionAllDecorator('hg.admin')
442 @HasPermissionAllDecorator('hg.admin')
404 def repo_locking(self, repo_name):
443 def repo_locking(self, repo_name):
405 """
444 """
406 Unlock repository when it is locked !
445 Unlock repository when it is locked !
407
446
408 :param repo_name:
447 :param repo_name:
409 """
448 """
410
449
411 try:
450 try:
412 repo = Repository.get_by_repo_name(repo_name)
451 repo = Repository.get_by_repo_name(repo_name)
413 if request.POST.get('set_lock'):
452 if request.POST.get('set_lock'):
414 Repository.lock(repo, c.rhodecode_user.user_id)
453 Repository.lock(repo, c.rhodecode_user.user_id)
415 elif request.POST.get('set_unlock'):
454 elif request.POST.get('set_unlock'):
416 Repository.unlock(repo)
455 Repository.unlock(repo)
417 except Exception, e:
456 except Exception, e:
418 log.error(traceback.format_exc())
457 log.error(traceback.format_exc())
419 h.flash(_('An error occurred during unlocking'),
458 h.flash(_('An error occurred during unlocking'),
420 category='error')
459 category='error')
421 return redirect(url('edit_repo', repo_name=repo_name))
460 return redirect(url('edit_repo', repo_name=repo_name))
422
461
423 @HasPermissionAllDecorator('hg.admin')
462 @HasPermissionAllDecorator('hg.admin')
424 def repo_public_journal(self, repo_name):
463 def repo_public_journal(self, repo_name):
425 """
464 """
426 Set's this repository to be visible in public journal,
465 Set's this repository to be visible in public journal,
427 in other words assing default user to follow this repo
466 in other words assing default user to follow this repo
428
467
429 :param repo_name:
468 :param repo_name:
430 """
469 """
431
470
432 cur_token = request.POST.get('auth_token')
471 cur_token = request.POST.get('auth_token')
433 token = get_token()
472 token = get_token()
434 if cur_token == token:
473 if cur_token == token:
435 try:
474 try:
436 repo_id = Repository.get_by_repo_name(repo_name).repo_id
475 repo_id = Repository.get_by_repo_name(repo_name).repo_id
437 user_id = User.get_by_username('default').user_id
476 user_id = User.get_by_username('default').user_id
438 self.scm_model.toggle_following_repo(repo_id, user_id)
477 self.scm_model.toggle_following_repo(repo_id, user_id)
439 h.flash(_('Updated repository visibility in public journal'),
478 h.flash(_('Updated repository visibility in public journal'),
440 category='success')
479 category='success')
441 Session().commit()
480 Session().commit()
442 except:
481 except:
443 h.flash(_('An error occurred during setting this'
482 h.flash(_('An error occurred during setting this'
444 ' repository in public journal'),
483 ' repository in public journal'),
445 category='error')
484 category='error')
446
485
447 else:
486 else:
448 h.flash(_('Token mismatch'), category='error')
487 h.flash(_('Token mismatch'), category='error')
449 return redirect(url('edit_repo', repo_name=repo_name))
488 return redirect(url('edit_repo', repo_name=repo_name))
450
489
451 @HasPermissionAllDecorator('hg.admin')
490 @HasPermissionAllDecorator('hg.admin')
452 def repo_pull(self, repo_name):
491 def repo_pull(self, repo_name):
453 """
492 """
454 Runs task to update given repository with remote changes,
493 Runs task to update given repository with remote changes,
455 ie. make pull on remote location
494 ie. make pull on remote location
456
495
457 :param repo_name:
496 :param repo_name:
458 """
497 """
459 try:
498 try:
460 ScmModel().pull_changes(repo_name, self.rhodecode_user.username)
499 ScmModel().pull_changes(repo_name, self.rhodecode_user.username)
461 h.flash(_('Pulled from remote location'), category='success')
500 h.flash(_('Pulled from remote location'), category='success')
462 except Exception, e:
501 except Exception, e:
463 h.flash(_('An error occurred during pull from remote location'),
502 h.flash(_('An error occurred during pull from remote location'),
464 category='error')
503 category='error')
465
504
466 return redirect(url('edit_repo', repo_name=repo_name))
505 return redirect(url('edit_repo', repo_name=repo_name))
467
506
468 @HasPermissionAllDecorator('hg.admin')
507 @HasPermissionAllDecorator('hg.admin')
469 def repo_as_fork(self, repo_name):
508 def repo_as_fork(self, repo_name):
470 """
509 """
471 Mark given repository as a fork of another
510 Mark given repository as a fork of another
472
511
473 :param repo_name:
512 :param repo_name:
474 """
513 """
475 try:
514 try:
476 fork_id = request.POST.get('id_fork_of')
515 fork_id = request.POST.get('id_fork_of')
477 repo = ScmModel().mark_as_fork(repo_name, fork_id,
516 repo = ScmModel().mark_as_fork(repo_name, fork_id,
478 self.rhodecode_user.username)
517 self.rhodecode_user.username)
479 fork = repo.fork.repo_name if repo.fork else _('Nothing')
518 fork = repo.fork.repo_name if repo.fork else _('Nothing')
480 Session().commit()
519 Session().commit()
481 h.flash(_('Marked repo %s as fork of %s') % (repo_name, fork),
520 h.flash(_('Marked repo %s as fork of %s') % (repo_name, fork),
482 category='success')
521 category='success')
483 except Exception, e:
522 except Exception, e:
484 log.error(traceback.format_exc())
523 log.error(traceback.format_exc())
485 h.flash(_('An error occurred during this operation'),
524 h.flash(_('An error occurred during this operation'),
486 category='error')
525 category='error')
487
526
488 return redirect(url('edit_repo', repo_name=repo_name))
527 return redirect(url('edit_repo', repo_name=repo_name))
489
528
490 @HasPermissionAllDecorator('hg.admin')
529 @HasPermissionAllDecorator('hg.admin')
491 def show(self, repo_name, format='html'):
530 def show(self, repo_name, format='html'):
492 """GET /repos/repo_name: Show a specific item"""
531 """GET /repos/repo_name: Show a specific item"""
493 # url('repo', repo_name=ID)
532 # url('repo', repo_name=ID)
494
533
495 @HasPermissionAllDecorator('hg.admin')
534 @HasPermissionAllDecorator('hg.admin')
496 def edit(self, repo_name, format='html'):
535 def edit(self, repo_name, format='html'):
497 """GET /repos/repo_name/edit: Form to edit an existing item"""
536 """GET /repos/repo_name/edit: Form to edit an existing item"""
498 # url('edit_repo', repo_name=ID)
537 # url('edit_repo', repo_name=ID)
499 defaults = self.__load_data(repo_name)
538 defaults = self.__load_data(repo_name)
500
539
501 return htmlfill.render(
540 return htmlfill.render(
502 render('admin/repos/repo_edit.html'),
541 render('admin/repos/repo_edit.html'),
503 defaults=defaults,
542 defaults=defaults,
504 encoding="UTF-8",
543 encoding="UTF-8",
505 force_defaults=False
544 force_defaults=False
506 )
545 )
507
546
508 @HasPermissionAllDecorator('hg.admin')
547 @HasPermissionAllDecorator('hg.admin')
509 def create_repo_field(self, repo_name):
548 def create_repo_field(self, repo_name):
510 try:
549 try:
511 form_result = RepoFieldForm()().to_python(dict(request.POST))
550 form_result = RepoFieldForm()().to_python(dict(request.POST))
512 new_field = RepositoryField()
551 new_field = RepositoryField()
513 new_field.repository = Repository.get_by_repo_name(repo_name)
552 new_field.repository = Repository.get_by_repo_name(repo_name)
514 new_field.field_key = form_result['new_field_key']
553 new_field.field_key = form_result['new_field_key']
515 new_field.field_type = form_result['new_field_type'] # python type
554 new_field.field_type = form_result['new_field_type'] # python type
516 new_field.field_value = form_result['new_field_value'] # set initial blank value
555 new_field.field_value = form_result['new_field_value'] # set initial blank value
517 new_field.field_desc = form_result['new_field_desc']
556 new_field.field_desc = form_result['new_field_desc']
518 new_field.field_label = form_result['new_field_label']
557 new_field.field_label = form_result['new_field_label']
519 Session().add(new_field)
558 Session().add(new_field)
520 Session().commit()
559 Session().commit()
521
560
522 except Exception, e:
561 except Exception, e:
523 log.error(traceback.format_exc())
562 log.error(traceback.format_exc())
524 msg = _('An error occurred during creation of field')
563 msg = _('An error occurred during creation of field')
525 if isinstance(e, formencode.Invalid):
564 if isinstance(e, formencode.Invalid):
526 msg += ". " + e.msg
565 msg += ". " + e.msg
527 h.flash(msg, category='error')
566 h.flash(msg, category='error')
528 return redirect(url('edit_repo', repo_name=repo_name))
567 return redirect(url('edit_repo', repo_name=repo_name))
529
568
530 @HasPermissionAllDecorator('hg.admin')
569 @HasPermissionAllDecorator('hg.admin')
531 def delete_repo_field(self, repo_name, field_id):
570 def delete_repo_field(self, repo_name, field_id):
532 field = RepositoryField.get_or_404(field_id)
571 field = RepositoryField.get_or_404(field_id)
533 try:
572 try:
534 Session().delete(field)
573 Session().delete(field)
535 Session().commit()
574 Session().commit()
536 except Exception, e:
575 except Exception, e:
537 log.error(traceback.format_exc())
576 log.error(traceback.format_exc())
538 msg = _('An error occurred during removal of field')
577 msg = _('An error occurred during removal of field')
539 h.flash(msg, category='error')
578 h.flash(msg, category='error')
540 return redirect(url('edit_repo', repo_name=repo_name))
579 return redirect(url('edit_repo', repo_name=repo_name))
@@ -1,401 +1,408 b''
1 """ this is forms validation classes
1 """ this is forms validation classes
2 http://formencode.org/module-formencode.validators.html
2 http://formencode.org/module-formencode.validators.html
3 for list off all availible validators
3 for list off all availible validators
4
4
5 we can create our own validators
5 we can create our own validators
6
6
7 The table below outlines the options which can be used in a schema in addition to the validators themselves
7 The table below outlines the options which can be used in a schema in addition to the validators themselves
8 pre_validators [] These validators will be applied before the schema
8 pre_validators [] These validators will be applied before the schema
9 chained_validators [] These validators will be applied after the schema
9 chained_validators [] These validators will be applied after the schema
10 allow_extra_fields False If True, then it is not an error when keys that aren't associated with a validator are present
10 allow_extra_fields False If True, then it is not an error when keys that aren't associated with a validator are present
11 filter_extra_fields False If True, then keys that aren't associated with a validator are removed
11 filter_extra_fields False If True, then keys that aren't associated with a validator are removed
12 if_key_missing NoDefault If this is given, then any keys that aren't available but are expected will be replaced with this value (and then validated). This does not override a present .if_missing attribute on validators. NoDefault is a special FormEncode class to mean that no default values has been specified and therefore missing keys shouldn't take a default value.
12 if_key_missing NoDefault If this is given, then any keys that aren't available but are expected will be replaced with this value (and then validated). This does not override a present .if_missing attribute on validators. NoDefault is a special FormEncode class to mean that no default values has been specified and therefore missing keys shouldn't take a default value.
13 ignore_key_missing False If True, then missing keys will be missing in the result, if the validator doesn't have .if_missing on it already
13 ignore_key_missing False If True, then missing keys will be missing in the result, if the validator doesn't have .if_missing on it already
14
14
15
15
16 <name> = formencode.validators.<name of validator>
16 <name> = formencode.validators.<name of validator>
17 <name> must equal form name
17 <name> must equal form name
18 list=[1,2,3,4,5]
18 list=[1,2,3,4,5]
19 for SELECT use formencode.All(OneOf(list), Int())
19 for SELECT use formencode.All(OneOf(list), Int())
20
20
21 """
21 """
22 import logging
22 import logging
23
23
24 import formencode
24 import formencode
25 from formencode import All
25 from formencode import All
26
26
27 from pylons.i18n.translation import _
27 from pylons.i18n.translation import _
28
28
29 from rhodecode.model import validators as v
29 from rhodecode.model import validators as v
30 from rhodecode import BACKENDS
30 from rhodecode import BACKENDS
31
31
32 log = logging.getLogger(__name__)
32 log = logging.getLogger(__name__)
33
33
34
34
35 class LoginForm(formencode.Schema):
35 class LoginForm(formencode.Schema):
36 allow_extra_fields = True
36 allow_extra_fields = True
37 filter_extra_fields = True
37 filter_extra_fields = True
38 username = v.UnicodeString(
38 username = v.UnicodeString(
39 strip=True,
39 strip=True,
40 min=1,
40 min=1,
41 not_empty=True,
41 not_empty=True,
42 messages={
42 messages={
43 'empty': _(u'Please enter a login'),
43 'empty': _(u'Please enter a login'),
44 'tooShort': _(u'Enter a value %(min)i characters long or more')}
44 'tooShort': _(u'Enter a value %(min)i characters long or more')}
45 )
45 )
46
46
47 password = v.UnicodeString(
47 password = v.UnicodeString(
48 strip=False,
48 strip=False,
49 min=3,
49 min=3,
50 not_empty=True,
50 not_empty=True,
51 messages={
51 messages={
52 'empty': _(u'Please enter a password'),
52 'empty': _(u'Please enter a password'),
53 'tooShort': _(u'Enter %(min)i characters or more')}
53 'tooShort': _(u'Enter %(min)i characters or more')}
54 )
54 )
55
55
56 remember = v.StringBoolean(if_missing=False)
56 remember = v.StringBoolean(if_missing=False)
57
57
58 chained_validators = [v.ValidAuth()]
58 chained_validators = [v.ValidAuth()]
59
59
60
60
61 def UserForm(edit=False, old_data={}):
61 def UserForm(edit=False, old_data={}):
62 class _UserForm(formencode.Schema):
62 class _UserForm(formencode.Schema):
63 allow_extra_fields = True
63 allow_extra_fields = True
64 filter_extra_fields = True
64 filter_extra_fields = True
65 username = All(v.UnicodeString(strip=True, min=1, not_empty=True),
65 username = All(v.UnicodeString(strip=True, min=1, not_empty=True),
66 v.ValidUsername(edit, old_data))
66 v.ValidUsername(edit, old_data))
67 if edit:
67 if edit:
68 new_password = All(
68 new_password = All(
69 v.ValidPassword(),
69 v.ValidPassword(),
70 v.UnicodeString(strip=False, min=6, not_empty=False)
70 v.UnicodeString(strip=False, min=6, not_empty=False)
71 )
71 )
72 password_confirmation = All(
72 password_confirmation = All(
73 v.ValidPassword(),
73 v.ValidPassword(),
74 v.UnicodeString(strip=False, min=6, not_empty=False),
74 v.UnicodeString(strip=False, min=6, not_empty=False),
75 )
75 )
76 admin = v.StringBoolean(if_missing=False)
76 admin = v.StringBoolean(if_missing=False)
77 else:
77 else:
78 password = All(
78 password = All(
79 v.ValidPassword(),
79 v.ValidPassword(),
80 v.UnicodeString(strip=False, min=6, not_empty=True)
80 v.UnicodeString(strip=False, min=6, not_empty=True)
81 )
81 )
82 password_confirmation = All(
82 password_confirmation = All(
83 v.ValidPassword(),
83 v.ValidPassword(),
84 v.UnicodeString(strip=False, min=6, not_empty=False)
84 v.UnicodeString(strip=False, min=6, not_empty=False)
85 )
85 )
86
86
87 active = v.StringBoolean(if_missing=False)
87 active = v.StringBoolean(if_missing=False)
88 firstname = v.UnicodeString(strip=True, min=1, not_empty=False)
88 firstname = v.UnicodeString(strip=True, min=1, not_empty=False)
89 lastname = v.UnicodeString(strip=True, min=1, not_empty=False)
89 lastname = v.UnicodeString(strip=True, min=1, not_empty=False)
90 email = All(v.Email(not_empty=True), v.UniqSystemEmail(old_data))
90 email = All(v.Email(not_empty=True), v.UniqSystemEmail(old_data))
91
91
92 chained_validators = [v.ValidPasswordsMatch()]
92 chained_validators = [v.ValidPasswordsMatch()]
93
93
94 return _UserForm
94 return _UserForm
95
95
96
96
97 def UserGroupForm(edit=False, old_data={}, available_members=[]):
97 def UserGroupForm(edit=False, old_data={}, available_members=[]):
98 class _UserGroupForm(formencode.Schema):
98 class _UserGroupForm(formencode.Schema):
99 allow_extra_fields = True
99 allow_extra_fields = True
100 filter_extra_fields = True
100 filter_extra_fields = True
101
101
102 users_group_name = All(
102 users_group_name = All(
103 v.UnicodeString(strip=True, min=1, not_empty=True),
103 v.UnicodeString(strip=True, min=1, not_empty=True),
104 v.ValidUserGroup(edit, old_data)
104 v.ValidUserGroup(edit, old_data)
105 )
105 )
106
106
107 users_group_active = v.StringBoolean(if_missing=False)
107 users_group_active = v.StringBoolean(if_missing=False)
108
108
109 if edit:
109 if edit:
110 users_group_members = v.OneOf(
110 users_group_members = v.OneOf(
111 available_members, hideList=False, testValueList=True,
111 available_members, hideList=False, testValueList=True,
112 if_missing=None, not_empty=False
112 if_missing=None, not_empty=False
113 )
113 )
114
114
115 return _UserGroupForm
115 return _UserGroupForm
116
116
117
117
118 def ReposGroupForm(edit=False, old_data={}, available_groups=[],
118 def ReposGroupForm(edit=False, old_data={}, available_groups=[],
119 can_create_in_root=False):
119 can_create_in_root=False):
120 class _ReposGroupForm(formencode.Schema):
120 class _ReposGroupForm(formencode.Schema):
121 allow_extra_fields = True
121 allow_extra_fields = True
122 filter_extra_fields = False
122 filter_extra_fields = False
123
123
124 group_name = All(v.UnicodeString(strip=True, min=1, not_empty=True),
124 group_name = All(v.UnicodeString(strip=True, min=1, not_empty=True),
125 v.SlugifyName())
125 v.SlugifyName())
126 group_description = v.UnicodeString(strip=True, min=1,
126 group_description = v.UnicodeString(strip=True, min=1,
127 not_empty=False)
127 not_empty=False)
128 if edit:
128 if edit:
129 #FIXME: do a special check that we cannot move a group to one of
129 #FIXME: do a special check that we cannot move a group to one of
130 #it's children
130 #it's children
131 pass
131 pass
132 group_parent_id = All(v.CanCreateGroup(can_create_in_root),
132 group_parent_id = All(v.CanCreateGroup(can_create_in_root),
133 v.OneOf(available_groups, hideList=False,
133 v.OneOf(available_groups, hideList=False,
134 testValueList=True,
134 testValueList=True,
135 if_missing=None, not_empty=True))
135 if_missing=None, not_empty=True))
136 enable_locking = v.StringBoolean(if_missing=False)
136 enable_locking = v.StringBoolean(if_missing=False)
137 recursive = v.StringBoolean(if_missing=False)
137 recursive = v.StringBoolean(if_missing=False)
138 chained_validators = [v.ValidReposGroup(edit, old_data),
138 chained_validators = [v.ValidReposGroup(edit, old_data),
139 v.ValidPerms('group')]
139 v.ValidPerms('group')]
140
140
141 return _ReposGroupForm
141 return _ReposGroupForm
142
142
143
143
144 def RegisterForm(edit=False, old_data={}):
144 def RegisterForm(edit=False, old_data={}):
145 class _RegisterForm(formencode.Schema):
145 class _RegisterForm(formencode.Schema):
146 allow_extra_fields = True
146 allow_extra_fields = True
147 filter_extra_fields = True
147 filter_extra_fields = True
148 username = All(
148 username = All(
149 v.ValidUsername(edit, old_data),
149 v.ValidUsername(edit, old_data),
150 v.UnicodeString(strip=True, min=1, not_empty=True)
150 v.UnicodeString(strip=True, min=1, not_empty=True)
151 )
151 )
152 password = All(
152 password = All(
153 v.ValidPassword(),
153 v.ValidPassword(),
154 v.UnicodeString(strip=False, min=6, not_empty=True)
154 v.UnicodeString(strip=False, min=6, not_empty=True)
155 )
155 )
156 password_confirmation = All(
156 password_confirmation = All(
157 v.ValidPassword(),
157 v.ValidPassword(),
158 v.UnicodeString(strip=False, min=6, not_empty=True)
158 v.UnicodeString(strip=False, min=6, not_empty=True)
159 )
159 )
160 active = v.StringBoolean(if_missing=False)
160 active = v.StringBoolean(if_missing=False)
161 firstname = v.UnicodeString(strip=True, min=1, not_empty=False)
161 firstname = v.UnicodeString(strip=True, min=1, not_empty=False)
162 lastname = v.UnicodeString(strip=True, min=1, not_empty=False)
162 lastname = v.UnicodeString(strip=True, min=1, not_empty=False)
163 email = All(v.Email(not_empty=True), v.UniqSystemEmail(old_data))
163 email = All(v.Email(not_empty=True), v.UniqSystemEmail(old_data))
164
164
165 chained_validators = [v.ValidPasswordsMatch()]
165 chained_validators = [v.ValidPasswordsMatch()]
166
166
167 return _RegisterForm
167 return _RegisterForm
168
168
169
169
170 def PasswordResetForm():
170 def PasswordResetForm():
171 class _PasswordResetForm(formencode.Schema):
171 class _PasswordResetForm(formencode.Schema):
172 allow_extra_fields = True
172 allow_extra_fields = True
173 filter_extra_fields = True
173 filter_extra_fields = True
174 email = All(v.ValidSystemEmail(), v.Email(not_empty=True))
174 email = All(v.ValidSystemEmail(), v.Email(not_empty=True))
175 return _PasswordResetForm
175 return _PasswordResetForm
176
176
177
177
178 def RepoForm(edit=False, old_data={}, supported_backends=BACKENDS.keys(),
178 def RepoForm(edit=False, old_data={}, supported_backends=BACKENDS.keys(),
179 repo_groups=[], landing_revs=[]):
179 repo_groups=[], landing_revs=[]):
180 class _RepoForm(formencode.Schema):
180 class _RepoForm(formencode.Schema):
181 allow_extra_fields = True
181 allow_extra_fields = True
182 filter_extra_fields = False
182 filter_extra_fields = False
183 repo_name = All(v.UnicodeString(strip=True, min=1, not_empty=True),
183 repo_name = All(v.UnicodeString(strip=True, min=1, not_empty=True),
184 v.SlugifyName())
184 v.SlugifyName())
185 repo_group = All(v.CanWriteGroup(old_data),
185 repo_group = All(v.CanWriteGroup(old_data),
186 v.OneOf(repo_groups, hideList=True))
186 v.OneOf(repo_groups, hideList=True))
187 repo_type = v.OneOf(supported_backends)
187 repo_type = v.OneOf(supported_backends)
188 repo_description = v.UnicodeString(strip=True, min=1, not_empty=False)
188 repo_description = v.UnicodeString(strip=True, min=1, not_empty=False)
189 repo_private = v.StringBoolean(if_missing=False)
189 repo_private = v.StringBoolean(if_missing=False)
190 repo_landing_rev = v.OneOf(landing_revs, hideList=True)
190 repo_landing_rev = v.OneOf(landing_revs, hideList=True)
191 clone_uri = All(v.UnicodeString(strip=True, min=1, not_empty=False))
191 clone_uri = All(v.UnicodeString(strip=True, min=1, not_empty=False))
192
192
193 repo_enable_statistics = v.StringBoolean(if_missing=False)
193 repo_enable_statistics = v.StringBoolean(if_missing=False)
194 repo_enable_downloads = v.StringBoolean(if_missing=False)
194 repo_enable_downloads = v.StringBoolean(if_missing=False)
195 repo_enable_locking = v.StringBoolean(if_missing=False)
195 repo_enable_locking = v.StringBoolean(if_missing=False)
196
196
197 if edit:
197 if edit:
198 #this is repo owner
198 #this is repo owner
199 user = All(v.UnicodeString(not_empty=True), v.ValidRepoUser())
199 user = All(v.UnicodeString(not_empty=True), v.ValidRepoUser())
200
200
201 chained_validators = [v.ValidCloneUri(),
201 chained_validators = [v.ValidCloneUri(),
202 v.ValidRepoName(edit, old_data),
202 v.ValidRepoName(edit, old_data)]
203 v.ValidPerms()]
204 return _RepoForm
203 return _RepoForm
205
204
206
205
206 def RepoPermsForm():
207 class _RepoPermsForm(formencode.Schema):
208 allow_extra_fields = True
209 filter_extra_fields = False
210 chained_validators = [v.ValidPerms()]
211 return _RepoPermsForm
212
213
207 def RepoFieldForm():
214 def RepoFieldForm():
208 class _RepoFieldForm(formencode.Schema):
215 class _RepoFieldForm(formencode.Schema):
209 filter_extra_fields = True
216 filter_extra_fields = True
210 allow_extra_fields = True
217 allow_extra_fields = True
211
218
212 new_field_key = All(v.FieldKey(),
219 new_field_key = All(v.FieldKey(),
213 v.UnicodeString(strip=True, min=3, not_empty=True))
220 v.UnicodeString(strip=True, min=3, not_empty=True))
214 new_field_value = v.UnicodeString(not_empty=False, if_missing='')
221 new_field_value = v.UnicodeString(not_empty=False, if_missing='')
215 new_field_type = v.OneOf(['str', 'unicode', 'list', 'tuple'],
222 new_field_type = v.OneOf(['str', 'unicode', 'list', 'tuple'],
216 if_missing='str')
223 if_missing='str')
217 new_field_label = v.UnicodeString(not_empty=False)
224 new_field_label = v.UnicodeString(not_empty=False)
218 new_field_desc = v.UnicodeString(not_empty=False)
225 new_field_desc = v.UnicodeString(not_empty=False)
219
226
220 return _RepoFieldForm
227 return _RepoFieldForm
221
228
222
229
223 def RepoSettingsForm(edit=False, old_data={}, supported_backends=BACKENDS.keys(),
230 def RepoSettingsForm(edit=False, old_data={}, supported_backends=BACKENDS.keys(),
224 repo_groups=[], landing_revs=[]):
231 repo_groups=[], landing_revs=[]):
225 class _RepoForm(formencode.Schema):
232 class _RepoForm(formencode.Schema):
226 allow_extra_fields = True
233 allow_extra_fields = True
227 filter_extra_fields = False
234 filter_extra_fields = False
228 repo_name = All(v.UnicodeString(strip=True, min=1, not_empty=True),
235 repo_name = All(v.UnicodeString(strip=True, min=1, not_empty=True),
229 v.SlugifyName())
236 v.SlugifyName())
230 repo_group = All(v.CanWriteGroup(old_data),
237 repo_group = All(v.CanWriteGroup(old_data),
231 v.OneOf(repo_groups, hideList=True))
238 v.OneOf(repo_groups, hideList=True))
232 repo_description = v.UnicodeString(strip=True, min=1, not_empty=False)
239 repo_description = v.UnicodeString(strip=True, min=1, not_empty=False)
233 repo_private = v.StringBoolean(if_missing=False)
240 repo_private = v.StringBoolean(if_missing=False)
234 repo_landing_rev = v.OneOf(landing_revs, hideList=True)
241 repo_landing_rev = v.OneOf(landing_revs, hideList=True)
235 clone_uri = All(v.UnicodeString(strip=True, min=1, not_empty=False))
242 clone_uri = All(v.UnicodeString(strip=True, min=1, not_empty=False))
236
243
237 chained_validators = [v.ValidCloneUri(),
244 chained_validators = [v.ValidCloneUri(),
238 v.ValidRepoName(edit, old_data),
245 v.ValidRepoName(edit, old_data),
239 v.ValidPerms(),
246 v.ValidPerms(),
240 v.ValidSettings()]
247 v.ValidSettings()]
241 return _RepoForm
248 return _RepoForm
242
249
243
250
244 def RepoForkForm(edit=False, old_data={}, supported_backends=BACKENDS.keys(),
251 def RepoForkForm(edit=False, old_data={}, supported_backends=BACKENDS.keys(),
245 repo_groups=[], landing_revs=[]):
252 repo_groups=[], landing_revs=[]):
246 class _RepoForkForm(formencode.Schema):
253 class _RepoForkForm(formencode.Schema):
247 allow_extra_fields = True
254 allow_extra_fields = True
248 filter_extra_fields = False
255 filter_extra_fields = False
249 repo_name = All(v.UnicodeString(strip=True, min=1, not_empty=True),
256 repo_name = All(v.UnicodeString(strip=True, min=1, not_empty=True),
250 v.SlugifyName())
257 v.SlugifyName())
251 repo_group = All(v.CanWriteGroup(),
258 repo_group = All(v.CanWriteGroup(),
252 v.OneOf(repo_groups, hideList=True))
259 v.OneOf(repo_groups, hideList=True))
253 repo_type = All(v.ValidForkType(old_data), v.OneOf(supported_backends))
260 repo_type = All(v.ValidForkType(old_data), v.OneOf(supported_backends))
254 description = v.UnicodeString(strip=True, min=1, not_empty=True)
261 description = v.UnicodeString(strip=True, min=1, not_empty=True)
255 private = v.StringBoolean(if_missing=False)
262 private = v.StringBoolean(if_missing=False)
256 copy_permissions = v.StringBoolean(if_missing=False)
263 copy_permissions = v.StringBoolean(if_missing=False)
257 update_after_clone = v.StringBoolean(if_missing=False)
264 update_after_clone = v.StringBoolean(if_missing=False)
258 fork_parent_id = v.UnicodeString()
265 fork_parent_id = v.UnicodeString()
259 chained_validators = [v.ValidForkName(edit, old_data)]
266 chained_validators = [v.ValidForkName(edit, old_data)]
260 landing_rev = v.OneOf(landing_revs, hideList=True)
267 landing_rev = v.OneOf(landing_revs, hideList=True)
261
268
262 return _RepoForkForm
269 return _RepoForkForm
263
270
264
271
265 def ApplicationSettingsForm():
272 def ApplicationSettingsForm():
266 class _ApplicationSettingsForm(formencode.Schema):
273 class _ApplicationSettingsForm(formencode.Schema):
267 allow_extra_fields = True
274 allow_extra_fields = True
268 filter_extra_fields = False
275 filter_extra_fields = False
269 rhodecode_title = v.UnicodeString(strip=True, min=1, not_empty=True)
276 rhodecode_title = v.UnicodeString(strip=True, min=1, not_empty=True)
270 rhodecode_realm = v.UnicodeString(strip=True, min=1, not_empty=True)
277 rhodecode_realm = v.UnicodeString(strip=True, min=1, not_empty=True)
271 rhodecode_ga_code = v.UnicodeString(strip=True, min=1, not_empty=False)
278 rhodecode_ga_code = v.UnicodeString(strip=True, min=1, not_empty=False)
272
279
273 return _ApplicationSettingsForm
280 return _ApplicationSettingsForm
274
281
275
282
276 def ApplicationVisualisationForm():
283 def ApplicationVisualisationForm():
277 class _ApplicationVisualisationForm(formencode.Schema):
284 class _ApplicationVisualisationForm(formencode.Schema):
278 allow_extra_fields = True
285 allow_extra_fields = True
279 filter_extra_fields = False
286 filter_extra_fields = False
280 rhodecode_show_public_icon = v.StringBoolean(if_missing=False)
287 rhodecode_show_public_icon = v.StringBoolean(if_missing=False)
281 rhodecode_show_private_icon = v.StringBoolean(if_missing=False)
288 rhodecode_show_private_icon = v.StringBoolean(if_missing=False)
282 rhodecode_stylify_metatags = v.StringBoolean(if_missing=False)
289 rhodecode_stylify_metatags = v.StringBoolean(if_missing=False)
283
290
284 rhodecode_lightweight_dashboard = v.StringBoolean(if_missing=False)
291 rhodecode_lightweight_dashboard = v.StringBoolean(if_missing=False)
285 rhodecode_repository_fields = v.StringBoolean(if_missing=False)
292 rhodecode_repository_fields = v.StringBoolean(if_missing=False)
286 rhodecode_lightweight_journal = v.StringBoolean(if_missing=False)
293 rhodecode_lightweight_journal = v.StringBoolean(if_missing=False)
287
294
288 return _ApplicationVisualisationForm
295 return _ApplicationVisualisationForm
289
296
290
297
291 def ApplicationUiSettingsForm():
298 def ApplicationUiSettingsForm():
292 class _ApplicationUiSettingsForm(formencode.Schema):
299 class _ApplicationUiSettingsForm(formencode.Schema):
293 allow_extra_fields = True
300 allow_extra_fields = True
294 filter_extra_fields = False
301 filter_extra_fields = False
295 web_push_ssl = v.StringBoolean(if_missing=False)
302 web_push_ssl = v.StringBoolean(if_missing=False)
296 paths_root_path = All(
303 paths_root_path = All(
297 v.ValidPath(),
304 v.ValidPath(),
298 v.UnicodeString(strip=True, min=1, not_empty=True)
305 v.UnicodeString(strip=True, min=1, not_empty=True)
299 )
306 )
300 hooks_changegroup_update = v.StringBoolean(if_missing=False)
307 hooks_changegroup_update = v.StringBoolean(if_missing=False)
301 hooks_changegroup_repo_size = v.StringBoolean(if_missing=False)
308 hooks_changegroup_repo_size = v.StringBoolean(if_missing=False)
302 hooks_changegroup_push_logger = v.StringBoolean(if_missing=False)
309 hooks_changegroup_push_logger = v.StringBoolean(if_missing=False)
303 hooks_outgoing_pull_logger = v.StringBoolean(if_missing=False)
310 hooks_outgoing_pull_logger = v.StringBoolean(if_missing=False)
304
311
305 extensions_largefiles = v.StringBoolean(if_missing=False)
312 extensions_largefiles = v.StringBoolean(if_missing=False)
306 extensions_hgsubversion = v.StringBoolean(if_missing=False)
313 extensions_hgsubversion = v.StringBoolean(if_missing=False)
307 extensions_hggit = v.StringBoolean(if_missing=False)
314 extensions_hggit = v.StringBoolean(if_missing=False)
308
315
309 return _ApplicationUiSettingsForm
316 return _ApplicationUiSettingsForm
310
317
311
318
312 def DefaultPermissionsForm(repo_perms_choices, group_perms_choices,
319 def DefaultPermissionsForm(repo_perms_choices, group_perms_choices,
313 register_choices, create_choices, fork_choices):
320 register_choices, create_choices, fork_choices):
314 class _DefaultPermissionsForm(formencode.Schema):
321 class _DefaultPermissionsForm(formencode.Schema):
315 allow_extra_fields = True
322 allow_extra_fields = True
316 filter_extra_fields = True
323 filter_extra_fields = True
317 overwrite_default_repo = v.StringBoolean(if_missing=False)
324 overwrite_default_repo = v.StringBoolean(if_missing=False)
318 overwrite_default_group = v.StringBoolean(if_missing=False)
325 overwrite_default_group = v.StringBoolean(if_missing=False)
319 anonymous = v.StringBoolean(if_missing=False)
326 anonymous = v.StringBoolean(if_missing=False)
320 default_repo_perm = v.OneOf(repo_perms_choices)
327 default_repo_perm = v.OneOf(repo_perms_choices)
321 default_group_perm = v.OneOf(group_perms_choices)
328 default_group_perm = v.OneOf(group_perms_choices)
322 default_register = v.OneOf(register_choices)
329 default_register = v.OneOf(register_choices)
323 default_create = v.OneOf(create_choices)
330 default_create = v.OneOf(create_choices)
324 default_fork = v.OneOf(fork_choices)
331 default_fork = v.OneOf(fork_choices)
325
332
326 return _DefaultPermissionsForm
333 return _DefaultPermissionsForm
327
334
328
335
329 def DefaultsForm(edit=False, old_data={}, supported_backends=BACKENDS.keys()):
336 def DefaultsForm(edit=False, old_data={}, supported_backends=BACKENDS.keys()):
330 class _DefaultsForm(formencode.Schema):
337 class _DefaultsForm(formencode.Schema):
331 allow_extra_fields = True
338 allow_extra_fields = True
332 filter_extra_fields = True
339 filter_extra_fields = True
333 default_repo_type = v.OneOf(supported_backends)
340 default_repo_type = v.OneOf(supported_backends)
334 default_repo_private = v.StringBoolean(if_missing=False)
341 default_repo_private = v.StringBoolean(if_missing=False)
335 default_repo_enable_statistics = v.StringBoolean(if_missing=False)
342 default_repo_enable_statistics = v.StringBoolean(if_missing=False)
336 default_repo_enable_downloads = v.StringBoolean(if_missing=False)
343 default_repo_enable_downloads = v.StringBoolean(if_missing=False)
337 default_repo_enable_locking = v.StringBoolean(if_missing=False)
344 default_repo_enable_locking = v.StringBoolean(if_missing=False)
338
345
339 return _DefaultsForm
346 return _DefaultsForm
340
347
341
348
342 def LdapSettingsForm(tls_reqcert_choices, search_scope_choices,
349 def LdapSettingsForm(tls_reqcert_choices, search_scope_choices,
343 tls_kind_choices):
350 tls_kind_choices):
344 class _LdapSettingsForm(formencode.Schema):
351 class _LdapSettingsForm(formencode.Schema):
345 allow_extra_fields = True
352 allow_extra_fields = True
346 filter_extra_fields = True
353 filter_extra_fields = True
347 #pre_validators = [LdapLibValidator]
354 #pre_validators = [LdapLibValidator]
348 ldap_active = v.StringBoolean(if_missing=False)
355 ldap_active = v.StringBoolean(if_missing=False)
349 ldap_host = v.UnicodeString(strip=True,)
356 ldap_host = v.UnicodeString(strip=True,)
350 ldap_port = v.Number(strip=True,)
357 ldap_port = v.Number(strip=True,)
351 ldap_tls_kind = v.OneOf(tls_kind_choices)
358 ldap_tls_kind = v.OneOf(tls_kind_choices)
352 ldap_tls_reqcert = v.OneOf(tls_reqcert_choices)
359 ldap_tls_reqcert = v.OneOf(tls_reqcert_choices)
353 ldap_dn_user = v.UnicodeString(strip=True,)
360 ldap_dn_user = v.UnicodeString(strip=True,)
354 ldap_dn_pass = v.UnicodeString(strip=True,)
361 ldap_dn_pass = v.UnicodeString(strip=True,)
355 ldap_base_dn = v.UnicodeString(strip=True,)
362 ldap_base_dn = v.UnicodeString(strip=True,)
356 ldap_filter = v.UnicodeString(strip=True,)
363 ldap_filter = v.UnicodeString(strip=True,)
357 ldap_search_scope = v.OneOf(search_scope_choices)
364 ldap_search_scope = v.OneOf(search_scope_choices)
358 ldap_attr_login = All(
365 ldap_attr_login = All(
359 v.AttrLoginValidator(),
366 v.AttrLoginValidator(),
360 v.UnicodeString(strip=True,)
367 v.UnicodeString(strip=True,)
361 )
368 )
362 ldap_attr_firstname = v.UnicodeString(strip=True,)
369 ldap_attr_firstname = v.UnicodeString(strip=True,)
363 ldap_attr_lastname = v.UnicodeString(strip=True,)
370 ldap_attr_lastname = v.UnicodeString(strip=True,)
364 ldap_attr_email = v.UnicodeString(strip=True,)
371 ldap_attr_email = v.UnicodeString(strip=True,)
365
372
366 return _LdapSettingsForm
373 return _LdapSettingsForm
367
374
368
375
369 def UserExtraEmailForm():
376 def UserExtraEmailForm():
370 class _UserExtraEmailForm(formencode.Schema):
377 class _UserExtraEmailForm(formencode.Schema):
371 email = All(v.UniqSystemEmail(), v.Email(not_empty=True))
378 email = All(v.UniqSystemEmail(), v.Email(not_empty=True))
372 return _UserExtraEmailForm
379 return _UserExtraEmailForm
373
380
374
381
375 def UserExtraIpForm():
382 def UserExtraIpForm():
376 class _UserExtraIpForm(formencode.Schema):
383 class _UserExtraIpForm(formencode.Schema):
377 ip = v.ValidIp()(not_empty=True)
384 ip = v.ValidIp()(not_empty=True)
378 return _UserExtraIpForm
385 return _UserExtraIpForm
379
386
380
387
381 def PullRequestForm(repo_id):
388 def PullRequestForm(repo_id):
382 class _PullRequestForm(formencode.Schema):
389 class _PullRequestForm(formencode.Schema):
383 allow_extra_fields = True
390 allow_extra_fields = True
384 filter_extra_fields = True
391 filter_extra_fields = True
385
392
386 user = v.UnicodeString(strip=True, required=True)
393 user = v.UnicodeString(strip=True, required=True)
387 org_repo = v.UnicodeString(strip=True, required=True)
394 org_repo = v.UnicodeString(strip=True, required=True)
388 org_ref = v.UnicodeString(strip=True, required=True)
395 org_ref = v.UnicodeString(strip=True, required=True)
389 other_repo = v.UnicodeString(strip=True, required=True)
396 other_repo = v.UnicodeString(strip=True, required=True)
390 other_ref = v.UnicodeString(strip=True, required=True)
397 other_ref = v.UnicodeString(strip=True, required=True)
391 revisions = All(#v.NotReviewedRevisions(repo_id)(),
398 revisions = All(#v.NotReviewedRevisions(repo_id)(),
392 v.UniqueList(not_empty=True))
399 v.UniqueList(not_empty=True))
393 review_members = v.UniqueList(not_empty=True)
400 review_members = v.UniqueList(not_empty=True)
394
401
395 pullrequest_title = v.UnicodeString(strip=True, required=True, min=3)
402 pullrequest_title = v.UnicodeString(strip=True, required=True, min=3)
396 pullrequest_desc = v.UnicodeString(strip=True, required=False)
403 pullrequest_desc = v.UnicodeString(strip=True, required=False)
397
404
398 ancestor_rev = v.UnicodeString(strip=True, required=True)
405 ancestor_rev = v.UnicodeString(strip=True, required=True)
399 merge_rev = v.UnicodeString(strip=True, required=True)
406 merge_rev = v.UnicodeString(strip=True, required=True)
400
407
401 return _PullRequestForm
408 return _PullRequestForm
@@ -1,700 +1,678 b''
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 remove_prefix, obfuscate_url_pw
35 remove_prefix, obfuscate_url_pw
36 from rhodecode.lib.caching_query import FromCache
36 from rhodecode.lib.caching_query import FromCache
37 from rhodecode.lib.hooks import log_create_repository, log_delete_repository
37 from rhodecode.lib.hooks import log_create_repository, log_delete_repository
38
38
39 from rhodecode.model import BaseModel
39 from rhodecode.model import BaseModel
40 from rhodecode.model.db import Repository, UserRepoToPerm, User, Permission, \
40 from rhodecode.model.db import Repository, UserRepoToPerm, User, Permission, \
41 Statistics, UserGroup, UserGroupRepoToPerm, RhodeCodeUi, RepoGroup,\
41 Statistics, UserGroup, UserGroupRepoToPerm, RhodeCodeUi, RepoGroup,\
42 RhodeCodeSetting, RepositoryField
42 RhodeCodeSetting, RepositoryField
43 from rhodecode.lib import helpers as h
43 from rhodecode.lib import helpers as h
44 from rhodecode.lib.auth import HasRepoPermissionAny
44 from rhodecode.lib.auth import HasRepoPermissionAny
45
45
46 log = logging.getLogger(__name__)
46 log = logging.getLogger(__name__)
47
47
48
48
49 class RepoModel(BaseModel):
49 class RepoModel(BaseModel):
50
50
51 cls = Repository
51 cls = Repository
52 URL_SEPARATOR = Repository.url_sep()
52 URL_SEPARATOR = Repository.url_sep()
53
53
54 def __get_users_group(self, users_group):
54 def __get_users_group(self, users_group):
55 return self._get_instance(UserGroup, users_group,
55 return self._get_instance(UserGroup, users_group,
56 callback=UserGroup.get_by_group_name)
56 callback=UserGroup.get_by_group_name)
57
57
58 def _get_repos_group(self, repos_group):
58 def _get_repos_group(self, repos_group):
59 return self._get_instance(RepoGroup, repos_group,
59 return self._get_instance(RepoGroup, repos_group,
60 callback=RepoGroup.get_by_group_name)
60 callback=RepoGroup.get_by_group_name)
61
61
62 @LazyProperty
62 @LazyProperty
63 def repos_path(self):
63 def repos_path(self):
64 """
64 """
65 Get's the repositories root path from database
65 Get's the repositories root path from database
66 """
66 """
67
67
68 q = self.sa.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key == '/').one()
68 q = self.sa.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key == '/').one()
69 return q.ui_value
69 return q.ui_value
70
70
71 def get(self, repo_id, cache=False):
71 def get(self, repo_id, cache=False):
72 repo = self.sa.query(Repository)\
72 repo = self.sa.query(Repository)\
73 .filter(Repository.repo_id == repo_id)
73 .filter(Repository.repo_id == repo_id)
74
74
75 if cache:
75 if cache:
76 repo = repo.options(FromCache("sql_cache_short",
76 repo = repo.options(FromCache("sql_cache_short",
77 "get_repo_%s" % repo_id))
77 "get_repo_%s" % repo_id))
78 return repo.scalar()
78 return repo.scalar()
79
79
80 def get_repo(self, repository):
80 def get_repo(self, repository):
81 return self._get_repo(repository)
81 return self._get_repo(repository)
82
82
83 def get_by_repo_name(self, repo_name, cache=False):
83 def get_by_repo_name(self, repo_name, cache=False):
84 repo = self.sa.query(Repository)\
84 repo = self.sa.query(Repository)\
85 .filter(Repository.repo_name == repo_name)
85 .filter(Repository.repo_name == repo_name)
86
86
87 if cache:
87 if cache:
88 repo = repo.options(FromCache("sql_cache_short",
88 repo = repo.options(FromCache("sql_cache_short",
89 "get_repo_%s" % repo_name))
89 "get_repo_%s" % repo_name))
90 return repo.scalar()
90 return repo.scalar()
91
91
92 def get_all_user_repos(self, user):
92 def get_all_user_repos(self, user):
93 """
93 """
94 Get's all repositories that user have at least read access
94 Get's all repositories that user have at least read access
95
95
96 :param user:
96 :param user:
97 :type user:
97 :type user:
98 """
98 """
99 from rhodecode.lib.auth import AuthUser
99 from rhodecode.lib.auth import AuthUser
100 user = self._get_user(user)
100 user = self._get_user(user)
101 repos = AuthUser(user_id=user.user_id).permissions['repositories']
101 repos = AuthUser(user_id=user.user_id).permissions['repositories']
102 access_check = lambda r: r[1] in ['repository.read',
102 access_check = lambda r: r[1] in ['repository.read',
103 'repository.write',
103 'repository.write',
104 'repository.admin']
104 'repository.admin']
105 repos = [x[0] for x in filter(access_check, repos.items())]
105 repos = [x[0] for x in filter(access_check, repos.items())]
106 return Repository.query().filter(Repository.repo_name.in_(repos))
106 return Repository.query().filter(Repository.repo_name.in_(repos))
107
107
108 def get_users_js(self):
108 def get_users_js(self):
109 users = self.sa.query(User).filter(User.active == True).all()
109 users = self.sa.query(User).filter(User.active == True).all()
110 return json.dumps([
110 return json.dumps([
111 {
111 {
112 'id': u.user_id,
112 'id': u.user_id,
113 'fname': u.name,
113 'fname': u.name,
114 'lname': u.lastname,
114 'lname': u.lastname,
115 'nname': u.username,
115 'nname': u.username,
116 'gravatar_lnk': h.gravatar_url(u.email, 14)
116 'gravatar_lnk': h.gravatar_url(u.email, 14)
117 } for u in users]
117 } for u in users]
118 )
118 )
119
119
120 def get_users_groups_js(self):
120 def get_users_groups_js(self):
121 users_groups = self.sa.query(UserGroup)\
121 users_groups = self.sa.query(UserGroup)\
122 .filter(UserGroup.users_group_active == True).all()
122 .filter(UserGroup.users_group_active == True).all()
123
123
124 return json.dumps([
124 return json.dumps([
125 {
125 {
126 'id': gr.users_group_id,
126 'id': gr.users_group_id,
127 'grname': gr.users_group_name,
127 'grname': gr.users_group_name,
128 'grmembers': len(gr.members),
128 'grmembers': len(gr.members),
129 } for gr in users_groups]
129 } for gr in users_groups]
130 )
130 )
131
131
132 @classmethod
132 @classmethod
133 def _render_datatable(cls, tmpl, *args, **kwargs):
133 def _render_datatable(cls, tmpl, *args, **kwargs):
134 import rhodecode
134 import rhodecode
135 from pylons import tmpl_context as c
135 from pylons import tmpl_context as c
136 from pylons.i18n.translation import _
136 from pylons.i18n.translation import _
137
137
138 _tmpl_lookup = rhodecode.CONFIG['pylons.app_globals'].mako_lookup
138 _tmpl_lookup = rhodecode.CONFIG['pylons.app_globals'].mako_lookup
139 template = _tmpl_lookup.get_template('data_table/_dt_elements.html')
139 template = _tmpl_lookup.get_template('data_table/_dt_elements.html')
140
140
141 tmpl = template.get_def(tmpl)
141 tmpl = template.get_def(tmpl)
142 kwargs.update(dict(_=_, h=h, c=c))
142 kwargs.update(dict(_=_, h=h, c=c))
143 return tmpl.render(*args, **kwargs)
143 return tmpl.render(*args, **kwargs)
144
144
145 @classmethod
145 @classmethod
146 def update_repoinfo(cls, repositories=None):
146 def update_repoinfo(cls, repositories=None):
147 if not repositories:
147 if not repositories:
148 repositories = Repository.getAll()
148 repositories = Repository.getAll()
149 for repo in repositories:
149 for repo in repositories:
150 repo.update_changeset_cache()
150 repo.update_changeset_cache()
151
151
152 def get_repos_as_dict(self, repos_list=None, admin=False, perm_check=True,
152 def get_repos_as_dict(self, repos_list=None, admin=False, perm_check=True,
153 super_user_actions=False):
153 super_user_actions=False):
154 _render = self._render_datatable
154 _render = self._render_datatable
155
155
156 def quick_menu(repo_name):
156 def quick_menu(repo_name):
157 return _render('quick_menu', repo_name)
157 return _render('quick_menu', repo_name)
158
158
159 def repo_lnk(name, rtype, private, fork_of):
159 def repo_lnk(name, rtype, private, fork_of):
160 return _render('repo_name', name, rtype, private, fork_of,
160 return _render('repo_name', name, rtype, private, fork_of,
161 short_name=not admin, admin=False)
161 short_name=not admin, admin=False)
162
162
163 def last_change(last_change):
163 def last_change(last_change):
164 return _render("last_change", last_change)
164 return _render("last_change", last_change)
165
165
166 def rss_lnk(repo_name):
166 def rss_lnk(repo_name):
167 return _render("rss", repo_name)
167 return _render("rss", repo_name)
168
168
169 def atom_lnk(repo_name):
169 def atom_lnk(repo_name):
170 return _render("atom", repo_name)
170 return _render("atom", repo_name)
171
171
172 def last_rev(repo_name, cs_cache):
172 def last_rev(repo_name, cs_cache):
173 return _render('revision', repo_name, cs_cache.get('revision'),
173 return _render('revision', repo_name, cs_cache.get('revision'),
174 cs_cache.get('raw_id'), cs_cache.get('author'),
174 cs_cache.get('raw_id'), cs_cache.get('author'),
175 cs_cache.get('message'))
175 cs_cache.get('message'))
176
176
177 def desc(desc):
177 def desc(desc):
178 from pylons import tmpl_context as c
178 from pylons import tmpl_context as c
179 if c.visual.stylify_metatags:
179 if c.visual.stylify_metatags:
180 return h.urlify_text(h.desc_stylize(h.truncate(desc, 60)))
180 return h.urlify_text(h.desc_stylize(h.truncate(desc, 60)))
181 else:
181 else:
182 return h.urlify_text(h.truncate(desc, 60))
182 return h.urlify_text(h.truncate(desc, 60))
183
183
184 def repo_actions(repo_name):
184 def repo_actions(repo_name):
185 return _render('repo_actions', repo_name, super_user_actions)
185 return _render('repo_actions', repo_name, super_user_actions)
186
186
187 def owner_actions(user_id, username):
187 def owner_actions(user_id, username):
188 return _render('user_name', user_id, username)
188 return _render('user_name', user_id, username)
189
189
190 repos_data = []
190 repos_data = []
191 for repo in repos_list:
191 for repo in repos_list:
192 if perm_check:
192 if perm_check:
193 # check permission at this level
193 # check permission at this level
194 if not HasRepoPermissionAny(
194 if not HasRepoPermissionAny(
195 'repository.read', 'repository.write', 'repository.admin'
195 'repository.read', 'repository.write', 'repository.admin'
196 )(repo.repo_name, 'get_repos_as_dict check'):
196 )(repo.repo_name, 'get_repos_as_dict check'):
197 continue
197 continue
198 cs_cache = repo.changeset_cache
198 cs_cache = repo.changeset_cache
199 row = {
199 row = {
200 "menu": quick_menu(repo.repo_name),
200 "menu": quick_menu(repo.repo_name),
201 "raw_name": repo.repo_name.lower(),
201 "raw_name": repo.repo_name.lower(),
202 "name": repo_lnk(repo.repo_name, repo.repo_type,
202 "name": repo_lnk(repo.repo_name, repo.repo_type,
203 repo.private, repo.fork),
203 repo.private, repo.fork),
204 "last_change": last_change(repo.last_db_change),
204 "last_change": last_change(repo.last_db_change),
205 "last_changeset": last_rev(repo.repo_name, cs_cache),
205 "last_changeset": last_rev(repo.repo_name, cs_cache),
206 "raw_tip": cs_cache.get('revision'),
206 "raw_tip": cs_cache.get('revision'),
207 "desc": desc(repo.description),
207 "desc": desc(repo.description),
208 "owner": h.person(repo.user.username),
208 "owner": h.person(repo.user.username),
209 "rss": rss_lnk(repo.repo_name),
209 "rss": rss_lnk(repo.repo_name),
210 "atom": atom_lnk(repo.repo_name),
210 "atom": atom_lnk(repo.repo_name),
211
211
212 }
212 }
213 if admin:
213 if admin:
214 row.update({
214 row.update({
215 "action": repo_actions(repo.repo_name),
215 "action": repo_actions(repo.repo_name),
216 "owner": owner_actions(repo.user.user_id,
216 "owner": owner_actions(repo.user.user_id,
217 h.person(repo.user.username))
217 h.person(repo.user.username))
218 })
218 })
219 repos_data.append(row)
219 repos_data.append(row)
220
220
221 return {
221 return {
222 "totalRecords": len(repos_list),
222 "totalRecords": len(repos_list),
223 "startIndex": 0,
223 "startIndex": 0,
224 "sort": "name",
224 "sort": "name",
225 "dir": "asc",
225 "dir": "asc",
226 "records": repos_data
226 "records": repos_data
227 }
227 }
228
228
229 def _get_defaults(self, repo_name):
229 def _get_defaults(self, repo_name):
230 """
230 """
231 Get's information about repository, and returns a dict for
231 Get's information about repository, and returns a dict for
232 usage in forms
232 usage in forms
233
233
234 :param repo_name:
234 :param repo_name:
235 """
235 """
236
236
237 repo_info = Repository.get_by_repo_name(repo_name)
237 repo_info = Repository.get_by_repo_name(repo_name)
238
238
239 if repo_info is None:
239 if repo_info is None:
240 return None
240 return None
241
241
242 defaults = repo_info.get_dict()
242 defaults = repo_info.get_dict()
243 group, repo_name, repo_name_full = repo_info.groups_and_repo
243 group, repo_name, repo_name_full = repo_info.groups_and_repo
244 defaults['repo_name'] = repo_name
244 defaults['repo_name'] = repo_name
245 defaults['repo_group'] = getattr(group[-1] if group else None,
245 defaults['repo_group'] = getattr(group[-1] if group else None,
246 'group_id', None)
246 'group_id', None)
247
247
248 for strip, k in [(0, 'repo_type'), (1, 'repo_enable_downloads'),
248 for strip, k in [(0, 'repo_type'), (1, 'repo_enable_downloads'),
249 (1, 'repo_description'), (1, 'repo_enable_locking'),
249 (1, 'repo_description'), (1, 'repo_enable_locking'),
250 (1, 'repo_landing_rev'), (0, 'clone_uri'),
250 (1, 'repo_landing_rev'), (0, 'clone_uri'),
251 (1, 'repo_private'), (1, 'repo_enable_statistics')]:
251 (1, 'repo_private'), (1, 'repo_enable_statistics')]:
252 attr = k
252 attr = k
253 if strip:
253 if strip:
254 attr = remove_prefix(k, 'repo_')
254 attr = remove_prefix(k, 'repo_')
255
255
256 defaults[k] = defaults[attr]
256 defaults[k] = defaults[attr]
257
257
258 # fill owner
258 # fill owner
259 if repo_info.user:
259 if repo_info.user:
260 defaults.update({'user': repo_info.user.username})
260 defaults.update({'user': repo_info.user.username})
261 else:
261 else:
262 replacement_user = User.query().filter(User.admin ==
262 replacement_user = User.query().filter(User.admin ==
263 True).first().username
263 True).first().username
264 defaults.update({'user': replacement_user})
264 defaults.update({'user': replacement_user})
265
265
266 # fill repository users
266 # fill repository users
267 for p in repo_info.repo_to_perm:
267 for p in repo_info.repo_to_perm:
268 defaults.update({'u_perm_%s' % p.user.username:
268 defaults.update({'u_perm_%s' % p.user.username:
269 p.permission.permission_name})
269 p.permission.permission_name})
270
270
271 # fill repository groups
271 # fill repository groups
272 for p in repo_info.users_group_to_perm:
272 for p in repo_info.users_group_to_perm:
273 defaults.update({'g_perm_%s' % p.users_group.users_group_name:
273 defaults.update({'g_perm_%s' % p.users_group.users_group_name:
274 p.permission.permission_name})
274 p.permission.permission_name})
275
275
276 return defaults
276 return defaults
277
277
278 def update(self, org_repo_name, **kwargs):
278 def update(self, org_repo_name, **kwargs):
279 try:
279 try:
280 cur_repo = self.get_by_repo_name(org_repo_name, cache=False)
280 cur_repo = self.get_by_repo_name(org_repo_name, cache=False)
281
281
282 # update permissions
283 for member, perm, member_type in kwargs['perms_updates']:
284 if member_type == 'user':
285 # this updates existing one
286 RepoModel().grant_user_permission(
287 repo=cur_repo, user=member, perm=perm
288 )
289 else:
290 RepoModel().grant_users_group_permission(
291 repo=cur_repo, group_name=member, perm=perm
292 )
293 # set new permissions
294 for member, perm, member_type in kwargs['perms_new']:
295 if member_type == 'user':
296 RepoModel().grant_user_permission(
297 repo=cur_repo, user=member, perm=perm
298 )
299 else:
300 RepoModel().grant_users_group_permission(
301 repo=cur_repo, group_name=member, perm=perm
302 )
303
304 if 'user' in kwargs:
282 if 'user' in kwargs:
305 cur_repo.user = User.get_by_username(kwargs['user'])
283 cur_repo.user = User.get_by_username(kwargs['user'])
306
284
307 if 'repo_group' in kwargs:
285 if 'repo_group' in kwargs:
308 cur_repo.group = RepoGroup.get(kwargs['repo_group'])
286 cur_repo.group = RepoGroup.get(kwargs['repo_group'])
309
287
310 for strip, k in [(0, 'repo_type'), (1, 'repo_enable_downloads'),
288 for strip, k in [(0, 'repo_type'), (1, 'repo_enable_downloads'),
311 (1, 'repo_description'), (1, 'repo_enable_locking'),
289 (1, 'repo_description'), (1, 'repo_enable_locking'),
312 (1, 'repo_landing_rev'), (0, 'clone_uri'),
290 (1, 'repo_landing_rev'), (0, 'clone_uri'),
313 (1, 'repo_private'), (1, 'repo_enable_statistics')]:
291 (1, 'repo_private'), (1, 'repo_enable_statistics')]:
314 if k in kwargs:
292 if k in kwargs:
315 val = kwargs[k]
293 val = kwargs[k]
316 if strip:
294 if strip:
317 k = remove_prefix(k, 'repo_')
295 k = remove_prefix(k, 'repo_')
318 setattr(cur_repo, k, val)
296 setattr(cur_repo, k, val)
319
297
320 new_name = cur_repo.get_new_name(kwargs['repo_name'])
298 new_name = cur_repo.get_new_name(kwargs['repo_name'])
321 cur_repo.repo_name = new_name
299 cur_repo.repo_name = new_name
322
300
323 #handle extra fields
301 #handle extra fields
324 for field in filter(lambda k: k.startswith(RepositoryField.PREFIX), kwargs):
302 for field in filter(lambda k: k.startswith(RepositoryField.PREFIX), kwargs):
325 k = RepositoryField.un_prefix_key(field)
303 k = RepositoryField.un_prefix_key(field)
326 ex_field = RepositoryField.get_by_key_name(key=k, repo=cur_repo)
304 ex_field = RepositoryField.get_by_key_name(key=k, repo=cur_repo)
327 if ex_field:
305 if ex_field:
328 ex_field.field_value = kwargs[field]
306 ex_field.field_value = kwargs[field]
329 self.sa.add(ex_field)
307 self.sa.add(ex_field)
330 self.sa.add(cur_repo)
308 self.sa.add(cur_repo)
331
309
332 if org_repo_name != new_name:
310 if org_repo_name != new_name:
333 # rename repository
311 # rename repository
334 self.__rename_repo(old=org_repo_name, new=new_name)
312 self.__rename_repo(old=org_repo_name, new=new_name)
335
313
336 return cur_repo
314 return cur_repo
337 except:
315 except:
338 log.error(traceback.format_exc())
316 log.error(traceback.format_exc())
339 raise
317 raise
340
318
341 def create_repo(self, repo_name, repo_type, description, owner,
319 def create_repo(self, repo_name, repo_type, description, owner,
342 private=False, clone_uri=None, repos_group=None,
320 private=False, clone_uri=None, repos_group=None,
343 landing_rev='tip', just_db=False, fork_of=None,
321 landing_rev='tip', just_db=False, fork_of=None,
344 copy_fork_permissions=False, enable_statistics=False,
322 copy_fork_permissions=False, enable_statistics=False,
345 enable_locking=False, enable_downloads=False):
323 enable_locking=False, enable_downloads=False):
346 """
324 """
347 Create repository
325 Create repository
348
326
349 """
327 """
350 from rhodecode.model.scm import ScmModel
328 from rhodecode.model.scm import ScmModel
351
329
352 owner = self._get_user(owner)
330 owner = self._get_user(owner)
353 fork_of = self._get_repo(fork_of)
331 fork_of = self._get_repo(fork_of)
354 repos_group = self._get_repos_group(repos_group)
332 repos_group = self._get_repos_group(repos_group)
355 try:
333 try:
356
334
357 # repo name is just a name of repository
335 # repo name is just a name of repository
358 # while repo_name_full is a full qualified name that is combined
336 # while repo_name_full is a full qualified name that is combined
359 # with name and path of group
337 # with name and path of group
360 repo_name_full = repo_name
338 repo_name_full = repo_name
361 repo_name = repo_name.split(self.URL_SEPARATOR)[-1]
339 repo_name = repo_name.split(self.URL_SEPARATOR)[-1]
362
340
363 new_repo = Repository()
341 new_repo = Repository()
364 new_repo.enable_statistics = False
342 new_repo.enable_statistics = False
365 new_repo.repo_name = repo_name_full
343 new_repo.repo_name = repo_name_full
366 new_repo.repo_type = repo_type
344 new_repo.repo_type = repo_type
367 new_repo.user = owner
345 new_repo.user = owner
368 new_repo.group = repos_group
346 new_repo.group = repos_group
369 new_repo.description = description or repo_name
347 new_repo.description = description or repo_name
370 new_repo.private = private
348 new_repo.private = private
371 new_repo.clone_uri = clone_uri
349 new_repo.clone_uri = clone_uri
372 new_repo.landing_rev = landing_rev
350 new_repo.landing_rev = landing_rev
373
351
374 new_repo.enable_statistics = enable_statistics
352 new_repo.enable_statistics = enable_statistics
375 new_repo.enable_locking = enable_locking
353 new_repo.enable_locking = enable_locking
376 new_repo.enable_downloads = enable_downloads
354 new_repo.enable_downloads = enable_downloads
377
355
378 if repos_group:
356 if repos_group:
379 new_repo.enable_locking = repos_group.enable_locking
357 new_repo.enable_locking = repos_group.enable_locking
380
358
381 if fork_of:
359 if fork_of:
382 parent_repo = fork_of
360 parent_repo = fork_of
383 new_repo.fork = parent_repo
361 new_repo.fork = parent_repo
384
362
385 self.sa.add(new_repo)
363 self.sa.add(new_repo)
386
364
387 def _create_default_perms():
365 def _create_default_perms():
388 # create default permission
366 # create default permission
389 repo_to_perm = UserRepoToPerm()
367 repo_to_perm = UserRepoToPerm()
390 default = 'repository.read'
368 default = 'repository.read'
391 for p in User.get_by_username('default').user_perms:
369 for p in User.get_by_username('default').user_perms:
392 if p.permission.permission_name.startswith('repository.'):
370 if p.permission.permission_name.startswith('repository.'):
393 default = p.permission.permission_name
371 default = p.permission.permission_name
394 break
372 break
395
373
396 default_perm = 'repository.none' if private else default
374 default_perm = 'repository.none' if private else default
397
375
398 repo_to_perm.permission_id = self.sa.query(Permission)\
376 repo_to_perm.permission_id = self.sa.query(Permission)\
399 .filter(Permission.permission_name == default_perm)\
377 .filter(Permission.permission_name == default_perm)\
400 .one().permission_id
378 .one().permission_id
401
379
402 repo_to_perm.repository = new_repo
380 repo_to_perm.repository = new_repo
403 repo_to_perm.user_id = User.get_by_username('default').user_id
381 repo_to_perm.user_id = User.get_by_username('default').user_id
404
382
405 self.sa.add(repo_to_perm)
383 self.sa.add(repo_to_perm)
406
384
407 if fork_of:
385 if fork_of:
408 if copy_fork_permissions:
386 if copy_fork_permissions:
409 repo = fork_of
387 repo = fork_of
410 user_perms = UserRepoToPerm.query()\
388 user_perms = UserRepoToPerm.query()\
411 .filter(UserRepoToPerm.repository == repo).all()
389 .filter(UserRepoToPerm.repository == repo).all()
412 group_perms = UserGroupRepoToPerm.query()\
390 group_perms = UserGroupRepoToPerm.query()\
413 .filter(UserGroupRepoToPerm.repository == repo).all()
391 .filter(UserGroupRepoToPerm.repository == repo).all()
414
392
415 for perm in user_perms:
393 for perm in user_perms:
416 UserRepoToPerm.create(perm.user, new_repo,
394 UserRepoToPerm.create(perm.user, new_repo,
417 perm.permission)
395 perm.permission)
418
396
419 for perm in group_perms:
397 for perm in group_perms:
420 UserGroupRepoToPerm.create(perm.users_group, new_repo,
398 UserGroupRepoToPerm.create(perm.users_group, new_repo,
421 perm.permission)
399 perm.permission)
422 else:
400 else:
423 _create_default_perms()
401 _create_default_perms()
424 else:
402 else:
425 _create_default_perms()
403 _create_default_perms()
426
404
427 if not just_db:
405 if not just_db:
428 self.__create_repo(repo_name, repo_type,
406 self.__create_repo(repo_name, repo_type,
429 repos_group,
407 repos_group,
430 clone_uri)
408 clone_uri)
431 log_create_repository(new_repo.get_dict(),
409 log_create_repository(new_repo.get_dict(),
432 created_by=owner.username)
410 created_by=owner.username)
433
411
434 # now automatically start following this repository as owner
412 # now automatically start following this repository as owner
435 ScmModel(self.sa).toggle_following_repo(new_repo.repo_id,
413 ScmModel(self.sa).toggle_following_repo(new_repo.repo_id,
436 owner.user_id)
414 owner.user_id)
437 return new_repo
415 return new_repo
438 except:
416 except:
439 log.error(traceback.format_exc())
417 log.error(traceback.format_exc())
440 raise
418 raise
441
419
442 def create(self, form_data, cur_user, just_db=False, fork=None):
420 def create(self, form_data, cur_user, just_db=False, fork=None):
443 """
421 """
444 Backward compatibility function, just a wrapper on top of create_repo
422 Backward compatibility function, just a wrapper on top of create_repo
445
423
446 :param form_data:
424 :param form_data:
447 :param cur_user:
425 :param cur_user:
448 :param just_db:
426 :param just_db:
449 :param fork:
427 :param fork:
450 """
428 """
451 owner = cur_user
429 owner = cur_user
452 repo_name = form_data['repo_name_full']
430 repo_name = form_data['repo_name_full']
453 repo_type = form_data['repo_type']
431 repo_type = form_data['repo_type']
454 description = form_data['repo_description']
432 description = form_data['repo_description']
455 private = form_data['repo_private']
433 private = form_data['repo_private']
456 clone_uri = form_data.get('clone_uri')
434 clone_uri = form_data.get('clone_uri')
457 repos_group = form_data['repo_group']
435 repos_group = form_data['repo_group']
458 landing_rev = form_data['repo_landing_rev']
436 landing_rev = form_data['repo_landing_rev']
459 copy_fork_permissions = form_data.get('copy_permissions')
437 copy_fork_permissions = form_data.get('copy_permissions')
460 fork_of = form_data.get('fork_parent_id')
438 fork_of = form_data.get('fork_parent_id')
461
439
462 ## repo creation defaults, private and repo_type are filled in form
440 ## repo creation defaults, private and repo_type are filled in form
463 defs = RhodeCodeSetting.get_default_repo_settings(strip_prefix=True)
441 defs = RhodeCodeSetting.get_default_repo_settings(strip_prefix=True)
464 enable_statistics = defs.get('repo_enable_statistics')
442 enable_statistics = defs.get('repo_enable_statistics')
465 enable_locking = defs.get('repo_enable_locking')
443 enable_locking = defs.get('repo_enable_locking')
466 enable_downloads = defs.get('repo_enable_downloads')
444 enable_downloads = defs.get('repo_enable_downloads')
467
445
468 return self.create_repo(
446 return self.create_repo(
469 repo_name, repo_type, description, owner, private, clone_uri,
447 repo_name, repo_type, description, owner, private, clone_uri,
470 repos_group, landing_rev, just_db, fork_of, copy_fork_permissions,
448 repos_group, landing_rev, just_db, fork_of, copy_fork_permissions,
471 enable_statistics, enable_locking, enable_downloads
449 enable_statistics, enable_locking, enable_downloads
472 )
450 )
473
451
474 def create_fork(self, form_data, cur_user):
452 def create_fork(self, form_data, cur_user):
475 """
453 """
476 Simple wrapper into executing celery task for fork creation
454 Simple wrapper into executing celery task for fork creation
477
455
478 :param form_data:
456 :param form_data:
479 :param cur_user:
457 :param cur_user:
480 """
458 """
481 from rhodecode.lib.celerylib import tasks, run_task
459 from rhodecode.lib.celerylib import tasks, run_task
482 run_task(tasks.create_repo_fork, form_data, cur_user)
460 run_task(tasks.create_repo_fork, form_data, cur_user)
483
461
484 def delete(self, repo):
462 def delete(self, repo):
485 repo = self._get_repo(repo)
463 repo = self._get_repo(repo)
486 if repo:
464 if repo:
487 old_repo_dict = repo.get_dict()
465 old_repo_dict = repo.get_dict()
488 owner = repo.user
466 owner = repo.user
489 try:
467 try:
490 self.sa.delete(repo)
468 self.sa.delete(repo)
491 self.__delete_repo(repo)
469 self.__delete_repo(repo)
492 log_delete_repository(old_repo_dict,
470 log_delete_repository(old_repo_dict,
493 deleted_by=owner.username)
471 deleted_by=owner.username)
494 except:
472 except:
495 log.error(traceback.format_exc())
473 log.error(traceback.format_exc())
496 raise
474 raise
497
475
498 def grant_user_permission(self, repo, user, perm):
476 def grant_user_permission(self, repo, user, perm):
499 """
477 """
500 Grant permission for user on given repository, or update existing one
478 Grant permission for user on given repository, or update existing one
501 if found
479 if found
502
480
503 :param repo: Instance of Repository, repository_id, or repository name
481 :param repo: Instance of Repository, repository_id, or repository name
504 :param user: Instance of User, user_id or username
482 :param user: Instance of User, user_id or username
505 :param perm: Instance of Permission, or permission_name
483 :param perm: Instance of Permission, or permission_name
506 """
484 """
507 user = self._get_user(user)
485 user = self._get_user(user)
508 repo = self._get_repo(repo)
486 repo = self._get_repo(repo)
509 permission = self._get_perm(perm)
487 permission = self._get_perm(perm)
510
488
511 # check if we have that permission already
489 # check if we have that permission already
512 obj = self.sa.query(UserRepoToPerm)\
490 obj = self.sa.query(UserRepoToPerm)\
513 .filter(UserRepoToPerm.user == user)\
491 .filter(UserRepoToPerm.user == user)\
514 .filter(UserRepoToPerm.repository == repo)\
492 .filter(UserRepoToPerm.repository == repo)\
515 .scalar()
493 .scalar()
516 if obj is None:
494 if obj is None:
517 # create new !
495 # create new !
518 obj = UserRepoToPerm()
496 obj = UserRepoToPerm()
519 obj.repository = repo
497 obj.repository = repo
520 obj.user = user
498 obj.user = user
521 obj.permission = permission
499 obj.permission = permission
522 self.sa.add(obj)
500 self.sa.add(obj)
523 log.debug('Granted perm %s to %s on %s' % (perm, user, repo))
501 log.debug('Granted perm %s to %s on %s' % (perm, user, repo))
524
502
525 def revoke_user_permission(self, repo, user):
503 def revoke_user_permission(self, repo, user):
526 """
504 """
527 Revoke permission for user on given repository
505 Revoke permission for user on given repository
528
506
529 :param repo: Instance of Repository, repository_id, or repository name
507 :param repo: Instance of Repository, repository_id, or repository name
530 :param user: Instance of User, user_id or username
508 :param user: Instance of User, user_id or username
531 """
509 """
532
510
533 user = self._get_user(user)
511 user = self._get_user(user)
534 repo = self._get_repo(repo)
512 repo = self._get_repo(repo)
535
513
536 obj = self.sa.query(UserRepoToPerm)\
514 obj = self.sa.query(UserRepoToPerm)\
537 .filter(UserRepoToPerm.repository == repo)\
515 .filter(UserRepoToPerm.repository == repo)\
538 .filter(UserRepoToPerm.user == user)\
516 .filter(UserRepoToPerm.user == user)\
539 .scalar()
517 .scalar()
540 if obj:
518 if obj:
541 self.sa.delete(obj)
519 self.sa.delete(obj)
542 log.debug('Revoked perm on %s on %s' % (repo, user))
520 log.debug('Revoked perm on %s on %s' % (repo, user))
543
521
544 def grant_users_group_permission(self, repo, group_name, perm):
522 def grant_users_group_permission(self, repo, group_name, perm):
545 """
523 """
546 Grant permission for user group on given repository, or update
524 Grant permission for user group on given repository, or update
547 existing one if found
525 existing one if found
548
526
549 :param repo: Instance of Repository, repository_id, or repository name
527 :param repo: Instance of Repository, repository_id, or repository name
550 :param group_name: Instance of UserGroup, users_group_id,
528 :param group_name: Instance of UserGroup, users_group_id,
551 or user group name
529 or user group name
552 :param perm: Instance of Permission, or permission_name
530 :param perm: Instance of Permission, or permission_name
553 """
531 """
554 repo = self._get_repo(repo)
532 repo = self._get_repo(repo)
555 group_name = self.__get_users_group(group_name)
533 group_name = self.__get_users_group(group_name)
556 permission = self._get_perm(perm)
534 permission = self._get_perm(perm)
557
535
558 # check if we have that permission already
536 # check if we have that permission already
559 obj = self.sa.query(UserGroupRepoToPerm)\
537 obj = self.sa.query(UserGroupRepoToPerm)\
560 .filter(UserGroupRepoToPerm.users_group == group_name)\
538 .filter(UserGroupRepoToPerm.users_group == group_name)\
561 .filter(UserGroupRepoToPerm.repository == repo)\
539 .filter(UserGroupRepoToPerm.repository == repo)\
562 .scalar()
540 .scalar()
563
541
564 if obj is None:
542 if obj is None:
565 # create new
543 # create new
566 obj = UserGroupRepoToPerm()
544 obj = UserGroupRepoToPerm()
567
545
568 obj.repository = repo
546 obj.repository = repo
569 obj.users_group = group_name
547 obj.users_group = group_name
570 obj.permission = permission
548 obj.permission = permission
571 self.sa.add(obj)
549 self.sa.add(obj)
572 log.debug('Granted perm %s to %s on %s' % (perm, group_name, repo))
550 log.debug('Granted perm %s to %s on %s' % (perm, group_name, repo))
573
551
574 def revoke_users_group_permission(self, repo, group_name):
552 def revoke_users_group_permission(self, repo, group_name):
575 """
553 """
576 Revoke permission for user group on given repository
554 Revoke permission for user group on given repository
577
555
578 :param repo: Instance of Repository, repository_id, or repository name
556 :param repo: Instance of Repository, repository_id, or repository name
579 :param group_name: Instance of UserGroup, users_group_id,
557 :param group_name: Instance of UserGroup, users_group_id,
580 or user group name
558 or user group name
581 """
559 """
582 repo = self._get_repo(repo)
560 repo = self._get_repo(repo)
583 group_name = self.__get_users_group(group_name)
561 group_name = self.__get_users_group(group_name)
584
562
585 obj = self.sa.query(UserGroupRepoToPerm)\
563 obj = self.sa.query(UserGroupRepoToPerm)\
586 .filter(UserGroupRepoToPerm.repository == repo)\
564 .filter(UserGroupRepoToPerm.repository == repo)\
587 .filter(UserGroupRepoToPerm.users_group == group_name)\
565 .filter(UserGroupRepoToPerm.users_group == group_name)\
588 .scalar()
566 .scalar()
589 if obj:
567 if obj:
590 self.sa.delete(obj)
568 self.sa.delete(obj)
591 log.debug('Revoked perm to %s on %s' % (repo, group_name))
569 log.debug('Revoked perm to %s on %s' % (repo, group_name))
592
570
593 def delete_stats(self, repo_name):
571 def delete_stats(self, repo_name):
594 """
572 """
595 removes stats for given repo
573 removes stats for given repo
596
574
597 :param repo_name:
575 :param repo_name:
598 """
576 """
599 repo = self._get_repo(repo_name)
577 repo = self._get_repo(repo_name)
600 try:
578 try:
601 obj = self.sa.query(Statistics)\
579 obj = self.sa.query(Statistics)\
602 .filter(Statistics.repository == repo).scalar()
580 .filter(Statistics.repository == repo).scalar()
603 if obj:
581 if obj:
604 self.sa.delete(obj)
582 self.sa.delete(obj)
605 except:
583 except:
606 log.error(traceback.format_exc())
584 log.error(traceback.format_exc())
607 raise
585 raise
608
586
609 def __create_repo(self, repo_name, alias, parent, clone_uri=False):
587 def __create_repo(self, repo_name, alias, parent, clone_uri=False):
610 """
588 """
611 makes repository on filesystem. It's group aware means it'll create
589 makes repository on filesystem. It's group aware means it'll create
612 a repository within a group, and alter the paths accordingly of
590 a repository within a group, and alter the paths accordingly of
613 group location
591 group location
614
592
615 :param repo_name:
593 :param repo_name:
616 :param alias:
594 :param alias:
617 :param parent_id:
595 :param parent_id:
618 :param clone_uri:
596 :param clone_uri:
619 """
597 """
620 from rhodecode.lib.utils import is_valid_repo, is_valid_repos_group
598 from rhodecode.lib.utils import is_valid_repo, is_valid_repos_group
621 from rhodecode.model.scm import ScmModel
599 from rhodecode.model.scm import ScmModel
622
600
623 if parent:
601 if parent:
624 new_parent_path = os.sep.join(parent.full_path_splitted)
602 new_parent_path = os.sep.join(parent.full_path_splitted)
625 else:
603 else:
626 new_parent_path = ''
604 new_parent_path = ''
627
605
628 # we need to make it str for mercurial
606 # we need to make it str for mercurial
629 repo_path = os.path.join(*map(lambda x: safe_str(x),
607 repo_path = os.path.join(*map(lambda x: safe_str(x),
630 [self.repos_path, new_parent_path, repo_name]))
608 [self.repos_path, new_parent_path, repo_name]))
631
609
632 # check if this path is not a repository
610 # check if this path is not a repository
633 if is_valid_repo(repo_path, self.repos_path):
611 if is_valid_repo(repo_path, self.repos_path):
634 raise Exception('This path %s is a valid repository' % repo_path)
612 raise Exception('This path %s is a valid repository' % repo_path)
635
613
636 # check if this path is a group
614 # check if this path is a group
637 if is_valid_repos_group(repo_path, self.repos_path):
615 if is_valid_repos_group(repo_path, self.repos_path):
638 raise Exception('This path %s is a valid group' % repo_path)
616 raise Exception('This path %s is a valid group' % repo_path)
639
617
640 log.info('creating repo %s in %s @ %s' % (
618 log.info('creating repo %s in %s @ %s' % (
641 repo_name, safe_unicode(repo_path),
619 repo_name, safe_unicode(repo_path),
642 obfuscate_url_pw(clone_uri)
620 obfuscate_url_pw(clone_uri)
643 )
621 )
644 )
622 )
645 backend = get_backend(alias)
623 backend = get_backend(alias)
646 if alias == 'hg':
624 if alias == 'hg':
647 backend(repo_path, create=True, src_url=clone_uri)
625 backend(repo_path, create=True, src_url=clone_uri)
648 elif alias == 'git':
626 elif alias == 'git':
649 r = backend(repo_path, create=True, src_url=clone_uri, bare=True)
627 r = backend(repo_path, create=True, src_url=clone_uri, bare=True)
650 # add rhodecode hook into this repo
628 # add rhodecode hook into this repo
651 ScmModel().install_git_hook(repo=r)
629 ScmModel().install_git_hook(repo=r)
652 else:
630 else:
653 raise Exception('Undefined alias %s' % alias)
631 raise Exception('Undefined alias %s' % alias)
654
632
655 def __rename_repo(self, old, new):
633 def __rename_repo(self, old, new):
656 """
634 """
657 renames repository on filesystem
635 renames repository on filesystem
658
636
659 :param old: old name
637 :param old: old name
660 :param new: new name
638 :param new: new name
661 """
639 """
662 log.info('renaming repo from %s to %s' % (old, new))
640 log.info('renaming repo from %s to %s' % (old, new))
663
641
664 old_path = os.path.join(self.repos_path, old)
642 old_path = os.path.join(self.repos_path, old)
665 new_path = os.path.join(self.repos_path, new)
643 new_path = os.path.join(self.repos_path, new)
666 if os.path.isdir(new_path):
644 if os.path.isdir(new_path):
667 raise Exception(
645 raise Exception(
668 'Was trying to rename to already existing dir %s' % new_path
646 'Was trying to rename to already existing dir %s' % new_path
669 )
647 )
670 shutil.move(old_path, new_path)
648 shutil.move(old_path, new_path)
671
649
672 def __delete_repo(self, repo):
650 def __delete_repo(self, repo):
673 """
651 """
674 removes repo from filesystem, the removal is acctually made by
652 removes repo from filesystem, the removal is acctually made by
675 added rm__ prefix into dir, and rename internat .hg/.git dirs so this
653 added rm__ prefix into dir, and rename internat .hg/.git dirs so this
676 repository is no longer valid for rhodecode, can be undeleted later on
654 repository is no longer valid for rhodecode, can be undeleted later on
677 by reverting the renames on this repository
655 by reverting the renames on this repository
678
656
679 :param repo: repo object
657 :param repo: repo object
680 """
658 """
681 rm_path = os.path.join(self.repos_path, repo.repo_name)
659 rm_path = os.path.join(self.repos_path, repo.repo_name)
682 log.info("Removing %s" % (rm_path))
660 log.info("Removing %s" % (rm_path))
683 # disable hg/git internal that it doesn't get detected as repo
661 # disable hg/git internal that it doesn't get detected as repo
684 alias = repo.repo_type
662 alias = repo.repo_type
685
663
686 bare = getattr(repo.scm_instance, 'bare', False)
664 bare = getattr(repo.scm_instance, 'bare', False)
687
665
688 if not bare:
666 if not bare:
689 # skip this for bare git repos
667 # skip this for bare git repos
690 shutil.move(os.path.join(rm_path, '.%s' % alias),
668 shutil.move(os.path.join(rm_path, '.%s' % alias),
691 os.path.join(rm_path, 'rm__.%s' % alias))
669 os.path.join(rm_path, 'rm__.%s' % alias))
692 # disable repo
670 # disable repo
693 _now = datetime.now()
671 _now = datetime.now()
694 _ms = str(_now.microsecond).rjust(6, '0')
672 _ms = str(_now.microsecond).rjust(6, '0')
695 _d = 'rm__%s__%s' % (_now.strftime('%Y%m%d_%H%M%S_' + _ms),
673 _d = 'rm__%s__%s' % (_now.strftime('%Y%m%d_%H%M%S_' + _ms),
696 repo.just_name)
674 repo.just_name)
697 if repo.group:
675 if repo.group:
698 args = repo.group.full_path_splitted + [_d]
676 args = repo.group.full_path_splitted + [_d]
699 _d = os.path.join(*args)
677 _d = os.path.join(*args)
700 shutil.move(rm_path, os.path.join(self.repos_path, _d))
678 shutil.move(rm_path, os.path.join(self.repos_path, _d))
@@ -1,378 +1,394 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2 ##
2 ##
3 ## See also repo_settings.html
3 ## See also repo_settings.html
4 ##
4 ##
5 <%inherit file="/base/base.html"/>
5 <%inherit file="/base/base.html"/>
6
6
7 <%def name="title()">
7 <%def name="title()">
8 ${_('Edit repository')} ${c.repo_info.repo_name} &middot; ${c.rhodecode_name}
8 ${_('Edit repository')} ${c.repo_info.repo_name} &middot; ${c.rhodecode_name}
9 </%def>
9 </%def>
10
10
11 <%def name="breadcrumbs_links()">
11 <%def name="breadcrumbs_links()">
12 ${_('Settings')}
12 ${_('Settings')}
13 </%def>
13 </%def>
14
14
15 <%def name="page_nav()">
15 <%def name="page_nav()">
16 ${self.menu('admin')}
16 ${self.menu('admin')}
17 </%def>
17 </%def>
18
18
19 <%def name="main()">
19 <%def name="main()">
20 ${self.context_bar('options')}
20 ${self.context_bar('options')}
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 ${h.form(url('repo', repo_name=c.repo_info.repo_name),method='put')}
26 ${h.form(url('repo', repo_name=c.repo_info.repo_name),method='put')}
27 <div class="form">
27 <div class="form">
28 <!-- fields -->
28 <!-- fields -->
29 <div class="fields">
29 <div class="fields">
30 <div class="field">
30 <div class="field">
31 <div class="label">
31 <div class="label">
32 <label for="repo_name">${_('Name')}:</label>
32 <label for="repo_name">${_('Name')}:</label>
33 </div>
33 </div>
34 <div class="input">
34 <div class="input">
35 ${h.text('repo_name',class_="medium")}
35 ${h.text('repo_name',class_="medium")}
36 </div>
36 </div>
37 </div>
37 </div>
38 <div class="field">
38 <div class="field">
39 <div class="label">
39 <div class="label">
40 <label for="clone_uri">${_('Clone uri')}:</label>
40 <label for="clone_uri">${_('Clone uri')}:</label>
41 </div>
41 </div>
42 <div class="input">
42 <div class="input">
43 ${h.text('clone_uri',class_="medium")}
43 ${h.text('clone_uri',class_="medium")}
44 <span class="help-block">${_('Optional http[s] url from which repository should be cloned.')}</span>
44 <span class="help-block">${_('Optional http[s] url from which repository should be cloned.')}</span>
45 </div>
45 </div>
46 </div>
46 </div>
47 <div class="field">
47 <div class="field">
48 <div class="label">
48 <div class="label">
49 <label for="repo_group">${_('Repository group')}:</label>
49 <label for="repo_group">${_('Repository group')}:</label>
50 </div>
50 </div>
51 <div class="input">
51 <div class="input">
52 ${h.select('repo_group','',c.repo_groups,class_="medium")}
52 ${h.select('repo_group','',c.repo_groups,class_="medium")}
53 <span class="help-block">${_('Optional select a group to put this repository into.')}</span>
53 <span class="help-block">${_('Optional select a group to put this repository into.')}</span>
54 </div>
54 </div>
55 </div>
55 </div>
56 <div class="field">
56 <div class="field">
57 <div class="label">
57 <div class="label">
58 <label for="repo_type">${_('Type')}:</label>
58 <label for="repo_type">${_('Type')}:</label>
59 </div>
59 </div>
60 <div class="input">
60 <div class="input">
61 ${h.select('repo_type','hg',c.backends,class_="medium")}
61 ${h.select('repo_type','hg',c.backends,class_="medium")}
62 </div>
62 </div>
63 </div>
63 </div>
64 <div class="field">
64 <div class="field">
65 <div class="label">
65 <div class="label">
66 <label for="repo_landing_rev">${_('Landing revision')}:</label>
66 <label for="repo_landing_rev">${_('Landing revision')}:</label>
67 </div>
67 </div>
68 <div class="input">
68 <div class="input">
69 ${h.select('repo_landing_rev','',c.landing_revs,class_="medium")}
69 ${h.select('repo_landing_rev','',c.landing_revs,class_="medium")}
70 <span class="help-block">${_('Default revision for files page, downloads, whoosh and readme')}</span>
70 <span class="help-block">${_('Default revision for files page, downloads, whoosh and readme')}</span>
71 </div>
71 </div>
72 </div>
72 </div>
73 <div class="field">
73 <div class="field">
74 <div class="label label-textarea">
74 <div class="label label-textarea">
75 <label for="repo_description">${_('Description')}:</label>
75 <label for="repo_description">${_('Description')}:</label>
76 </div>
76 </div>
77 <div class="textarea text-area editor">
77 <div class="textarea text-area editor">
78 ${h.textarea('repo_description')}
78 ${h.textarea('repo_description')}
79 <span class="help-block">${_('Keep it short and to the point. Use a README file for longer descriptions.')}</span>
79 <span class="help-block">${_('Keep it short and to the point. Use a README file for longer descriptions.')}</span>
80 </div>
80 </div>
81 </div>
81 </div>
82
82
83 <div class="field">
83 <div class="field">
84 <div class="label label-checkbox">
84 <div class="label label-checkbox">
85 <label for="repo_private">${_('Private repository')}:</label>
85 <label for="repo_private">${_('Private repository')}:</label>
86 </div>
86 </div>
87 <div class="checkboxes">
87 <div class="checkboxes">
88 ${h.checkbox('repo_private',value="True")}
88 ${h.checkbox('repo_private',value="True")}
89 <span class="help-block">${_('Private repositories are only visible to people explicitly added as collaborators.')}</span>
89 <span class="help-block">${_('Private repositories are only visible to people explicitly added as collaborators.')}</span>
90 </div>
90 </div>
91 </div>
91 </div>
92 <div class="field">
92 <div class="field">
93 <div class="label label-checkbox">
93 <div class="label label-checkbox">
94 <label for="repo_enable_statistics">${_('Enable statistics')}:</label>
94 <label for="repo_enable_statistics">${_('Enable statistics')}:</label>
95 </div>
95 </div>
96 <div class="checkboxes">
96 <div class="checkboxes">
97 ${h.checkbox('repo_enable_statistics',value="True")}
97 ${h.checkbox('repo_enable_statistics',value="True")}
98 <span class="help-block">${_('Enable statistics window on summary page.')}</span>
98 <span class="help-block">${_('Enable statistics window on summary page.')}</span>
99 </div>
99 </div>
100 </div>
100 </div>
101 <div class="field">
101 <div class="field">
102 <div class="label label-checkbox">
102 <div class="label label-checkbox">
103 <label for="repo_enable_downloads">${_('Enable downloads')}:</label>
103 <label for="repo_enable_downloads">${_('Enable downloads')}:</label>
104 </div>
104 </div>
105 <div class="checkboxes">
105 <div class="checkboxes">
106 ${h.checkbox('repo_enable_downloads',value="True")}
106 ${h.checkbox('repo_enable_downloads',value="True")}
107 <span class="help-block">${_('Enable download menu on summary page.')}</span>
107 <span class="help-block">${_('Enable download menu on summary page.')}</span>
108 </div>
108 </div>
109 </div>
109 </div>
110 <div class="field">
110 <div class="field">
111 <div class="label label-checkbox">
111 <div class="label label-checkbox">
112 <label for="repo_enable_locking">${_('Enable locking')}:</label>
112 <label for="repo_enable_locking">${_('Enable locking')}:</label>
113 </div>
113 </div>
114 <div class="checkboxes">
114 <div class="checkboxes">
115 ${h.checkbox('repo_enable_locking',value="True")}
115 ${h.checkbox('repo_enable_locking',value="True")}
116 <span class="help-block">${_('Enable lock-by-pulling on repository.')}</span>
116 <span class="help-block">${_('Enable lock-by-pulling on repository.')}</span>
117 </div>
117 </div>
118 </div>
118 </div>
119 <div class="field">
119 <div class="field">
120 <div class="label">
120 <div class="label">
121 <label for="user">${_('Owner')}:</label>
121 <label for="user">${_('Owner')}:</label>
122 </div>
122 </div>
123 <div class="input input-medium ac">
123 <div class="input input-medium ac">
124 <div class="perm_ac">
124 <div class="perm_ac">
125 ${h.text('user',class_='yui-ac-input')}
125 ${h.text('user',class_='yui-ac-input')}
126 <span class="help-block">${_('Change owner of this repository.')}</span>
126 <span class="help-block">${_('Change owner of this repository.')}</span>
127 <div id="owner_container"></div>
127 <div id="owner_container"></div>
128 </div>
128 </div>
129 </div>
129 </div>
130 </div>
130 </div>
131 %if c.visual.repository_fields:
131 %if c.visual.repository_fields:
132 ## EXTRA FIELDS
132 ## EXTRA FIELDS
133 %for field in c.repo_fields:
133 %for field in c.repo_fields:
134 <div class="field">
134 <div class="field">
135 <div class="label">
135 <div class="label">
136 <label for="${field.field_key_prefixed}">${field.field_label} (${field.field_key}):</label>
136 <label for="${field.field_key_prefixed}">${field.field_label} (${field.field_key}):</label>
137 </div>
137 </div>
138 <div class="input input-medium">
138 <div class="input input-medium">
139 ${h.text(field.field_key_prefixed, field.field_value, class_='medium')}
139 ${h.text(field.field_key_prefixed, field.field_value, class_='medium')}
140 %if field.field_desc:
140 %if field.field_desc:
141 <span class="help-block">${field.field_desc}</span>
141 <span class="help-block">${field.field_desc}</span>
142 %endif
142 %endif
143 </div>
143 </div>
144 </div>
144 </div>
145 %endfor
145 %endfor
146 %endif
146 %endif
147 <div class="field">
148 <div class="label">
149 <label for="input">${_('Permissions')}:</label>
150 </div>
151 <div class="input">
152 <%include file="repo_edit_perms.html"/>
153 </div>
154 </div>
155
156 <div class="buttons">
147 <div class="buttons">
157 ${h.submit('save',_('Save'),class_="ui-btn large")}
148 ${h.submit('save',_('Save'),class_="ui-btn large")}
158 ${h.reset('reset',_('Reset'),class_="ui-btn large")}
149 ${h.reset('reset',_('Reset'),class_="ui-btn large")}
159 </div>
150 </div>
160 </div>
151 </div>
161 </div>
152 </div>
162 ${h.end_form()}
153 ${h.end_form()}
163 </div>
154 </div>
164
155
165 <div class="box box-right">
156 <div class="box box-right">
166 <div class="title">
157 <div class="title">
158 <h5>${_('Permissions')}</h5>
159 </div>
160 ${h.form(url('set_repo_perm_member', repo_name=c.repo_info.repo_name),method='post')}
161 <div class="form">
162 <div class="fields">
163 <div class="field">
164 <div class="label">
165 <label for="input">${_('Permissions')}:</label>
166 </div>
167 <div class="input">
168 <%include file="repo_edit_perms.html"/>
169 </div>
170 </div>
171 <div class="buttons">
172 ${h.submit('save',_('Save'),class_="ui-btn large")}
173 ${h.reset('reset',_('Reset'),class_="ui-btn large")}
174 </div>
175 </div>
176 </div>
177 ${h.end_form()}
178 </div>
179
180
181 <div class="box box-right" style="clear:right">
182 <div class="title">
167 <h5>${_('Advanced settings')}</h5>
183 <h5>${_('Advanced settings')}</h5>
168 </div>
184 </div>
169
185
170 <h3>${_('Statistics')}</h3>
186 <h3>${_('Statistics')}</h3>
171 ${h.form(url('repo_stats', repo_name=c.repo_info.repo_name),method='delete')}
187 ${h.form(url('repo_stats', repo_name=c.repo_info.repo_name),method='delete')}
172 <div class="form">
188 <div class="form">
173 <div class="fields">
189 <div class="fields">
174 ${h.submit('reset_stats_%s' % c.repo_info.repo_name,_('Reset current statistics'),class_="ui-btn",onclick="return confirm('"+_('Confirm to remove current statistics')+"');")}
190 ${h.submit('reset_stats_%s' % c.repo_info.repo_name,_('Reset current statistics'),class_="ui-btn",onclick="return confirm('"+_('Confirm to remove current statistics')+"');")}
175 <div class="field" style="border:none;color:#888">
191 <div class="field" style="border:none;color:#888">
176 <ul>
192 <ul>
177 <li>${_('Fetched to rev')}: ${c.stats_revision}/${c.repo_last_rev}</li>
193 <li>${_('Fetched to rev')}: ${c.stats_revision}/${c.repo_last_rev}</li>
178 <li>${_('Stats gathered')}: ${c.stats_percentage}%</li>
194 <li>${_('Stats gathered')}: ${c.stats_percentage}%</li>
179 </ul>
195 </ul>
180 </div>
196 </div>
181 </div>
197 </div>
182 </div>
198 </div>
183 ${h.end_form()}
199 ${h.end_form()}
184
200
185 %if c.repo_info.clone_uri:
201 %if c.repo_info.clone_uri:
186 <h3>${_('Remote')}</h3>
202 <h3>${_('Remote')}</h3>
187 ${h.form(url('repo_pull', repo_name=c.repo_info.repo_name),method='put')}
203 ${h.form(url('repo_pull', repo_name=c.repo_info.repo_name),method='put')}
188 <div class="form">
204 <div class="form">
189 <div class="fields">
205 <div class="fields">
190 ${h.submit('remote_pull_%s' % c.repo_info.repo_name,_('Pull changes from remote location'),class_="ui-btn",onclick="return confirm('"+_('Confirm to pull changes from remote side')+"');")}
206 ${h.submit('remote_pull_%s' % c.repo_info.repo_name,_('Pull changes from remote location'),class_="ui-btn",onclick="return confirm('"+_('Confirm to pull changes from remote side')+"');")}
191 <div class="field" style="border:none">
207 <div class="field" style="border:none">
192 <ul>
208 <ul>
193 <li><a href="${c.repo_info.clone_uri}">${c.repo_info.clone_uri}</a></li>
209 <li><a href="${c.repo_info.clone_uri}">${c.repo_info.clone_uri}</a></li>
194 </ul>
210 </ul>
195 </div>
211 </div>
196 </div>
212 </div>
197 </div>
213 </div>
198 ${h.end_form()}
214 ${h.end_form()}
199 %endif
215 %endif
200
216
201 <h3>${_('Cache')}</h3>
217 <h3>${_('Cache')}</h3>
202 ${h.form(url('repo_cache', repo_name=c.repo_info.repo_name),method='delete')}
218 ${h.form(url('repo_cache', repo_name=c.repo_info.repo_name),method='delete')}
203 <div class="form">
219 <div class="form">
204 <div class="fields">
220 <div class="fields">
205 ${h.submit('reset_cache_%s' % c.repo_info.repo_name,_('Invalidate repository cache'),class_="ui-btn",onclick="return confirm('"+_('Confirm to invalidate repository cache')+"');")}
221 ${h.submit('reset_cache_%s' % c.repo_info.repo_name,_('Invalidate repository cache'),class_="ui-btn",onclick="return confirm('"+_('Confirm to invalidate repository cache')+"');")}
206 <div class="field" style="border:none;color:#888">
222 <div class="field" style="border:none;color:#888">
207 <ul>
223 <ul>
208 <li>${_('Manually invalidate cache for this repository. On first access repository will be cached again')}
224 <li>${_('Manually invalidate cache for this repository. On first access repository will be cached again')}
209 </li>
225 </li>
210 </ul>
226 </ul>
211 </div>
227 </div>
212 <div class="field" style="border:none;">
228 <div class="field" style="border:none;">
213 ${_('List of cached values')}
229 ${_('List of cached values')}
214 <table>
230 <table>
215 <tr>
231 <tr>
216 <th>${_('Prefix')}</th>
232 <th>${_('Prefix')}</th>
217 <th>${_('Key')}</th>
233 <th>${_('Key')}</th>
218 <th>${_('Active')}</th>
234 <th>${_('Active')}</th>
219 </tr>
235 </tr>
220 %for cache in c.repo_info.cache_keys:
236 %for cache in c.repo_info.cache_keys:
221 <tr>
237 <tr>
222 <td>${cache.get_prefix() or '-'}</td>
238 <td>${cache.get_prefix() or '-'}</td>
223 <td>${cache.cache_key}</td>
239 <td>${cache.cache_key}</td>
224 <td>${h.boolicon(cache.cache_active)}</td>
240 <td>${h.boolicon(cache.cache_active)}</td>
225 </tr>
241 </tr>
226 %endfor
242 %endfor
227 </table>
243 </table>
228 </div>
244 </div>
229 </div>
245 </div>
230 </div>
246 </div>
231 ${h.end_form()}
247 ${h.end_form()}
232
248
233 <h3>${_('Public journal')}</h3>
249 <h3>${_('Public journal')}</h3>
234 ${h.form(url('repo_public_journal', repo_name=c.repo_info.repo_name),method='put')}
250 ${h.form(url('repo_public_journal', repo_name=c.repo_info.repo_name),method='put')}
235 <div class="form">
251 <div class="form">
236 ${h.hidden('auth_token',str(h.get_token()))}
252 ${h.hidden('auth_token',str(h.get_token()))}
237 <div class="field">
253 <div class="field">
238 %if c.in_public_journal:
254 %if c.in_public_journal:
239 ${h.submit('set_public_%s' % c.repo_info.repo_name,_('Remove from public journal'),class_="ui-btn")}
255 ${h.submit('set_public_%s' % c.repo_info.repo_name,_('Remove from public journal'),class_="ui-btn")}
240 %else:
256 %else:
241 ${h.submit('set_public_%s' % c.repo_info.repo_name,_('Add to public journal'),class_="ui-btn")}
257 ${h.submit('set_public_%s' % c.repo_info.repo_name,_('Add to public journal'),class_="ui-btn")}
242 %endif
258 %endif
243 </div>
259 </div>
244 <div class="field" style="border:none;color:#888">
260 <div class="field" style="border:none;color:#888">
245 <ul>
261 <ul>
246 <li>${_('All actions made on this repository will be accessible to everyone in public journal')}
262 <li>${_('All actions made on this repository will be accessible to everyone in public journal')}
247 </li>
263 </li>
248 </ul>
264 </ul>
249 </div>
265 </div>
250 </div>
266 </div>
251 ${h.end_form()}
267 ${h.end_form()}
252
268
253 <h3>${_('Locking')}</h3>
269 <h3>${_('Locking')}</h3>
254 ${h.form(url('repo_locking', repo_name=c.repo_info.repo_name),method='put')}
270 ${h.form(url('repo_locking', repo_name=c.repo_info.repo_name),method='put')}
255 <div class="form">
271 <div class="form">
256 <div class="fields">
272 <div class="fields">
257 %if c.repo_info.locked[0]:
273 %if c.repo_info.locked[0]:
258 ${h.submit('set_unlock' ,_('Unlock locked repo'),class_="ui-btn",onclick="return confirm('"+_('Confirm to unlock repository')+"');")}
274 ${h.submit('set_unlock' ,_('Unlock locked repo'),class_="ui-btn",onclick="return confirm('"+_('Confirm to unlock repository')+"');")}
259 ${'Locked by %s on %s' % (h.person_by_id(c.repo_info.locked[0]),h.fmt_date(h.time_to_datetime(c.repo_info.locked[1])))}
275 ${'Locked by %s on %s' % (h.person_by_id(c.repo_info.locked[0]),h.fmt_date(h.time_to_datetime(c.repo_info.locked[1])))}
260 %else:
276 %else:
261 ${h.submit('set_lock',_('lock repo'),class_="ui-btn",onclick="return confirm('"+_('Confirm to lock repository')+"');")}
277 ${h.submit('set_lock',_('lock repo'),class_="ui-btn",onclick="return confirm('"+_('Confirm to lock repository')+"');")}
262 ${_('Repository is not locked')}
278 ${_('Repository is not locked')}
263 %endif
279 %endif
264 </div>
280 </div>
265 <div class="field" style="border:none;color:#888">
281 <div class="field" style="border:none;color:#888">
266 <ul>
282 <ul>
267 <li>${_('Force locking on repository. Works only when anonymous access is disabled')}
283 <li>${_('Force locking on repository. Works only when anonymous access is disabled')}
268 </li>
284 </li>
269 </ul>
285 </ul>
270 </div>
286 </div>
271 </div>
287 </div>
272 ${h.end_form()}
288 ${h.end_form()}
273
289
274 <h3>${_('Set as fork of')}</h3>
290 <h3>${_('Set as fork of')}</h3>
275 ${h.form(url('repo_as_fork', repo_name=c.repo_info.repo_name),method='put')}
291 ${h.form(url('repo_as_fork', repo_name=c.repo_info.repo_name),method='put')}
276 <div class="form">
292 <div class="form">
277 <div class="fields">
293 <div class="fields">
278 ${h.select('id_fork_of','',c.repos_list,class_="medium")}
294 ${h.select('id_fork_of','',c.repos_list,class_="medium")}
279 ${h.submit('set_as_fork_%s' % c.repo_info.repo_name,_('set'),class_="ui-btn",)}
295 ${h.submit('set_as_fork_%s' % c.repo_info.repo_name,_('set'),class_="ui-btn",)}
280 </div>
296 </div>
281 <div class="field" style="border:none;color:#888">
297 <div class="field" style="border:none;color:#888">
282 <ul>
298 <ul>
283 <li>${_('''Manually set this repository as a fork of another from the list''')}</li>
299 <li>${_('''Manually set this repository as a fork of another from the list''')}</li>
284 </ul>
300 </ul>
285 </div>
301 </div>
286 </div>
302 </div>
287 ${h.end_form()}
303 ${h.end_form()}
288
304
289 <h3>${_('Delete')}</h3>
305 <h3>${_('Delete')}</h3>
290 ${h.form(url('repo', repo_name=c.repo_info.repo_name),method='delete')}
306 ${h.form(url('repo', repo_name=c.repo_info.repo_name),method='delete')}
291 <div class="form">
307 <div class="form">
292 <div class="fields">
308 <div class="fields">
293 <div class="field" style="border:none;color:#888">
309 <div class="field" style="border:none;color:#888">
294 ## <div class="label">
310 ## <div class="label">
295 ## <label for="">${_('Remove repository')}:</label>
311 ## <label for="">${_('Remove repository')}:</label>
296 ## </div>
312 ## </div>
297 <div class="checkboxes">
313 <div class="checkboxes">
298 ${h.submit('remove_%s' % c.repo_info.repo_name,_('Remove this repository'),class_="ui-btn red",onclick="return confirm('"+_('Confirm to delete this repository')+"');")}
314 ${h.submit('remove_%s' % c.repo_info.repo_name,_('Remove this repository'),class_="ui-btn red",onclick="return confirm('"+_('Confirm to delete this repository')+"');")}
299 %if c.repo_info.forks.count():
315 %if c.repo_info.forks.count():
300 - ${ungettext('this repository has %s fork', 'this repository has %s forks', c.repo_info.forks.count()) % c.repo_info.forks.count()}
316 - ${ungettext('this repository has %s fork', 'this repository has %s forks', c.repo_info.forks.count()) % c.repo_info.forks.count()}
301 <input type="radio" name="forks" value="detach_forks" checked="checked"/> <label for="forks">${_('Detach forks')}</label>
317 <input type="radio" name="forks" value="detach_forks" checked="checked"/> <label for="forks">${_('Detach forks')}</label>
302 <input type="radio" name="forks" value="delete_forks" /> <label for="forks">${_('Delete forks')}</label>
318 <input type="radio" name="forks" value="delete_forks" /> <label for="forks">${_('Delete forks')}</label>
303 %endif
319 %endif
304 <ul>
320 <ul>
305 <li>${_('This repository will be renamed in a special way in order to be unaccesible for RhodeCode and VCS systems. If you need to fully delete it from file system please do it manually')}</li>
321 <li>${_('This repository will be renamed in a special way in order to be unaccesible for RhodeCode and VCS systems. If you need to fully delete it from file system please do it manually')}</li>
306 </ul>
322 </ul>
307 </div>
323 </div>
308 </div>
324 </div>
309 </div>
325 </div>
310 </div>
326 </div>
311 ${h.end_form()}
327 ${h.end_form()}
312 </div>
328 </div>
313
329
314 ##TODO: this should be controlled by the VISUAL setting
330 ##TODO: this should be controlled by the VISUAL setting
315 %if c.visual.repository_fields:
331 %if c.visual.repository_fields:
316 <div class="box box-left" style="clear:left">
332 <div class="box box-left" style="clear:left">
317 <!-- box / title -->
333 <!-- box / title -->
318 <div class="title">
334 <div class="title">
319 <h5>${_('Extra fields')}</h5>
335 <h5>${_('Extra fields')}</h5>
320 </div>
336 </div>
321
337
322 <div class="emails_wrap">
338 <div class="emails_wrap">
323 <table class="noborder">
339 <table class="noborder">
324 %for field in c.repo_fields:
340 %for field in c.repo_fields:
325 <tr>
341 <tr>
326 <td>${field.field_label} (${field.field_key})</td>
342 <td>${field.field_label} (${field.field_key})</td>
327 <td>${field.field_type}</td>
343 <td>${field.field_type}</td>
328 <td>
344 <td>
329 ${h.form(url('delete_repo_fields', repo_name=c.repo_info.repo_name, field_id=field.repo_field_id),method='delete')}
345 ${h.form(url('delete_repo_fields', repo_name=c.repo_info.repo_name, field_id=field.repo_field_id),method='delete')}
330 ${h.submit('remove_%s' % field.repo_field_id, _('delete'), id="remove_field_%s" % field.repo_field_id,
346 ${h.submit('remove_%s' % field.repo_field_id, _('delete'), id="remove_field_%s" % field.repo_field_id,
331 class_="delete_icon action_button", onclick="return confirm('"+_('Confirm to delete this field: %s') % field.field_key+"');")}
347 class_="delete_icon action_button", onclick="return confirm('"+_('Confirm to delete this field: %s') % field.field_key+"');")}
332 ${h.end_form()}
348 ${h.end_form()}
333 </td>
349 </td>
334 </tr>
350 </tr>
335 %endfor
351 %endfor
336 </table>
352 </table>
337 </div>
353 </div>
338
354
339 ${h.form(url('create_repo_fields', repo_name=c.repo_info.repo_name),method='put')}
355 ${h.form(url('create_repo_fields', repo_name=c.repo_info.repo_name),method='put')}
340 <div class="form">
356 <div class="form">
341 <!-- fields -->
357 <!-- fields -->
342 <div class="fields">
358 <div class="fields">
343 <div class="field">
359 <div class="field">
344 <div class="label">
360 <div class="label">
345 <label for="new_field_key">${_('New field key')}:</label>
361 <label for="new_field_key">${_('New field key')}:</label>
346 </div>
362 </div>
347 <div class="input">
363 <div class="input">
348 ${h.text('new_field_key', class_='small')}
364 ${h.text('new_field_key', class_='small')}
349 </div>
365 </div>
350 </div>
366 </div>
351 <div class="field">
367 <div class="field">
352 <div class="label">
368 <div class="label">
353 <label for="new_field_label">${_('New field label')}:</label>
369 <label for="new_field_label">${_('New field label')}:</label>
354 </div>
370 </div>
355 <div class="input">
371 <div class="input">
356 ${h.text('new_field_label', class_='small', placeholder=_('Enter short label'))}
372 ${h.text('new_field_label', class_='small', placeholder=_('Enter short label'))}
357 </div>
373 </div>
358 </div>
374 </div>
359
375
360 <div class="field">
376 <div class="field">
361 <div class="label">
377 <div class="label">
362 <label for="new_field_desc">${_('New field description')}:</label>
378 <label for="new_field_desc">${_('New field description')}:</label>
363 </div>
379 </div>
364 <div class="input">
380 <div class="input">
365 ${h.text('new_field_desc', class_='small', placeholder=_('Enter description of a field'))}
381 ${h.text('new_field_desc', class_='small', placeholder=_('Enter description of a field'))}
366 </div>
382 </div>
367 </div>
383 </div>
368
384
369 <div class="buttons">
385 <div class="buttons">
370 ${h.submit('save',_('Add'),class_="ui-btn large")}
386 ${h.submit('save',_('Add'),class_="ui-btn large")}
371 ${h.reset('reset',_('Reset'),class_="ui-btn large")}
387 ${h.reset('reset',_('Reset'),class_="ui-btn large")}
372 </div>
388 </div>
373 </div>
389 </div>
374 </div>
390 </div>
375 ${h.end_form()}
391 ${h.end_form()}
376 </div>
392 </div>
377 %endif
393 %endif
378 </%def>
394 </%def>
General Comments 0
You need to be logged in to leave comments. Login now