##// END OF EJS Templates
Authors of pull-requests can now delete them
marcink -
r2746:49a4864b beta
parent child Browse files
Show More
@@ -1,575 +1,580
1 """
1 """
2 Routes configuration
2 Routes configuration
3
3
4 The more specific and detailed routes should be defined first so they
4 The more specific and detailed routes should be defined first so they
5 may take precedent over the more generic routes. For more information
5 may take precedent over the more generic routes. For more information
6 refer to the routes manual at http://routes.groovie.org/docs/
6 refer to the routes manual at http://routes.groovie.org/docs/
7 """
7 """
8 from __future__ import with_statement
8 from __future__ import with_statement
9 from routes import Mapper
9 from routes import Mapper
10
10
11 # prefix for non repository related links needs to be prefixed with `/`
11 # prefix for non repository related links needs to be prefixed with `/`
12 ADMIN_PREFIX = '/_admin'
12 ADMIN_PREFIX = '/_admin'
13
13
14
14
15 def make_map(config):
15 def make_map(config):
16 """Create, configure and return the routes Mapper"""
16 """Create, configure and return the routes Mapper"""
17 rmap = Mapper(directory=config['pylons.paths']['controllers'],
17 rmap = Mapper(directory=config['pylons.paths']['controllers'],
18 always_scan=config['debug'])
18 always_scan=config['debug'])
19 rmap.minimization = False
19 rmap.minimization = False
20 rmap.explicit = False
20 rmap.explicit = False
21
21
22 from rhodecode.lib.utils import is_valid_repo
22 from rhodecode.lib.utils import is_valid_repo
23 from rhodecode.lib.utils import is_valid_repos_group
23 from rhodecode.lib.utils import is_valid_repos_group
24
24
25 def check_repo(environ, match_dict):
25 def check_repo(environ, match_dict):
26 """
26 """
27 check for valid repository for proper 404 handling
27 check for valid repository for proper 404 handling
28
28
29 :param environ:
29 :param environ:
30 :param match_dict:
30 :param match_dict:
31 """
31 """
32 from rhodecode.model.db import Repository
32 from rhodecode.model.db import Repository
33 repo_name = match_dict.get('repo_name')
33 repo_name = match_dict.get('repo_name')
34
34
35 try:
35 try:
36 by_id = repo_name.split('_')
36 by_id = repo_name.split('_')
37 if len(by_id) == 2 and by_id[1].isdigit():
37 if len(by_id) == 2 and by_id[1].isdigit():
38 repo_name = Repository.get(by_id[1]).repo_name
38 repo_name = Repository.get(by_id[1]).repo_name
39 match_dict['repo_name'] = repo_name
39 match_dict['repo_name'] = repo_name
40 except:
40 except:
41 pass
41 pass
42
42
43 return is_valid_repo(repo_name, config['base_path'])
43 return is_valid_repo(repo_name, config['base_path'])
44
44
45 def check_group(environ, match_dict):
45 def check_group(environ, match_dict):
46 """
46 """
47 check for valid repositories group for proper 404 handling
47 check for valid repositories group for proper 404 handling
48
48
49 :param environ:
49 :param environ:
50 :param match_dict:
50 :param match_dict:
51 """
51 """
52 repos_group_name = match_dict.get('group_name')
52 repos_group_name = match_dict.get('group_name')
53
53
54 return is_valid_repos_group(repos_group_name, config['base_path'])
54 return is_valid_repos_group(repos_group_name, config['base_path'])
55
55
56 def check_int(environ, match_dict):
56 def check_int(environ, match_dict):
57 return match_dict.get('id').isdigit()
57 return match_dict.get('id').isdigit()
58
58
59 # The ErrorController route (handles 404/500 error pages); it should
59 # The ErrorController route (handles 404/500 error pages); it should
60 # likely stay at the top, ensuring it can always be resolved
60 # likely stay at the top, ensuring it can always be resolved
61 rmap.connect('/error/{action}', controller='error')
61 rmap.connect('/error/{action}', controller='error')
62 rmap.connect('/error/{action}/{id}', controller='error')
62 rmap.connect('/error/{action}/{id}', controller='error')
63
63
64 #==========================================================================
64 #==========================================================================
65 # CUSTOM ROUTES HERE
65 # CUSTOM ROUTES HERE
66 #==========================================================================
66 #==========================================================================
67
67
68 #MAIN PAGE
68 #MAIN PAGE
69 rmap.connect('home', '/', controller='home', action='index')
69 rmap.connect('home', '/', controller='home', action='index')
70 rmap.connect('repo_switcher', '/repos', controller='home',
70 rmap.connect('repo_switcher', '/repos', controller='home',
71 action='repo_switcher')
71 action='repo_switcher')
72 rmap.connect('branch_tag_switcher', '/branches-tags/{repo_name:.*?}',
72 rmap.connect('branch_tag_switcher', '/branches-tags/{repo_name:.*?}',
73 controller='home', action='branch_tag_switcher')
73 controller='home', action='branch_tag_switcher')
74 rmap.connect('bugtracker',
74 rmap.connect('bugtracker',
75 "http://bitbucket.org/marcinkuzminski/rhodecode/issues",
75 "http://bitbucket.org/marcinkuzminski/rhodecode/issues",
76 _static=True)
76 _static=True)
77 rmap.connect('rst_help',
77 rmap.connect('rst_help',
78 "http://docutils.sourceforge.net/docs/user/rst/quickref.html",
78 "http://docutils.sourceforge.net/docs/user/rst/quickref.html",
79 _static=True)
79 _static=True)
80 rmap.connect('rhodecode_official', "http://rhodecode.org", _static=True)
80 rmap.connect('rhodecode_official', "http://rhodecode.org", _static=True)
81
81
82 #ADMIN REPOSITORY REST ROUTES
82 #ADMIN REPOSITORY REST ROUTES
83 with rmap.submapper(path_prefix=ADMIN_PREFIX,
83 with rmap.submapper(path_prefix=ADMIN_PREFIX,
84 controller='admin/repos') as m:
84 controller='admin/repos') as m:
85 m.connect("repos", "/repos",
85 m.connect("repos", "/repos",
86 action="create", conditions=dict(method=["POST"]))
86 action="create", conditions=dict(method=["POST"]))
87 m.connect("repos", "/repos",
87 m.connect("repos", "/repos",
88 action="index", conditions=dict(method=["GET"]))
88 action="index", conditions=dict(method=["GET"]))
89 m.connect("formatted_repos", "/repos.{format}",
89 m.connect("formatted_repos", "/repos.{format}",
90 action="index",
90 action="index",
91 conditions=dict(method=["GET"]))
91 conditions=dict(method=["GET"]))
92 m.connect("new_repo", "/repos/new",
92 m.connect("new_repo", "/repos/new",
93 action="new", conditions=dict(method=["GET"]))
93 action="new", conditions=dict(method=["GET"]))
94 m.connect("formatted_new_repo", "/repos/new.{format}",
94 m.connect("formatted_new_repo", "/repos/new.{format}",
95 action="new", conditions=dict(method=["GET"]))
95 action="new", conditions=dict(method=["GET"]))
96 m.connect("/repos/{repo_name:.*?}",
96 m.connect("/repos/{repo_name:.*?}",
97 action="update", conditions=dict(method=["PUT"],
97 action="update", conditions=dict(method=["PUT"],
98 function=check_repo))
98 function=check_repo))
99 m.connect("/repos/{repo_name:.*?}",
99 m.connect("/repos/{repo_name:.*?}",
100 action="delete", conditions=dict(method=["DELETE"],
100 action="delete", conditions=dict(method=["DELETE"],
101 function=check_repo))
101 function=check_repo))
102 m.connect("edit_repo", "/repos/{repo_name:.*?}/edit",
102 m.connect("edit_repo", "/repos/{repo_name:.*?}/edit",
103 action="edit", conditions=dict(method=["GET"],
103 action="edit", conditions=dict(method=["GET"],
104 function=check_repo))
104 function=check_repo))
105 m.connect("formatted_edit_repo", "/repos/{repo_name:.*?}.{format}/edit",
105 m.connect("formatted_edit_repo", "/repos/{repo_name:.*?}.{format}/edit",
106 action="edit", conditions=dict(method=["GET"],
106 action="edit", conditions=dict(method=["GET"],
107 function=check_repo))
107 function=check_repo))
108 m.connect("repo", "/repos/{repo_name:.*?}",
108 m.connect("repo", "/repos/{repo_name:.*?}",
109 action="show", conditions=dict(method=["GET"],
109 action="show", conditions=dict(method=["GET"],
110 function=check_repo))
110 function=check_repo))
111 m.connect("formatted_repo", "/repos/{repo_name:.*?}.{format}",
111 m.connect("formatted_repo", "/repos/{repo_name:.*?}.{format}",
112 action="show", conditions=dict(method=["GET"],
112 action="show", conditions=dict(method=["GET"],
113 function=check_repo))
113 function=check_repo))
114 #ajax delete repo perm user
114 #ajax delete repo perm user
115 m.connect('delete_repo_user', "/repos_delete_user/{repo_name:.*?}",
115 m.connect('delete_repo_user', "/repos_delete_user/{repo_name:.*?}",
116 action="delete_perm_user",
116 action="delete_perm_user",
117 conditions=dict(method=["DELETE"], function=check_repo))
117 conditions=dict(method=["DELETE"], function=check_repo))
118
118
119 #ajax delete repo perm users_group
119 #ajax delete repo perm users_group
120 m.connect('delete_repo_users_group',
120 m.connect('delete_repo_users_group',
121 "/repos_delete_users_group/{repo_name:.*?}",
121 "/repos_delete_users_group/{repo_name:.*?}",
122 action="delete_perm_users_group",
122 action="delete_perm_users_group",
123 conditions=dict(method=["DELETE"], function=check_repo))
123 conditions=dict(method=["DELETE"], function=check_repo))
124
124
125 #settings actions
125 #settings actions
126 m.connect('repo_stats', "/repos_stats/{repo_name:.*?}",
126 m.connect('repo_stats', "/repos_stats/{repo_name:.*?}",
127 action="repo_stats", conditions=dict(method=["DELETE"],
127 action="repo_stats", conditions=dict(method=["DELETE"],
128 function=check_repo))
128 function=check_repo))
129 m.connect('repo_cache', "/repos_cache/{repo_name:.*?}",
129 m.connect('repo_cache', "/repos_cache/{repo_name:.*?}",
130 action="repo_cache", conditions=dict(method=["DELETE"],
130 action="repo_cache", conditions=dict(method=["DELETE"],
131 function=check_repo))
131 function=check_repo))
132 m.connect('repo_public_journal', "/repos_public_journal/{repo_name:.*?}",
132 m.connect('repo_public_journal', "/repos_public_journal/{repo_name:.*?}",
133 action="repo_public_journal", conditions=dict(method=["PUT"],
133 action="repo_public_journal", conditions=dict(method=["PUT"],
134 function=check_repo))
134 function=check_repo))
135 m.connect('repo_pull', "/repo_pull/{repo_name:.*?}",
135 m.connect('repo_pull', "/repo_pull/{repo_name:.*?}",
136 action="repo_pull", conditions=dict(method=["PUT"],
136 action="repo_pull", conditions=dict(method=["PUT"],
137 function=check_repo))
137 function=check_repo))
138 m.connect('repo_as_fork', "/repo_as_fork/{repo_name:.*?}",
138 m.connect('repo_as_fork', "/repo_as_fork/{repo_name:.*?}",
139 action="repo_as_fork", conditions=dict(method=["PUT"],
139 action="repo_as_fork", conditions=dict(method=["PUT"],
140 function=check_repo))
140 function=check_repo))
141 m.connect('repo_locking', "/repo_locking/{repo_name:.*?}",
141 m.connect('repo_locking', "/repo_locking/{repo_name:.*?}",
142 action="repo_locking", conditions=dict(method=["PUT"],
142 action="repo_locking", conditions=dict(method=["PUT"],
143 function=check_repo))
143 function=check_repo))
144 with rmap.submapper(path_prefix=ADMIN_PREFIX,
144 with rmap.submapper(path_prefix=ADMIN_PREFIX,
145 controller='admin/repos_groups') as m:
145 controller='admin/repos_groups') as m:
146 m.connect("repos_groups", "/repos_groups",
146 m.connect("repos_groups", "/repos_groups",
147 action="create", conditions=dict(method=["POST"]))
147 action="create", conditions=dict(method=["POST"]))
148 m.connect("repos_groups", "/repos_groups",
148 m.connect("repos_groups", "/repos_groups",
149 action="index", conditions=dict(method=["GET"]))
149 action="index", conditions=dict(method=["GET"]))
150 m.connect("formatted_repos_groups", "/repos_groups.{format}",
150 m.connect("formatted_repos_groups", "/repos_groups.{format}",
151 action="index", conditions=dict(method=["GET"]))
151 action="index", conditions=dict(method=["GET"]))
152 m.connect("new_repos_group", "/repos_groups/new",
152 m.connect("new_repos_group", "/repos_groups/new",
153 action="new", conditions=dict(method=["GET"]))
153 action="new", conditions=dict(method=["GET"]))
154 m.connect("formatted_new_repos_group", "/repos_groups/new.{format}",
154 m.connect("formatted_new_repos_group", "/repos_groups/new.{format}",
155 action="new", conditions=dict(method=["GET"]))
155 action="new", conditions=dict(method=["GET"]))
156 m.connect("update_repos_group", "/repos_groups/{id}",
156 m.connect("update_repos_group", "/repos_groups/{id}",
157 action="update", conditions=dict(method=["PUT"],
157 action="update", conditions=dict(method=["PUT"],
158 function=check_int))
158 function=check_int))
159 m.connect("delete_repos_group", "/repos_groups/{id}",
159 m.connect("delete_repos_group", "/repos_groups/{id}",
160 action="delete", conditions=dict(method=["DELETE"],
160 action="delete", conditions=dict(method=["DELETE"],
161 function=check_int))
161 function=check_int))
162 m.connect("edit_repos_group", "/repos_groups/{id}/edit",
162 m.connect("edit_repos_group", "/repos_groups/{id}/edit",
163 action="edit", conditions=dict(method=["GET"],))
163 action="edit", conditions=dict(method=["GET"],))
164 m.connect("formatted_edit_repos_group",
164 m.connect("formatted_edit_repos_group",
165 "/repos_groups/{id}.{format}/edit",
165 "/repos_groups/{id}.{format}/edit",
166 action="edit", conditions=dict(method=["GET"],
166 action="edit", conditions=dict(method=["GET"],
167 function=check_int))
167 function=check_int))
168 m.connect("repos_group", "/repos_groups/{id}",
168 m.connect("repos_group", "/repos_groups/{id}",
169 action="show", conditions=dict(method=["GET"],
169 action="show", conditions=dict(method=["GET"],
170 function=check_int))
170 function=check_int))
171 m.connect("formatted_repos_group", "/repos_groups/{id}.{format}",
171 m.connect("formatted_repos_group", "/repos_groups/{id}.{format}",
172 action="show", conditions=dict(method=["GET"],
172 action="show", conditions=dict(method=["GET"],
173 function=check_int))
173 function=check_int))
174 # ajax delete repos group perm user
174 # ajax delete repos group perm user
175 m.connect('delete_repos_group_user_perm',
175 m.connect('delete_repos_group_user_perm',
176 "/delete_repos_group_user_perm/{group_name:.*}",
176 "/delete_repos_group_user_perm/{group_name:.*}",
177 action="delete_repos_group_user_perm",
177 action="delete_repos_group_user_perm",
178 conditions=dict(method=["DELETE"], function=check_group))
178 conditions=dict(method=["DELETE"], function=check_group))
179
179
180 # ajax delete repos group perm users_group
180 # ajax delete repos group perm users_group
181 m.connect('delete_repos_group_users_group_perm',
181 m.connect('delete_repos_group_users_group_perm',
182 "/delete_repos_group_users_group_perm/{group_name:.*}",
182 "/delete_repos_group_users_group_perm/{group_name:.*}",
183 action="delete_repos_group_users_group_perm",
183 action="delete_repos_group_users_group_perm",
184 conditions=dict(method=["DELETE"], function=check_group))
184 conditions=dict(method=["DELETE"], function=check_group))
185
185
186 #ADMIN USER REST ROUTES
186 #ADMIN USER REST ROUTES
187 with rmap.submapper(path_prefix=ADMIN_PREFIX,
187 with rmap.submapper(path_prefix=ADMIN_PREFIX,
188 controller='admin/users') as m:
188 controller='admin/users') as m:
189 m.connect("users", "/users",
189 m.connect("users", "/users",
190 action="create", conditions=dict(method=["POST"]))
190 action="create", conditions=dict(method=["POST"]))
191 m.connect("users", "/users",
191 m.connect("users", "/users",
192 action="index", conditions=dict(method=["GET"]))
192 action="index", conditions=dict(method=["GET"]))
193 m.connect("formatted_users", "/users.{format}",
193 m.connect("formatted_users", "/users.{format}",
194 action="index", conditions=dict(method=["GET"]))
194 action="index", conditions=dict(method=["GET"]))
195 m.connect("new_user", "/users/new",
195 m.connect("new_user", "/users/new",
196 action="new", conditions=dict(method=["GET"]))
196 action="new", conditions=dict(method=["GET"]))
197 m.connect("formatted_new_user", "/users/new.{format}",
197 m.connect("formatted_new_user", "/users/new.{format}",
198 action="new", conditions=dict(method=["GET"]))
198 action="new", conditions=dict(method=["GET"]))
199 m.connect("update_user", "/users/{id}",
199 m.connect("update_user", "/users/{id}",
200 action="update", conditions=dict(method=["PUT"]))
200 action="update", conditions=dict(method=["PUT"]))
201 m.connect("delete_user", "/users/{id}",
201 m.connect("delete_user", "/users/{id}",
202 action="delete", conditions=dict(method=["DELETE"]))
202 action="delete", conditions=dict(method=["DELETE"]))
203 m.connect("edit_user", "/users/{id}/edit",
203 m.connect("edit_user", "/users/{id}/edit",
204 action="edit", conditions=dict(method=["GET"]))
204 action="edit", conditions=dict(method=["GET"]))
205 m.connect("formatted_edit_user",
205 m.connect("formatted_edit_user",
206 "/users/{id}.{format}/edit",
206 "/users/{id}.{format}/edit",
207 action="edit", conditions=dict(method=["GET"]))
207 action="edit", conditions=dict(method=["GET"]))
208 m.connect("user", "/users/{id}",
208 m.connect("user", "/users/{id}",
209 action="show", conditions=dict(method=["GET"]))
209 action="show", conditions=dict(method=["GET"]))
210 m.connect("formatted_user", "/users/{id}.{format}",
210 m.connect("formatted_user", "/users/{id}.{format}",
211 action="show", conditions=dict(method=["GET"]))
211 action="show", conditions=dict(method=["GET"]))
212
212
213 #EXTRAS USER ROUTES
213 #EXTRAS USER ROUTES
214 m.connect("user_perm", "/users_perm/{id}",
214 m.connect("user_perm", "/users_perm/{id}",
215 action="update_perm", conditions=dict(method=["PUT"]))
215 action="update_perm", conditions=dict(method=["PUT"]))
216 m.connect("user_emails", "/users_emails/{id}",
216 m.connect("user_emails", "/users_emails/{id}",
217 action="add_email", conditions=dict(method=["PUT"]))
217 action="add_email", conditions=dict(method=["PUT"]))
218 m.connect("user_emails_delete", "/users_emails/{id}",
218 m.connect("user_emails_delete", "/users_emails/{id}",
219 action="delete_email", conditions=dict(method=["DELETE"]))
219 action="delete_email", conditions=dict(method=["DELETE"]))
220
220
221 #ADMIN USERS GROUPS REST ROUTES
221 #ADMIN USERS GROUPS REST ROUTES
222 with rmap.submapper(path_prefix=ADMIN_PREFIX,
222 with rmap.submapper(path_prefix=ADMIN_PREFIX,
223 controller='admin/users_groups') as m:
223 controller='admin/users_groups') as m:
224 m.connect("users_groups", "/users_groups",
224 m.connect("users_groups", "/users_groups",
225 action="create", conditions=dict(method=["POST"]))
225 action="create", conditions=dict(method=["POST"]))
226 m.connect("users_groups", "/users_groups",
226 m.connect("users_groups", "/users_groups",
227 action="index", conditions=dict(method=["GET"]))
227 action="index", conditions=dict(method=["GET"]))
228 m.connect("formatted_users_groups", "/users_groups.{format}",
228 m.connect("formatted_users_groups", "/users_groups.{format}",
229 action="index", conditions=dict(method=["GET"]))
229 action="index", conditions=dict(method=["GET"]))
230 m.connect("new_users_group", "/users_groups/new",
230 m.connect("new_users_group", "/users_groups/new",
231 action="new", conditions=dict(method=["GET"]))
231 action="new", conditions=dict(method=["GET"]))
232 m.connect("formatted_new_users_group", "/users_groups/new.{format}",
232 m.connect("formatted_new_users_group", "/users_groups/new.{format}",
233 action="new", conditions=dict(method=["GET"]))
233 action="new", conditions=dict(method=["GET"]))
234 m.connect("update_users_group", "/users_groups/{id}",
234 m.connect("update_users_group", "/users_groups/{id}",
235 action="update", conditions=dict(method=["PUT"]))
235 action="update", conditions=dict(method=["PUT"]))
236 m.connect("delete_users_group", "/users_groups/{id}",
236 m.connect("delete_users_group", "/users_groups/{id}",
237 action="delete", conditions=dict(method=["DELETE"]))
237 action="delete", conditions=dict(method=["DELETE"]))
238 m.connect("edit_users_group", "/users_groups/{id}/edit",
238 m.connect("edit_users_group", "/users_groups/{id}/edit",
239 action="edit", conditions=dict(method=["GET"]))
239 action="edit", conditions=dict(method=["GET"]))
240 m.connect("formatted_edit_users_group",
240 m.connect("formatted_edit_users_group",
241 "/users_groups/{id}.{format}/edit",
241 "/users_groups/{id}.{format}/edit",
242 action="edit", conditions=dict(method=["GET"]))
242 action="edit", conditions=dict(method=["GET"]))
243 m.connect("users_group", "/users_groups/{id}",
243 m.connect("users_group", "/users_groups/{id}",
244 action="show", conditions=dict(method=["GET"]))
244 action="show", conditions=dict(method=["GET"]))
245 m.connect("formatted_users_group", "/users_groups/{id}.{format}",
245 m.connect("formatted_users_group", "/users_groups/{id}.{format}",
246 action="show", conditions=dict(method=["GET"]))
246 action="show", conditions=dict(method=["GET"]))
247
247
248 #EXTRAS USER ROUTES
248 #EXTRAS USER ROUTES
249 m.connect("users_group_perm", "/users_groups_perm/{id}",
249 m.connect("users_group_perm", "/users_groups_perm/{id}",
250 action="update_perm", conditions=dict(method=["PUT"]))
250 action="update_perm", conditions=dict(method=["PUT"]))
251
251
252 #ADMIN GROUP REST ROUTES
252 #ADMIN GROUP REST ROUTES
253 rmap.resource('group', 'groups',
253 rmap.resource('group', 'groups',
254 controller='admin/groups', path_prefix=ADMIN_PREFIX)
254 controller='admin/groups', path_prefix=ADMIN_PREFIX)
255
255
256 #ADMIN PERMISSIONS REST ROUTES
256 #ADMIN PERMISSIONS REST ROUTES
257 rmap.resource('permission', 'permissions',
257 rmap.resource('permission', 'permissions',
258 controller='admin/permissions', path_prefix=ADMIN_PREFIX)
258 controller='admin/permissions', path_prefix=ADMIN_PREFIX)
259
259
260 ##ADMIN LDAP SETTINGS
260 ##ADMIN LDAP SETTINGS
261 rmap.connect('ldap_settings', '%s/ldap' % ADMIN_PREFIX,
261 rmap.connect('ldap_settings', '%s/ldap' % ADMIN_PREFIX,
262 controller='admin/ldap_settings', action='ldap_settings',
262 controller='admin/ldap_settings', action='ldap_settings',
263 conditions=dict(method=["POST"]))
263 conditions=dict(method=["POST"]))
264
264
265 rmap.connect('ldap_home', '%s/ldap' % ADMIN_PREFIX,
265 rmap.connect('ldap_home', '%s/ldap' % ADMIN_PREFIX,
266 controller='admin/ldap_settings')
266 controller='admin/ldap_settings')
267
267
268 #ADMIN SETTINGS REST ROUTES
268 #ADMIN SETTINGS REST ROUTES
269 with rmap.submapper(path_prefix=ADMIN_PREFIX,
269 with rmap.submapper(path_prefix=ADMIN_PREFIX,
270 controller='admin/settings') as m:
270 controller='admin/settings') as m:
271 m.connect("admin_settings", "/settings",
271 m.connect("admin_settings", "/settings",
272 action="create", conditions=dict(method=["POST"]))
272 action="create", conditions=dict(method=["POST"]))
273 m.connect("admin_settings", "/settings",
273 m.connect("admin_settings", "/settings",
274 action="index", conditions=dict(method=["GET"]))
274 action="index", conditions=dict(method=["GET"]))
275 m.connect("formatted_admin_settings", "/settings.{format}",
275 m.connect("formatted_admin_settings", "/settings.{format}",
276 action="index", conditions=dict(method=["GET"]))
276 action="index", conditions=dict(method=["GET"]))
277 m.connect("admin_new_setting", "/settings/new",
277 m.connect("admin_new_setting", "/settings/new",
278 action="new", conditions=dict(method=["GET"]))
278 action="new", conditions=dict(method=["GET"]))
279 m.connect("formatted_admin_new_setting", "/settings/new.{format}",
279 m.connect("formatted_admin_new_setting", "/settings/new.{format}",
280 action="new", conditions=dict(method=["GET"]))
280 action="new", conditions=dict(method=["GET"]))
281 m.connect("/settings/{setting_id}",
281 m.connect("/settings/{setting_id}",
282 action="update", conditions=dict(method=["PUT"]))
282 action="update", conditions=dict(method=["PUT"]))
283 m.connect("/settings/{setting_id}",
283 m.connect("/settings/{setting_id}",
284 action="delete", conditions=dict(method=["DELETE"]))
284 action="delete", conditions=dict(method=["DELETE"]))
285 m.connect("admin_edit_setting", "/settings/{setting_id}/edit",
285 m.connect("admin_edit_setting", "/settings/{setting_id}/edit",
286 action="edit", conditions=dict(method=["GET"]))
286 action="edit", conditions=dict(method=["GET"]))
287 m.connect("formatted_admin_edit_setting",
287 m.connect("formatted_admin_edit_setting",
288 "/settings/{setting_id}.{format}/edit",
288 "/settings/{setting_id}.{format}/edit",
289 action="edit", conditions=dict(method=["GET"]))
289 action="edit", conditions=dict(method=["GET"]))
290 m.connect("admin_setting", "/settings/{setting_id}",
290 m.connect("admin_setting", "/settings/{setting_id}",
291 action="show", conditions=dict(method=["GET"]))
291 action="show", conditions=dict(method=["GET"]))
292 m.connect("formatted_admin_setting", "/settings/{setting_id}.{format}",
292 m.connect("formatted_admin_setting", "/settings/{setting_id}.{format}",
293 action="show", conditions=dict(method=["GET"]))
293 action="show", conditions=dict(method=["GET"]))
294 m.connect("admin_settings_my_account", "/my_account",
294 m.connect("admin_settings_my_account", "/my_account",
295 action="my_account", conditions=dict(method=["GET"]))
295 action="my_account", conditions=dict(method=["GET"]))
296 m.connect("admin_settings_my_account_update", "/my_account_update",
296 m.connect("admin_settings_my_account_update", "/my_account_update",
297 action="my_account_update", conditions=dict(method=["PUT"]))
297 action="my_account_update", conditions=dict(method=["PUT"]))
298 m.connect("admin_settings_create_repository", "/create_repository",
298 m.connect("admin_settings_create_repository", "/create_repository",
299 action="create_repository", conditions=dict(method=["GET"]))
299 action="create_repository", conditions=dict(method=["GET"]))
300 m.connect("admin_settings_my_repos", "/my_account/repos",
300 m.connect("admin_settings_my_repos", "/my_account/repos",
301 action="my_account_my_repos", conditions=dict(method=["GET"]))
301 action="my_account_my_repos", conditions=dict(method=["GET"]))
302 m.connect("admin_settings_my_pullrequests", "/my_account/pull_requests",
302 m.connect("admin_settings_my_pullrequests", "/my_account/pull_requests",
303 action="my_account_my_pullrequests", conditions=dict(method=["GET"]))
303 action="my_account_my_pullrequests", conditions=dict(method=["GET"]))
304
304
305 #NOTIFICATION REST ROUTES
305 #NOTIFICATION REST ROUTES
306 with rmap.submapper(path_prefix=ADMIN_PREFIX,
306 with rmap.submapper(path_prefix=ADMIN_PREFIX,
307 controller='admin/notifications') as m:
307 controller='admin/notifications') as m:
308 m.connect("notifications", "/notifications",
308 m.connect("notifications", "/notifications",
309 action="create", conditions=dict(method=["POST"]))
309 action="create", conditions=dict(method=["POST"]))
310 m.connect("notifications", "/notifications",
310 m.connect("notifications", "/notifications",
311 action="index", conditions=dict(method=["GET"]))
311 action="index", conditions=dict(method=["GET"]))
312 m.connect("notifications_mark_all_read", "/notifications/mark_all_read",
312 m.connect("notifications_mark_all_read", "/notifications/mark_all_read",
313 action="mark_all_read", conditions=dict(method=["GET"]))
313 action="mark_all_read", conditions=dict(method=["GET"]))
314 m.connect("formatted_notifications", "/notifications.{format}",
314 m.connect("formatted_notifications", "/notifications.{format}",
315 action="index", conditions=dict(method=["GET"]))
315 action="index", conditions=dict(method=["GET"]))
316 m.connect("new_notification", "/notifications/new",
316 m.connect("new_notification", "/notifications/new",
317 action="new", conditions=dict(method=["GET"]))
317 action="new", conditions=dict(method=["GET"]))
318 m.connect("formatted_new_notification", "/notifications/new.{format}",
318 m.connect("formatted_new_notification", "/notifications/new.{format}",
319 action="new", conditions=dict(method=["GET"]))
319 action="new", conditions=dict(method=["GET"]))
320 m.connect("/notification/{notification_id}",
320 m.connect("/notification/{notification_id}",
321 action="update", conditions=dict(method=["PUT"]))
321 action="update", conditions=dict(method=["PUT"]))
322 m.connect("/notification/{notification_id}",
322 m.connect("/notification/{notification_id}",
323 action="delete", conditions=dict(method=["DELETE"]))
323 action="delete", conditions=dict(method=["DELETE"]))
324 m.connect("edit_notification", "/notification/{notification_id}/edit",
324 m.connect("edit_notification", "/notification/{notification_id}/edit",
325 action="edit", conditions=dict(method=["GET"]))
325 action="edit", conditions=dict(method=["GET"]))
326 m.connect("formatted_edit_notification",
326 m.connect("formatted_edit_notification",
327 "/notification/{notification_id}.{format}/edit",
327 "/notification/{notification_id}.{format}/edit",
328 action="edit", conditions=dict(method=["GET"]))
328 action="edit", conditions=dict(method=["GET"]))
329 m.connect("notification", "/notification/{notification_id}",
329 m.connect("notification", "/notification/{notification_id}",
330 action="show", conditions=dict(method=["GET"]))
330 action="show", conditions=dict(method=["GET"]))
331 m.connect("formatted_notification", "/notifications/{notification_id}.{format}",
331 m.connect("formatted_notification", "/notifications/{notification_id}.{format}",
332 action="show", conditions=dict(method=["GET"]))
332 action="show", conditions=dict(method=["GET"]))
333
333
334 #ADMIN MAIN PAGES
334 #ADMIN MAIN PAGES
335 with rmap.submapper(path_prefix=ADMIN_PREFIX,
335 with rmap.submapper(path_prefix=ADMIN_PREFIX,
336 controller='admin/admin') as m:
336 controller='admin/admin') as m:
337 m.connect('admin_home', '', action='index')
337 m.connect('admin_home', '', action='index')
338 m.connect('admin_add_repo', '/add_repo/{new_repo:[a-z0-9\. _-]*}',
338 m.connect('admin_add_repo', '/add_repo/{new_repo:[a-z0-9\. _-]*}',
339 action='add_repo')
339 action='add_repo')
340
340
341 #==========================================================================
341 #==========================================================================
342 # API V2
342 # API V2
343 #==========================================================================
343 #==========================================================================
344 with rmap.submapper(path_prefix=ADMIN_PREFIX,
344 with rmap.submapper(path_prefix=ADMIN_PREFIX,
345 controller='api/api') as m:
345 controller='api/api') as m:
346 m.connect('api', '/api')
346 m.connect('api', '/api')
347
347
348 #USER JOURNAL
348 #USER JOURNAL
349 rmap.connect('journal', '%s/journal' % ADMIN_PREFIX,
349 rmap.connect('journal', '%s/journal' % ADMIN_PREFIX,
350 controller='journal', action='index')
350 controller='journal', action='index')
351 rmap.connect('journal_rss', '%s/journal/rss' % ADMIN_PREFIX,
351 rmap.connect('journal_rss', '%s/journal/rss' % ADMIN_PREFIX,
352 controller='journal', action='journal_rss')
352 controller='journal', action='journal_rss')
353 rmap.connect('journal_atom', '%s/journal/atom' % ADMIN_PREFIX,
353 rmap.connect('journal_atom', '%s/journal/atom' % ADMIN_PREFIX,
354 controller='journal', action='journal_atom')
354 controller='journal', action='journal_atom')
355
355
356 rmap.connect('public_journal', '%s/public_journal' % ADMIN_PREFIX,
356 rmap.connect('public_journal', '%s/public_journal' % ADMIN_PREFIX,
357 controller='journal', action="public_journal")
357 controller='journal', action="public_journal")
358
358
359 rmap.connect('public_journal_rss', '%s/public_journal/rss' % ADMIN_PREFIX,
359 rmap.connect('public_journal_rss', '%s/public_journal/rss' % ADMIN_PREFIX,
360 controller='journal', action="public_journal_rss")
360 controller='journal', action="public_journal_rss")
361
361
362 rmap.connect('public_journal_rss_old', '%s/public_journal_rss' % ADMIN_PREFIX,
362 rmap.connect('public_journal_rss_old', '%s/public_journal_rss' % ADMIN_PREFIX,
363 controller='journal', action="public_journal_rss")
363 controller='journal', action="public_journal_rss")
364
364
365 rmap.connect('public_journal_atom',
365 rmap.connect('public_journal_atom',
366 '%s/public_journal/atom' % ADMIN_PREFIX, controller='journal',
366 '%s/public_journal/atom' % ADMIN_PREFIX, controller='journal',
367 action="public_journal_atom")
367 action="public_journal_atom")
368
368
369 rmap.connect('public_journal_atom_old',
369 rmap.connect('public_journal_atom_old',
370 '%s/public_journal_atom' % ADMIN_PREFIX, controller='journal',
370 '%s/public_journal_atom' % ADMIN_PREFIX, controller='journal',
371 action="public_journal_atom")
371 action="public_journal_atom")
372
372
373 rmap.connect('toggle_following', '%s/toggle_following' % ADMIN_PREFIX,
373 rmap.connect('toggle_following', '%s/toggle_following' % ADMIN_PREFIX,
374 controller='journal', action='toggle_following',
374 controller='journal', action='toggle_following',
375 conditions=dict(method=["POST"]))
375 conditions=dict(method=["POST"]))
376
376
377 #SEARCH
377 #SEARCH
378 rmap.connect('search', '%s/search' % ADMIN_PREFIX, controller='search',)
378 rmap.connect('search', '%s/search' % ADMIN_PREFIX, controller='search',)
379 rmap.connect('search_repo', '%s/search/{search_repo:.*}' % ADMIN_PREFIX,
379 rmap.connect('search_repo', '%s/search/{search_repo:.*}' % ADMIN_PREFIX,
380 controller='search')
380 controller='search')
381
381
382 #LOGIN/LOGOUT/REGISTER/SIGN IN
382 #LOGIN/LOGOUT/REGISTER/SIGN IN
383 rmap.connect('login_home', '%s/login' % ADMIN_PREFIX, controller='login')
383 rmap.connect('login_home', '%s/login' % ADMIN_PREFIX, controller='login')
384 rmap.connect('logout_home', '%s/logout' % ADMIN_PREFIX, controller='login',
384 rmap.connect('logout_home', '%s/logout' % ADMIN_PREFIX, controller='login',
385 action='logout')
385 action='logout')
386
386
387 rmap.connect('register', '%s/register' % ADMIN_PREFIX, controller='login',
387 rmap.connect('register', '%s/register' % ADMIN_PREFIX, controller='login',
388 action='register')
388 action='register')
389
389
390 rmap.connect('reset_password', '%s/password_reset' % ADMIN_PREFIX,
390 rmap.connect('reset_password', '%s/password_reset' % ADMIN_PREFIX,
391 controller='login', action='password_reset')
391 controller='login', action='password_reset')
392
392
393 rmap.connect('reset_password_confirmation',
393 rmap.connect('reset_password_confirmation',
394 '%s/password_reset_confirmation' % ADMIN_PREFIX,
394 '%s/password_reset_confirmation' % ADMIN_PREFIX,
395 controller='login', action='password_reset_confirmation')
395 controller='login', action='password_reset_confirmation')
396
396
397 #FEEDS
397 #FEEDS
398 rmap.connect('rss_feed_home', '/{repo_name:.*?}/feed/rss',
398 rmap.connect('rss_feed_home', '/{repo_name:.*?}/feed/rss',
399 controller='feed', action='rss',
399 controller='feed', action='rss',
400 conditions=dict(function=check_repo))
400 conditions=dict(function=check_repo))
401
401
402 rmap.connect('atom_feed_home', '/{repo_name:.*?}/feed/atom',
402 rmap.connect('atom_feed_home', '/{repo_name:.*?}/feed/atom',
403 controller='feed', action='atom',
403 controller='feed', action='atom',
404 conditions=dict(function=check_repo))
404 conditions=dict(function=check_repo))
405
405
406 #==========================================================================
406 #==========================================================================
407 # REPOSITORY ROUTES
407 # REPOSITORY ROUTES
408 #==========================================================================
408 #==========================================================================
409 rmap.connect('summary_home', '/{repo_name:.*?}',
409 rmap.connect('summary_home', '/{repo_name:.*?}',
410 controller='summary',
410 controller='summary',
411 conditions=dict(function=check_repo))
411 conditions=dict(function=check_repo))
412
412
413 rmap.connect('repos_group_home', '/{group_name:.*}',
413 rmap.connect('repos_group_home', '/{group_name:.*}',
414 controller='admin/repos_groups', action="show_by_name",
414 controller='admin/repos_groups', action="show_by_name",
415 conditions=dict(function=check_group))
415 conditions=dict(function=check_group))
416
416
417 rmap.connect('changeset_home', '/{repo_name:.*?}/changeset/{revision}',
417 rmap.connect('changeset_home', '/{repo_name:.*?}/changeset/{revision}',
418 controller='changeset', revision='tip',
418 controller='changeset', revision='tip',
419 conditions=dict(function=check_repo))
419 conditions=dict(function=check_repo))
420
420
421 rmap.connect('changeset_comment',
421 rmap.connect('changeset_comment',
422 '/{repo_name:.*?}/changeset/{revision}/comment',
422 '/{repo_name:.*?}/changeset/{revision}/comment',
423 controller='changeset', revision='tip', action='comment',
423 controller='changeset', revision='tip', action='comment',
424 conditions=dict(function=check_repo))
424 conditions=dict(function=check_repo))
425
425
426 rmap.connect('changeset_comment_delete',
426 rmap.connect('changeset_comment_delete',
427 '/{repo_name:.*?}/changeset/comment/{comment_id}/delete',
427 '/{repo_name:.*?}/changeset/comment/{comment_id}/delete',
428 controller='changeset', action='delete_comment',
428 controller='changeset', action='delete_comment',
429 conditions=dict(function=check_repo, method=["DELETE"]))
429 conditions=dict(function=check_repo, method=["DELETE"]))
430
430
431 rmap.connect('raw_changeset_home',
431 rmap.connect('raw_changeset_home',
432 '/{repo_name:.*?}/raw-changeset/{revision}',
432 '/{repo_name:.*?}/raw-changeset/{revision}',
433 controller='changeset', action='raw_changeset',
433 controller='changeset', action='raw_changeset',
434 revision='tip', conditions=dict(function=check_repo))
434 revision='tip', conditions=dict(function=check_repo))
435
435
436 rmap.connect('compare_url',
436 rmap.connect('compare_url',
437 '/{repo_name:.*?}/compare/{org_ref_type}@{org_ref}...{other_ref_type}@{other_ref}',
437 '/{repo_name:.*?}/compare/{org_ref_type}@{org_ref}...{other_ref_type}@{other_ref}',
438 controller='compare', action='index',
438 controller='compare', action='index',
439 conditions=dict(function=check_repo),
439 conditions=dict(function=check_repo),
440 requirements=dict(
440 requirements=dict(
441 org_ref_type='(branch|book|tag|rev|org_ref_type)',
441 org_ref_type='(branch|book|tag|rev|org_ref_type)',
442 other_ref_type='(branch|book|tag|rev|other_ref_type)')
442 other_ref_type='(branch|book|tag|rev|other_ref_type)')
443 )
443 )
444
444
445 rmap.connect('pullrequest_home',
445 rmap.connect('pullrequest_home',
446 '/{repo_name:.*?}/pull-request/new', controller='pullrequests',
446 '/{repo_name:.*?}/pull-request/new', controller='pullrequests',
447 action='index', conditions=dict(function=check_repo,
447 action='index', conditions=dict(function=check_repo,
448 method=["GET"]))
448 method=["GET"]))
449
449
450 rmap.connect('pullrequest',
450 rmap.connect('pullrequest',
451 '/{repo_name:.*?}/pull-request/new', controller='pullrequests',
451 '/{repo_name:.*?}/pull-request/new', controller='pullrequests',
452 action='create', conditions=dict(function=check_repo,
452 action='create', conditions=dict(function=check_repo,
453 method=["POST"]))
453 method=["POST"]))
454
454
455 rmap.connect('pullrequest_show',
455 rmap.connect('pullrequest_show',
456 '/{repo_name:.*?}/pull-request/{pull_request_id}',
456 '/{repo_name:.*?}/pull-request/{pull_request_id}',
457 controller='pullrequests',
457 controller='pullrequests',
458 action='show', conditions=dict(function=check_repo,
458 action='show', conditions=dict(function=check_repo,
459 method=["GET"]))
459 method=["GET"]))
460 rmap.connect('pullrequest_update',
460 rmap.connect('pullrequest_update',
461 '/{repo_name:.*?}/pull-request/{pull_request_id}',
461 '/{repo_name:.*?}/pull-request/{pull_request_id}',
462 controller='pullrequests',
462 controller='pullrequests',
463 action='update', conditions=dict(function=check_repo,
463 action='update', conditions=dict(function=check_repo,
464 method=["PUT"]))
464 method=["PUT"]))
465 rmap.connect('pullrequest_delete',
466 '/{repo_name:.*?}/pull-request/{pull_request_id}',
467 controller='pullrequests',
468 action='delete', conditions=dict(function=check_repo,
469 method=["DELETE"]))
465
470
466 rmap.connect('pullrequest_show_all',
471 rmap.connect('pullrequest_show_all',
467 '/{repo_name:.*?}/pull-request',
472 '/{repo_name:.*?}/pull-request',
468 controller='pullrequests',
473 controller='pullrequests',
469 action='show_all', conditions=dict(function=check_repo,
474 action='show_all', conditions=dict(function=check_repo,
470 method=["GET"]))
475 method=["GET"]))
471
476
472 rmap.connect('pullrequest_comment',
477 rmap.connect('pullrequest_comment',
473 '/{repo_name:.*?}/pull-request-comment/{pull_request_id}',
478 '/{repo_name:.*?}/pull-request-comment/{pull_request_id}',
474 controller='pullrequests',
479 controller='pullrequests',
475 action='comment', conditions=dict(function=check_repo,
480 action='comment', conditions=dict(function=check_repo,
476 method=["POST"]))
481 method=["POST"]))
477
482
478 rmap.connect('pullrequest_comment_delete',
483 rmap.connect('pullrequest_comment_delete',
479 '/{repo_name:.*?}/pull-request-comment/{comment_id}/delete',
484 '/{repo_name:.*?}/pull-request-comment/{comment_id}/delete',
480 controller='pullrequests', action='delete_comment',
485 controller='pullrequests', action='delete_comment',
481 conditions=dict(function=check_repo, method=["DELETE"]))
486 conditions=dict(function=check_repo, method=["DELETE"]))
482
487
483 rmap.connect('summary_home', '/{repo_name:.*?}/summary',
488 rmap.connect('summary_home', '/{repo_name:.*?}/summary',
484 controller='summary', conditions=dict(function=check_repo))
489 controller='summary', conditions=dict(function=check_repo))
485
490
486 rmap.connect('shortlog_home', '/{repo_name:.*?}/shortlog',
491 rmap.connect('shortlog_home', '/{repo_name:.*?}/shortlog',
487 controller='shortlog', conditions=dict(function=check_repo))
492 controller='shortlog', conditions=dict(function=check_repo))
488
493
489 rmap.connect('branches_home', '/{repo_name:.*?}/branches',
494 rmap.connect('branches_home', '/{repo_name:.*?}/branches',
490 controller='branches', conditions=dict(function=check_repo))
495 controller='branches', conditions=dict(function=check_repo))
491
496
492 rmap.connect('tags_home', '/{repo_name:.*?}/tags',
497 rmap.connect('tags_home', '/{repo_name:.*?}/tags',
493 controller='tags', conditions=dict(function=check_repo))
498 controller='tags', conditions=dict(function=check_repo))
494
499
495 rmap.connect('bookmarks_home', '/{repo_name:.*?}/bookmarks',
500 rmap.connect('bookmarks_home', '/{repo_name:.*?}/bookmarks',
496 controller='bookmarks', conditions=dict(function=check_repo))
501 controller='bookmarks', conditions=dict(function=check_repo))
497
502
498 rmap.connect('changelog_home', '/{repo_name:.*?}/changelog',
503 rmap.connect('changelog_home', '/{repo_name:.*?}/changelog',
499 controller='changelog', conditions=dict(function=check_repo))
504 controller='changelog', conditions=dict(function=check_repo))
500
505
501 rmap.connect('changelog_details', '/{repo_name:.*?}/changelog_details/{cs}',
506 rmap.connect('changelog_details', '/{repo_name:.*?}/changelog_details/{cs}',
502 controller='changelog', action='changelog_details',
507 controller='changelog', action='changelog_details',
503 conditions=dict(function=check_repo))
508 conditions=dict(function=check_repo))
504
509
505 rmap.connect('files_home', '/{repo_name:.*?}/files/{revision}/{f_path:.*}',
510 rmap.connect('files_home', '/{repo_name:.*?}/files/{revision}/{f_path:.*}',
506 controller='files', revision='tip', f_path='',
511 controller='files', revision='tip', f_path='',
507 conditions=dict(function=check_repo))
512 conditions=dict(function=check_repo))
508
513
509 rmap.connect('files_diff_home', '/{repo_name:.*?}/diff/{f_path:.*}',
514 rmap.connect('files_diff_home', '/{repo_name:.*?}/diff/{f_path:.*}',
510 controller='files', action='diff', revision='tip', f_path='',
515 controller='files', action='diff', revision='tip', f_path='',
511 conditions=dict(function=check_repo))
516 conditions=dict(function=check_repo))
512
517
513 rmap.connect('files_rawfile_home',
518 rmap.connect('files_rawfile_home',
514 '/{repo_name:.*?}/rawfile/{revision}/{f_path:.*}',
519 '/{repo_name:.*?}/rawfile/{revision}/{f_path:.*}',
515 controller='files', action='rawfile', revision='tip',
520 controller='files', action='rawfile', revision='tip',
516 f_path='', conditions=dict(function=check_repo))
521 f_path='', conditions=dict(function=check_repo))
517
522
518 rmap.connect('files_raw_home',
523 rmap.connect('files_raw_home',
519 '/{repo_name:.*?}/raw/{revision}/{f_path:.*}',
524 '/{repo_name:.*?}/raw/{revision}/{f_path:.*}',
520 controller='files', action='raw', revision='tip', f_path='',
525 controller='files', action='raw', revision='tip', f_path='',
521 conditions=dict(function=check_repo))
526 conditions=dict(function=check_repo))
522
527
523 rmap.connect('files_annotate_home',
528 rmap.connect('files_annotate_home',
524 '/{repo_name:.*?}/annotate/{revision}/{f_path:.*}',
529 '/{repo_name:.*?}/annotate/{revision}/{f_path:.*}',
525 controller='files', action='index', revision='tip',
530 controller='files', action='index', revision='tip',
526 f_path='', annotate=True, conditions=dict(function=check_repo))
531 f_path='', annotate=True, conditions=dict(function=check_repo))
527
532
528 rmap.connect('files_edit_home',
533 rmap.connect('files_edit_home',
529 '/{repo_name:.*?}/edit/{revision}/{f_path:.*}',
534 '/{repo_name:.*?}/edit/{revision}/{f_path:.*}',
530 controller='files', action='edit', revision='tip',
535 controller='files', action='edit', revision='tip',
531 f_path='', conditions=dict(function=check_repo))
536 f_path='', conditions=dict(function=check_repo))
532
537
533 rmap.connect('files_add_home',
538 rmap.connect('files_add_home',
534 '/{repo_name:.*?}/add/{revision}/{f_path:.*}',
539 '/{repo_name:.*?}/add/{revision}/{f_path:.*}',
535 controller='files', action='add', revision='tip',
540 controller='files', action='add', revision='tip',
536 f_path='', conditions=dict(function=check_repo))
541 f_path='', conditions=dict(function=check_repo))
537
542
538 rmap.connect('files_archive_home', '/{repo_name:.*?}/archive/{fname}',
543 rmap.connect('files_archive_home', '/{repo_name:.*?}/archive/{fname}',
539 controller='files', action='archivefile',
544 controller='files', action='archivefile',
540 conditions=dict(function=check_repo))
545 conditions=dict(function=check_repo))
541
546
542 rmap.connect('files_nodelist_home',
547 rmap.connect('files_nodelist_home',
543 '/{repo_name:.*?}/nodelist/{revision}/{f_path:.*}',
548 '/{repo_name:.*?}/nodelist/{revision}/{f_path:.*}',
544 controller='files', action='nodelist',
549 controller='files', action='nodelist',
545 conditions=dict(function=check_repo))
550 conditions=dict(function=check_repo))
546
551
547 rmap.connect('repo_settings_delete', '/{repo_name:.*?}/settings',
552 rmap.connect('repo_settings_delete', '/{repo_name:.*?}/settings',
548 controller='settings', action="delete",
553 controller='settings', action="delete",
549 conditions=dict(method=["DELETE"], function=check_repo))
554 conditions=dict(method=["DELETE"], function=check_repo))
550
555
551 rmap.connect('repo_settings_update', '/{repo_name:.*?}/settings',
556 rmap.connect('repo_settings_update', '/{repo_name:.*?}/settings',
552 controller='settings', action="update",
557 controller='settings', action="update",
553 conditions=dict(method=["PUT"], function=check_repo))
558 conditions=dict(method=["PUT"], function=check_repo))
554
559
555 rmap.connect('repo_settings_home', '/{repo_name:.*?}/settings',
560 rmap.connect('repo_settings_home', '/{repo_name:.*?}/settings',
556 controller='settings', action='index',
561 controller='settings', action='index',
557 conditions=dict(function=check_repo))
562 conditions=dict(function=check_repo))
558
563
559 rmap.connect('repo_fork_create_home', '/{repo_name:.*?}/fork',
564 rmap.connect('repo_fork_create_home', '/{repo_name:.*?}/fork',
560 controller='forks', action='fork_create',
565 controller='forks', action='fork_create',
561 conditions=dict(function=check_repo, method=["POST"]))
566 conditions=dict(function=check_repo, method=["POST"]))
562
567
563 rmap.connect('repo_fork_home', '/{repo_name:.*?}/fork',
568 rmap.connect('repo_fork_home', '/{repo_name:.*?}/fork',
564 controller='forks', action='fork',
569 controller='forks', action='fork',
565 conditions=dict(function=check_repo))
570 conditions=dict(function=check_repo))
566
571
567 rmap.connect('repo_forks_home', '/{repo_name:.*?}/forks',
572 rmap.connect('repo_forks_home', '/{repo_name:.*?}/forks',
568 controller='forks', action='forks',
573 controller='forks', action='forks',
569 conditions=dict(function=check_repo))
574 conditions=dict(function=check_repo))
570
575
571 rmap.connect('repo_followers_home', '/{repo_name:.*?}/followers',
576 rmap.connect('repo_followers_home', '/{repo_name:.*?}/followers',
572 controller='followers', action='followers',
577 controller='followers', action='followers',
573 conditions=dict(function=check_repo))
578 conditions=dict(function=check_repo))
574
579
575 return rmap
580 return rmap
@@ -1,388 +1,402
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.controllers.pullrequests
3 rhodecode.controllers.pullrequests
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5
5
6 pull requests controller for rhodecode for initializing pull requests
6 pull requests controller for rhodecode for initializing pull requests
7
7
8 :created_on: May 7, 2012
8 :created_on: May 7, 2012
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 import logging
25 import logging
26 import traceback
26 import traceback
27 import formencode
27 import formencode
28
28
29 from webob.exc import HTTPNotFound, HTTPForbidden
29 from webob.exc import HTTPNotFound, HTTPForbidden
30 from collections import defaultdict
30 from collections import defaultdict
31 from itertools import groupby
31 from itertools import groupby
32
32
33 from pylons import request, response, session, tmpl_context as c, url
33 from pylons import request, response, session, tmpl_context as c, url
34 from pylons.controllers.util import abort, redirect
34 from pylons.controllers.util import abort, redirect
35 from pylons.i18n.translation import _
35 from pylons.i18n.translation import _
36 from pylons.decorators import jsonify
36 from pylons.decorators import jsonify
37
37
38 from rhodecode.lib.compat import json
38 from rhodecode.lib.compat import json
39 from rhodecode.lib.base import BaseRepoController, render
39 from rhodecode.lib.base import BaseRepoController, render
40 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator,\
40 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator,\
41 NotAnonymous
41 NotAnonymous
42 from rhodecode.lib import helpers as h
42 from rhodecode.lib import helpers as h
43 from rhodecode.lib import diffs
43 from rhodecode.lib import diffs
44 from rhodecode.lib.utils import action_logger
44 from rhodecode.lib.utils import action_logger
45 from rhodecode.model.db import User, PullRequest, ChangesetStatus,\
45 from rhodecode.model.db import User, PullRequest, ChangesetStatus,\
46 ChangesetComment
46 ChangesetComment
47 from rhodecode.model.pull_request import PullRequestModel
47 from rhodecode.model.pull_request import PullRequestModel
48 from rhodecode.model.meta import Session
48 from rhodecode.model.meta import Session
49 from rhodecode.model.repo import RepoModel
49 from rhodecode.model.repo import RepoModel
50 from rhodecode.model.comment import ChangesetCommentsModel
50 from rhodecode.model.comment import ChangesetCommentsModel
51 from rhodecode.model.changeset_status import ChangesetStatusModel
51 from rhodecode.model.changeset_status import ChangesetStatusModel
52 from rhodecode.model.forms import PullRequestForm
52 from rhodecode.model.forms import PullRequestForm
53
53
54 log = logging.getLogger(__name__)
54 log = logging.getLogger(__name__)
55
55
56
56
57 class PullrequestsController(BaseRepoController):
57 class PullrequestsController(BaseRepoController):
58
58
59 @LoginRequired()
59 @LoginRequired()
60 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
60 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
61 'repository.admin')
61 'repository.admin')
62 def __before__(self):
62 def __before__(self):
63 super(PullrequestsController, self).__before__()
63 super(PullrequestsController, self).__before__()
64 repo_model = RepoModel()
64 repo_model = RepoModel()
65 c.users_array = repo_model.get_users_js()
65 c.users_array = repo_model.get_users_js()
66 c.users_groups_array = repo_model.get_users_groups_js()
66 c.users_groups_array = repo_model.get_users_groups_js()
67
67
68 def _get_repo_refs(self, repo):
68 def _get_repo_refs(self, repo):
69 hist_l = []
69 hist_l = []
70
70
71 branches_group = ([('branch:%s:%s' % (k, v), k) for
71 branches_group = ([('branch:%s:%s' % (k, v), k) for
72 k, v in repo.branches.iteritems()], _("Branches"))
72 k, v in repo.branches.iteritems()], _("Branches"))
73 bookmarks_group = ([('book:%s:%s' % (k, v), k) for
73 bookmarks_group = ([('book:%s:%s' % (k, v), k) for
74 k, v in repo.bookmarks.iteritems()], _("Bookmarks"))
74 k, v in repo.bookmarks.iteritems()], _("Bookmarks"))
75 tags_group = ([('tag:%s:%s' % (k, v), k) for
75 tags_group = ([('tag:%s:%s' % (k, v), k) for
76 k, v in repo.tags.iteritems()], _("Tags"))
76 k, v in repo.tags.iteritems()], _("Tags"))
77
77
78 hist_l.append(bookmarks_group)
78 hist_l.append(bookmarks_group)
79 hist_l.append(branches_group)
79 hist_l.append(branches_group)
80 hist_l.append(tags_group)
80 hist_l.append(tags_group)
81
81
82 return hist_l
82 return hist_l
83
83
84 def show_all(self, repo_name):
84 def show_all(self, repo_name):
85 c.pull_requests = PullRequestModel().get_all(repo_name)
85 c.pull_requests = PullRequestModel().get_all(repo_name)
86 c.repo_name = repo_name
86 c.repo_name = repo_name
87 return render('/pullrequests/pullrequest_show_all.html')
87 return render('/pullrequests/pullrequest_show_all.html')
88
88
89 @NotAnonymous()
89 @NotAnonymous()
90 def index(self):
90 def index(self):
91 org_repo = c.rhodecode_db_repo
91 org_repo = c.rhodecode_db_repo
92
92
93 if org_repo.scm_instance.alias != 'hg':
93 if org_repo.scm_instance.alias != 'hg':
94 log.error('Review not available for GIT REPOS')
94 log.error('Review not available for GIT REPOS')
95 raise HTTPNotFound
95 raise HTTPNotFound
96
96
97 other_repos_info = {}
97 other_repos_info = {}
98
98
99 c.org_refs = self._get_repo_refs(c.rhodecode_repo)
99 c.org_refs = self._get_repo_refs(c.rhodecode_repo)
100 c.org_repos = []
100 c.org_repos = []
101 c.other_repos = []
101 c.other_repos = []
102 c.org_repos.append((org_repo.repo_name, '%s/%s' % (
102 c.org_repos.append((org_repo.repo_name, '%s/%s' % (
103 org_repo.user.username, c.repo_name))
103 org_repo.user.username, c.repo_name))
104 )
104 )
105
105
106 # add org repo to other so we can open pull request agains itself
106 # add org repo to other so we can open pull request agains itself
107 c.other_repos.extend(c.org_repos)
107 c.other_repos.extend(c.org_repos)
108
108
109 c.default_pull_request = org_repo.repo_name
109 c.default_pull_request = org_repo.repo_name
110 c.default_revs = self._get_repo_refs(org_repo.scm_instance)
110 c.default_revs = self._get_repo_refs(org_repo.scm_instance)
111 #add orginal repo
111 #add orginal repo
112 other_repos_info[org_repo.repo_name] = {
112 other_repos_info[org_repo.repo_name] = {
113 'gravatar': h.gravatar_url(org_repo.user.email, 24),
113 'gravatar': h.gravatar_url(org_repo.user.email, 24),
114 'description': org_repo.description,
114 'description': org_repo.description,
115 'revs': h.select('other_ref', '', c.default_revs, class_='refs')
115 'revs': h.select('other_ref', '', c.default_revs, class_='refs')
116 }
116 }
117
117
118 #gather forks and add to this list
118 #gather forks and add to this list
119 for fork in org_repo.forks:
119 for fork in org_repo.forks:
120 c.other_repos.append((fork.repo_name, '%s/%s' % (
120 c.other_repos.append((fork.repo_name, '%s/%s' % (
121 fork.user.username, fork.repo_name))
121 fork.user.username, fork.repo_name))
122 )
122 )
123 other_repos_info[fork.repo_name] = {
123 other_repos_info[fork.repo_name] = {
124 'gravatar': h.gravatar_url(fork.user.email, 24),
124 'gravatar': h.gravatar_url(fork.user.email, 24),
125 'description': fork.description,
125 'description': fork.description,
126 'revs': h.select('other_ref', '',
126 'revs': h.select('other_ref', '',
127 self._get_repo_refs(fork.scm_instance),
127 self._get_repo_refs(fork.scm_instance),
128 class_='refs')
128 class_='refs')
129 }
129 }
130 #add parents of this fork also
130 #add parents of this fork also
131 if org_repo.parent:
131 if org_repo.parent:
132 c.default_pull_request = org_repo.parent.repo_name
132 c.default_pull_request = org_repo.parent.repo_name
133 c.other_repos.append((org_repo.parent.repo_name, '%s/%s' % (
133 c.other_repos.append((org_repo.parent.repo_name, '%s/%s' % (
134 org_repo.parent.user.username,
134 org_repo.parent.user.username,
135 org_repo.parent.repo_name))
135 org_repo.parent.repo_name))
136 )
136 )
137 other_repos_info[org_repo.parent.repo_name] = {
137 other_repos_info[org_repo.parent.repo_name] = {
138 'gravatar': h.gravatar_url(org_repo.parent.user.email, 24),
138 'gravatar': h.gravatar_url(org_repo.parent.user.email, 24),
139 'description': org_repo.parent.description,
139 'description': org_repo.parent.description,
140 'revs': h.select('other_ref', '',
140 'revs': h.select('other_ref', '',
141 self._get_repo_refs(org_repo.parent.scm_instance),
141 self._get_repo_refs(org_repo.parent.scm_instance),
142 class_='refs')
142 class_='refs')
143 }
143 }
144
144
145 c.other_repos_info = json.dumps(other_repos_info)
145 c.other_repos_info = json.dumps(other_repos_info)
146 c.review_members = [org_repo.user]
146 c.review_members = [org_repo.user]
147 return render('/pullrequests/pullrequest.html')
147 return render('/pullrequests/pullrequest.html')
148
148
149 @NotAnonymous()
149 @NotAnonymous()
150 def create(self, repo_name):
150 def create(self, repo_name):
151 try:
151 try:
152 _form = PullRequestForm()().to_python(request.POST)
152 _form = PullRequestForm()().to_python(request.POST)
153 except formencode.Invalid, errors:
153 except formencode.Invalid, errors:
154 log.error(traceback.format_exc())
154 log.error(traceback.format_exc())
155 if errors.error_dict.get('revisions'):
155 if errors.error_dict.get('revisions'):
156 msg = 'Revisions: %s' % errors.error_dict['revisions']
156 msg = 'Revisions: %s' % errors.error_dict['revisions']
157 elif errors.error_dict.get('pullrequest_title'):
157 elif errors.error_dict.get('pullrequest_title'):
158 msg = _('Pull request requires a title with min. 3 chars')
158 msg = _('Pull request requires a title with min. 3 chars')
159 else:
159 else:
160 msg = _('error during creation of pull request')
160 msg = _('error during creation of pull request')
161
161
162 h.flash(msg, 'error')
162 h.flash(msg, 'error')
163 return redirect(url('pullrequest_home', repo_name=repo_name))
163 return redirect(url('pullrequest_home', repo_name=repo_name))
164
164
165 org_repo = _form['org_repo']
165 org_repo = _form['org_repo']
166 org_ref = _form['org_ref']
166 org_ref = _form['org_ref']
167 other_repo = _form['other_repo']
167 other_repo = _form['other_repo']
168 other_ref = _form['other_ref']
168 other_ref = _form['other_ref']
169 revisions = _form['revisions']
169 revisions = _form['revisions']
170 reviewers = _form['review_members']
170 reviewers = _form['review_members']
171
171
172 title = _form['pullrequest_title']
172 title = _form['pullrequest_title']
173 description = _form['pullrequest_desc']
173 description = _form['pullrequest_desc']
174
174
175 try:
175 try:
176 pull_request = PullRequestModel().create(
176 pull_request = PullRequestModel().create(
177 self.rhodecode_user.user_id, org_repo, org_ref, other_repo,
177 self.rhodecode_user.user_id, org_repo, org_ref, other_repo,
178 other_ref, revisions, reviewers, title, description
178 other_ref, revisions, reviewers, title, description
179 )
179 )
180 Session().commit()
180 Session().commit()
181 h.flash(_('Successfully opened new pull request'),
181 h.flash(_('Successfully opened new pull request'),
182 category='success')
182 category='success')
183 except Exception:
183 except Exception:
184 h.flash(_('Error occurred during sending pull request'),
184 h.flash(_('Error occurred during sending pull request'),
185 category='error')
185 category='error')
186 log.error(traceback.format_exc())
186 log.error(traceback.format_exc())
187 return redirect(url('pullrequest_home', repo_name=repo_name))
187 return redirect(url('pullrequest_home', repo_name=repo_name))
188
188
189 return redirect(url('pullrequest_show', repo_name=other_repo,
189 return redirect(url('pullrequest_show', repo_name=other_repo,
190 pull_request_id=pull_request.pull_request_id))
190 pull_request_id=pull_request.pull_request_id))
191
191
192 @NotAnonymous()
192 @NotAnonymous()
193 @jsonify
193 @jsonify
194 def update(self, repo_name, pull_request_id):
194 def update(self, repo_name, pull_request_id):
195 pull_request = PullRequest.get_or_404(pull_request_id)
195 pull_request = PullRequest.get_or_404(pull_request_id)
196 if pull_request.is_closed():
196 if pull_request.is_closed():
197 raise HTTPForbidden()
197 raise HTTPForbidden()
198
198
199 reviewers_ids = map(int, filter(lambda v: v not in [None, ''],
199 reviewers_ids = map(int, filter(lambda v: v not in [None, ''],
200 request.POST.get('reviewers_ids', '').split(',')))
200 request.POST.get('reviewers_ids', '').split(',')))
201
201
202 PullRequestModel().update_reviewers(pull_request_id, reviewers_ids)
202 PullRequestModel().update_reviewers(pull_request_id, reviewers_ids)
203 Session.commit()
203 Session.commit()
204 return True
204 return True
205
205
206 @NotAnonymous()
207 @jsonify
208 def delete(self, repo_name, pull_request_id):
209 pull_request = PullRequest.get_or_404(pull_request_id)
210 #only owner can delete it !
211 if pull_request.author.user_id == c.rhodecode_user.user_id:
212 PullRequestModel().delete(pull_request)
213 Session().commit()
214 h.flash(_('Successfully deleted pull request'),
215 category='success')
216 return redirect(url('admin_settings_my_account'))
217 else:
218 raise HTTPForbidden()
219
206 def _load_compare_data(self, pull_request, enable_comments=True):
220 def _load_compare_data(self, pull_request, enable_comments=True):
207 """
221 """
208 Load context data needed for generating compare diff
222 Load context data needed for generating compare diff
209
223
210 :param pull_request:
224 :param pull_request:
211 :type pull_request:
225 :type pull_request:
212 """
226 """
213
227
214 org_repo = pull_request.org_repo
228 org_repo = pull_request.org_repo
215 (org_ref_type,
229 (org_ref_type,
216 org_ref_name,
230 org_ref_name,
217 org_ref_rev) = pull_request.org_ref.split(':')
231 org_ref_rev) = pull_request.org_ref.split(':')
218
232
219 other_repo = pull_request.other_repo
233 other_repo = pull_request.other_repo
220 (other_ref_type,
234 (other_ref_type,
221 other_ref_name,
235 other_ref_name,
222 other_ref_rev) = pull_request.other_ref.split(':')
236 other_ref_rev) = pull_request.other_ref.split(':')
223
237
224 # despite opening revisions for bookmarks/branches/tags, we always
238 # despite opening revisions for bookmarks/branches/tags, we always
225 # convert this to rev to prevent changes after book or branch change
239 # convert this to rev to prevent changes after book or branch change
226 org_ref = ('rev', org_ref_rev)
240 org_ref = ('rev', org_ref_rev)
227 other_ref = ('rev', other_ref_rev)
241 other_ref = ('rev', other_ref_rev)
228
242
229 c.org_repo = org_repo
243 c.org_repo = org_repo
230 c.other_repo = other_repo
244 c.other_repo = other_repo
231
245
232 c.cs_ranges, discovery_data = PullRequestModel().get_compare_data(
246 c.cs_ranges, discovery_data = PullRequestModel().get_compare_data(
233 org_repo, org_ref, other_repo, other_ref
247 org_repo, org_ref, other_repo, other_ref
234 )
248 )
235
249
236 c.statuses = c.rhodecode_db_repo.statuses([x.raw_id for x in
250 c.statuses = c.rhodecode_db_repo.statuses([x.raw_id for x in
237 c.cs_ranges])
251 c.cs_ranges])
238 # defines that we need hidden inputs with changesets
252 # defines that we need hidden inputs with changesets
239 c.as_form = request.GET.get('as_form', False)
253 c.as_form = request.GET.get('as_form', False)
240
254
241 c.org_ref = org_ref[1]
255 c.org_ref = org_ref[1]
242 c.other_ref = other_ref[1]
256 c.other_ref = other_ref[1]
243 # diff needs to have swapped org with other to generate proper diff
257 # diff needs to have swapped org with other to generate proper diff
244 _diff = diffs.differ(other_repo, other_ref, org_repo, org_ref,
258 _diff = diffs.differ(other_repo, other_ref, org_repo, org_ref,
245 discovery_data)
259 discovery_data)
246 diff_processor = diffs.DiffProcessor(_diff, format='gitdiff')
260 diff_processor = diffs.DiffProcessor(_diff, format='gitdiff')
247 _parsed = diff_processor.prepare()
261 _parsed = diff_processor.prepare()
248
262
249 c.files = []
263 c.files = []
250 c.changes = {}
264 c.changes = {}
251
265
252 for f in _parsed:
266 for f in _parsed:
253 fid = h.FID('', f['filename'])
267 fid = h.FID('', f['filename'])
254 c.files.append([fid, f['operation'], f['filename'], f['stats']])
268 c.files.append([fid, f['operation'], f['filename'], f['stats']])
255 diff = diff_processor.as_html(enable_comments=enable_comments,
269 diff = diff_processor.as_html(enable_comments=enable_comments,
256 diff_lines=[f])
270 diff_lines=[f])
257 c.changes[fid] = [f['operation'], f['filename'], diff]
271 c.changes[fid] = [f['operation'], f['filename'], diff]
258
272
259 def show(self, repo_name, pull_request_id):
273 def show(self, repo_name, pull_request_id):
260 repo_model = RepoModel()
274 repo_model = RepoModel()
261 c.users_array = repo_model.get_users_js()
275 c.users_array = repo_model.get_users_js()
262 c.users_groups_array = repo_model.get_users_groups_js()
276 c.users_groups_array = repo_model.get_users_groups_js()
263 c.pull_request = PullRequest.get_or_404(pull_request_id)
277 c.pull_request = PullRequest.get_or_404(pull_request_id)
264
278
265 cc_model = ChangesetCommentsModel()
279 cc_model = ChangesetCommentsModel()
266 cs_model = ChangesetStatusModel()
280 cs_model = ChangesetStatusModel()
267 _cs_statuses = cs_model.get_statuses(c.pull_request.org_repo,
281 _cs_statuses = cs_model.get_statuses(c.pull_request.org_repo,
268 pull_request=c.pull_request,
282 pull_request=c.pull_request,
269 with_revisions=True)
283 with_revisions=True)
270
284
271 cs_statuses = defaultdict(list)
285 cs_statuses = defaultdict(list)
272 for st in _cs_statuses:
286 for st in _cs_statuses:
273 cs_statuses[st.author.username] += [st]
287 cs_statuses[st.author.username] += [st]
274
288
275 c.pull_request_reviewers = []
289 c.pull_request_reviewers = []
276 c.pull_request_pending_reviewers = []
290 c.pull_request_pending_reviewers = []
277 for o in c.pull_request.reviewers:
291 for o in c.pull_request.reviewers:
278 st = cs_statuses.get(o.user.username, None)
292 st = cs_statuses.get(o.user.username, None)
279 if st:
293 if st:
280 sorter = lambda k: k.version
294 sorter = lambda k: k.version
281 st = [(x, list(y)[0])
295 st = [(x, list(y)[0])
282 for x, y in (groupby(sorted(st, key=sorter), sorter))]
296 for x, y in (groupby(sorted(st, key=sorter), sorter))]
283 else:
297 else:
284 c.pull_request_pending_reviewers.append(o.user)
298 c.pull_request_pending_reviewers.append(o.user)
285 c.pull_request_reviewers.append([o.user, st])
299 c.pull_request_reviewers.append([o.user, st])
286
300
287 # pull_requests repo_name we opened it against
301 # pull_requests repo_name we opened it against
288 # ie. other_repo must match
302 # ie. other_repo must match
289 if repo_name != c.pull_request.other_repo.repo_name:
303 if repo_name != c.pull_request.other_repo.repo_name:
290 raise HTTPNotFound
304 raise HTTPNotFound
291
305
292 # load compare data into template context
306 # load compare data into template context
293 enable_comments = not c.pull_request.is_closed()
307 enable_comments = not c.pull_request.is_closed()
294 self._load_compare_data(c.pull_request, enable_comments=enable_comments)
308 self._load_compare_data(c.pull_request, enable_comments=enable_comments)
295
309
296 # inline comments
310 # inline comments
297 c.inline_cnt = 0
311 c.inline_cnt = 0
298 c.inline_comments = cc_model.get_inline_comments(
312 c.inline_comments = cc_model.get_inline_comments(
299 c.rhodecode_db_repo.repo_id,
313 c.rhodecode_db_repo.repo_id,
300 pull_request=pull_request_id)
314 pull_request=pull_request_id)
301 # count inline comments
315 # count inline comments
302 for __, lines in c.inline_comments:
316 for __, lines in c.inline_comments:
303 for comments in lines.values():
317 for comments in lines.values():
304 c.inline_cnt += len(comments)
318 c.inline_cnt += len(comments)
305 # comments
319 # comments
306 c.comments = cc_model.get_comments(c.rhodecode_db_repo.repo_id,
320 c.comments = cc_model.get_comments(c.rhodecode_db_repo.repo_id,
307 pull_request=pull_request_id)
321 pull_request=pull_request_id)
308
322
309 # changeset(pull-request) status
323 # changeset(pull-request) status
310 c.current_changeset_status = cs_model.calculate_status(
324 c.current_changeset_status = cs_model.calculate_status(
311 c.pull_request_reviewers
325 c.pull_request_reviewers
312 )
326 )
313 c.changeset_statuses = ChangesetStatus.STATUSES
327 c.changeset_statuses = ChangesetStatus.STATUSES
314 c.target_repo = c.pull_request.org_repo.repo_name
328 c.target_repo = c.pull_request.org_repo.repo_name
315 return render('/pullrequests/pullrequest_show.html')
329 return render('/pullrequests/pullrequest_show.html')
316
330
317 @NotAnonymous()
331 @NotAnonymous()
318 @jsonify
332 @jsonify
319 def comment(self, repo_name, pull_request_id):
333 def comment(self, repo_name, pull_request_id):
320 pull_request = PullRequest.get_or_404(pull_request_id)
334 pull_request = PullRequest.get_or_404(pull_request_id)
321 if pull_request.is_closed():
335 if pull_request.is_closed():
322 raise HTTPForbidden()
336 raise HTTPForbidden()
323
337
324 status = request.POST.get('changeset_status')
338 status = request.POST.get('changeset_status')
325 change_status = request.POST.get('change_changeset_status')
339 change_status = request.POST.get('change_changeset_status')
326
340
327 comm = ChangesetCommentsModel().create(
341 comm = ChangesetCommentsModel().create(
328 text=request.POST.get('text'),
342 text=request.POST.get('text'),
329 repo=c.rhodecode_db_repo.repo_id,
343 repo=c.rhodecode_db_repo.repo_id,
330 user=c.rhodecode_user.user_id,
344 user=c.rhodecode_user.user_id,
331 pull_request=pull_request_id,
345 pull_request=pull_request_id,
332 f_path=request.POST.get('f_path'),
346 f_path=request.POST.get('f_path'),
333 line_no=request.POST.get('line'),
347 line_no=request.POST.get('line'),
334 status_change=(ChangesetStatus.get_status_lbl(status)
348 status_change=(ChangesetStatus.get_status_lbl(status)
335 if status and change_status else None)
349 if status and change_status else None)
336 )
350 )
337
351
338 # get status if set !
352 # get status if set !
339 if status and change_status:
353 if status and change_status:
340 ChangesetStatusModel().set_status(
354 ChangesetStatusModel().set_status(
341 c.rhodecode_db_repo.repo_id,
355 c.rhodecode_db_repo.repo_id,
342 status,
356 status,
343 c.rhodecode_user.user_id,
357 c.rhodecode_user.user_id,
344 comm,
358 comm,
345 pull_request=pull_request_id
359 pull_request=pull_request_id
346 )
360 )
347 action_logger(self.rhodecode_user,
361 action_logger(self.rhodecode_user,
348 'user_commented_pull_request:%s' % pull_request_id,
362 'user_commented_pull_request:%s' % pull_request_id,
349 c.rhodecode_db_repo, self.ip_addr, self.sa)
363 c.rhodecode_db_repo, self.ip_addr, self.sa)
350
364
351 if request.POST.get('save_close'):
365 if request.POST.get('save_close'):
352 PullRequestModel().close_pull_request(pull_request_id)
366 PullRequestModel().close_pull_request(pull_request_id)
353 action_logger(self.rhodecode_user,
367 action_logger(self.rhodecode_user,
354 'user_closed_pull_request:%s' % pull_request_id,
368 'user_closed_pull_request:%s' % pull_request_id,
355 c.rhodecode_db_repo, self.ip_addr, self.sa)
369 c.rhodecode_db_repo, self.ip_addr, self.sa)
356
370
357 Session().commit()
371 Session().commit()
358
372
359 if not request.environ.get('HTTP_X_PARTIAL_XHR'):
373 if not request.environ.get('HTTP_X_PARTIAL_XHR'):
360 return redirect(h.url('pullrequest_show', repo_name=repo_name,
374 return redirect(h.url('pullrequest_show', repo_name=repo_name,
361 pull_request_id=pull_request_id))
375 pull_request_id=pull_request_id))
362
376
363 data = {
377 data = {
364 'target_id': h.safeid(h.safe_unicode(request.POST.get('f_path'))),
378 'target_id': h.safeid(h.safe_unicode(request.POST.get('f_path'))),
365 }
379 }
366 if comm:
380 if comm:
367 c.co = comm
381 c.co = comm
368 data.update(comm.get_dict())
382 data.update(comm.get_dict())
369 data.update({'rendered_text':
383 data.update({'rendered_text':
370 render('changeset/changeset_comment_block.html')})
384 render('changeset/changeset_comment_block.html')})
371
385
372 return data
386 return data
373
387
374 @NotAnonymous()
388 @NotAnonymous()
375 @jsonify
389 @jsonify
376 def delete_comment(self, repo_name, comment_id):
390 def delete_comment(self, repo_name, comment_id):
377 co = ChangesetComment.get(comment_id)
391 co = ChangesetComment.get(comment_id)
378 if co.pull_request.is_closed():
392 if co.pull_request.is_closed():
379 #don't allow deleting comments on closed pull request
393 #don't allow deleting comments on closed pull request
380 raise HTTPForbidden()
394 raise HTTPForbidden()
381
395
382 owner = lambda: co.author.user_id == c.rhodecode_user.user_id
396 owner = lambda: co.author.user_id == c.rhodecode_user.user_id
383 if h.HasPermissionAny('hg.admin', 'repository.admin')() or owner:
397 if h.HasPermissionAny('hg.admin', 'repository.admin')() or owner:
384 ChangesetCommentsModel().delete(comment=co)
398 ChangesetCommentsModel().delete(comment=co)
385 Session().commit()
399 Session().commit()
386 return True
400 return True
387 else:
401 else:
388 raise HTTPForbidden()
402 raise HTTPForbidden()
@@ -1,245 +1,249
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.model.pull_request
3 rhodecode.model.pull_request
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5
5
6 pull request model for RhodeCode
6 pull request model for RhodeCode
7
7
8 :created_on: Jun 6, 2012
8 :created_on: Jun 6, 2012
9 :author: marcink
9 :author: marcink
10 :copyright: (C) 2012-2012 Marcin Kuzminski <marcin@python-works.com>
10 :copyright: (C) 2012-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 binascii
27 import binascii
28 import datetime
28 import datetime
29
29
30 from pylons.i18n.translation import _
30 from pylons.i18n.translation import _
31
31
32 from rhodecode.model.meta import Session
32 from rhodecode.model.meta import Session
33 from rhodecode.lib import helpers as h
33 from rhodecode.lib import helpers as h
34 from rhodecode.model import BaseModel
34 from rhodecode.model import BaseModel
35 from rhodecode.model.db import PullRequest, PullRequestReviewers, Notification
35 from rhodecode.model.db import PullRequest, PullRequestReviewers, Notification
36 from rhodecode.model.notification import NotificationModel
36 from rhodecode.model.notification import NotificationModel
37 from rhodecode.lib.utils2 import safe_unicode
37 from rhodecode.lib.utils2 import safe_unicode
38
38
39 from rhodecode.lib.vcs.utils.hgcompat import discovery, localrepo, scmutil
39 from rhodecode.lib.vcs.utils.hgcompat import discovery, localrepo, scmutil
40
40
41 log = logging.getLogger(__name__)
41 log = logging.getLogger(__name__)
42
42
43
43
44 class PullRequestModel(BaseModel):
44 class PullRequestModel(BaseModel):
45
45
46 cls = PullRequest
46 cls = PullRequest
47
47
48 def __get_pull_request(self, pull_request):
48 def __get_pull_request(self, pull_request):
49 return self._get_instance(PullRequest, pull_request)
49 return self._get_instance(PullRequest, pull_request)
50
50
51 def get_all(self, repo):
51 def get_all(self, repo):
52 repo = self._get_repo(repo)
52 repo = self._get_repo(repo)
53 return PullRequest.query().filter(PullRequest.other_repo == repo).all()
53 return PullRequest.query().filter(PullRequest.other_repo == repo).all()
54
54
55 def create(self, created_by, org_repo, org_ref, other_repo,
55 def create(self, created_by, org_repo, org_ref, other_repo,
56 other_ref, revisions, reviewers, title, description=None):
56 other_ref, revisions, reviewers, title, description=None):
57
57
58 created_by_user = self._get_user(created_by)
58 created_by_user = self._get_user(created_by)
59 org_repo = self._get_repo(org_repo)
59 org_repo = self._get_repo(org_repo)
60 other_repo = self._get_repo(other_repo)
60 other_repo = self._get_repo(other_repo)
61
61
62 new = PullRequest()
62 new = PullRequest()
63 new.org_repo = org_repo
63 new.org_repo = org_repo
64 new.org_ref = org_ref
64 new.org_ref = org_ref
65 new.other_repo = other_repo
65 new.other_repo = other_repo
66 new.other_ref = other_ref
66 new.other_ref = other_ref
67 new.revisions = revisions
67 new.revisions = revisions
68 new.title = title
68 new.title = title
69 new.description = description
69 new.description = description
70 new.author = created_by_user
70 new.author = created_by_user
71 self.sa.add(new)
71 self.sa.add(new)
72 Session().flush()
72 Session().flush()
73 #members
73 #members
74 for member in reviewers:
74 for member in reviewers:
75 _usr = self._get_user(member)
75 _usr = self._get_user(member)
76 reviewer = PullRequestReviewers(_usr, new)
76 reviewer = PullRequestReviewers(_usr, new)
77 self.sa.add(reviewer)
77 self.sa.add(reviewer)
78
78
79 #notification to reviewers
79 #notification to reviewers
80 notif = NotificationModel()
80 notif = NotificationModel()
81
81
82 subject = safe_unicode(
82 subject = safe_unicode(
83 h.link_to(
83 h.link_to(
84 _('%(user)s wants you to review pull request #%(pr_id)s') % \
84 _('%(user)s wants you to review pull request #%(pr_id)s') % \
85 {'user': created_by_user.username,
85 {'user': created_by_user.username,
86 'pr_id': new.pull_request_id},
86 'pr_id': new.pull_request_id},
87 h.url('pullrequest_show', repo_name=other_repo.repo_name,
87 h.url('pullrequest_show', repo_name=other_repo.repo_name,
88 pull_request_id=new.pull_request_id,
88 pull_request_id=new.pull_request_id,
89 qualified=True,
89 qualified=True,
90 )
90 )
91 )
91 )
92 )
92 )
93 body = description
93 body = description
94 notif.create(created_by=created_by_user, subject=subject, body=body,
94 notif.create(created_by=created_by_user, subject=subject, body=body,
95 recipients=reviewers,
95 recipients=reviewers,
96 type_=Notification.TYPE_PULL_REQUEST,)
96 type_=Notification.TYPE_PULL_REQUEST,)
97
97
98 return new
98 return new
99
99
100 def update_reviewers(self, pull_request, reviewers_ids):
100 def update_reviewers(self, pull_request, reviewers_ids):
101 reviewers_ids = set(reviewers_ids)
101 reviewers_ids = set(reviewers_ids)
102 pull_request = self.__get_pull_request(pull_request)
102 pull_request = self.__get_pull_request(pull_request)
103 current_reviewers = PullRequestReviewers.query()\
103 current_reviewers = PullRequestReviewers.query()\
104 .filter(PullRequestReviewers.pull_request==
104 .filter(PullRequestReviewers.pull_request==
105 pull_request)\
105 pull_request)\
106 .all()
106 .all()
107 current_reviewers_ids = set([x.user.user_id for x in current_reviewers])
107 current_reviewers_ids = set([x.user.user_id for x in current_reviewers])
108
108
109 to_add = reviewers_ids.difference(current_reviewers_ids)
109 to_add = reviewers_ids.difference(current_reviewers_ids)
110 to_remove = current_reviewers_ids.difference(reviewers_ids)
110 to_remove = current_reviewers_ids.difference(reviewers_ids)
111
111
112 log.debug("Adding %s reviewers" % to_add)
112 log.debug("Adding %s reviewers" % to_add)
113 log.debug("Removing %s reviewers" % to_remove)
113 log.debug("Removing %s reviewers" % to_remove)
114
114
115 for uid in to_add:
115 for uid in to_add:
116 _usr = self._get_user(uid)
116 _usr = self._get_user(uid)
117 reviewer = PullRequestReviewers(_usr, pull_request)
117 reviewer = PullRequestReviewers(_usr, pull_request)
118 self.sa.add(reviewer)
118 self.sa.add(reviewer)
119
119
120 for uid in to_remove:
120 for uid in to_remove:
121 reviewer = PullRequestReviewers.query()\
121 reviewer = PullRequestReviewers.query()\
122 .filter(PullRequestReviewers.user_id==uid,
122 .filter(PullRequestReviewers.user_id==uid,
123 PullRequestReviewers.pull_request==pull_request)\
123 PullRequestReviewers.pull_request==pull_request)\
124 .scalar()
124 .scalar()
125 if reviewer:
125 if reviewer:
126 self.sa.delete(reviewer)
126 self.sa.delete(reviewer)
127
127
128 def delete(self, pull_request):
129 pull_request = self.__get_pull_request(pull_request)
130 Session().delete(pull_request)
131
128 def close_pull_request(self, pull_request):
132 def close_pull_request(self, pull_request):
129 pull_request = self.__get_pull_request(pull_request)
133 pull_request = self.__get_pull_request(pull_request)
130 pull_request.status = PullRequest.STATUS_CLOSED
134 pull_request.status = PullRequest.STATUS_CLOSED
131 pull_request.updated_on = datetime.datetime.now()
135 pull_request.updated_on = datetime.datetime.now()
132 self.sa.add(pull_request)
136 self.sa.add(pull_request)
133
137
134 def _get_changesets(self, org_repo, org_ref, other_repo, other_ref,
138 def _get_changesets(self, org_repo, org_ref, other_repo, other_ref,
135 discovery_data):
139 discovery_data):
136 """
140 """
137 Returns a list of changesets that are incoming from org_repo@org_ref
141 Returns a list of changesets that are incoming from org_repo@org_ref
138 to other_repo@other_ref
142 to other_repo@other_ref
139
143
140 :param org_repo:
144 :param org_repo:
141 :type org_repo:
145 :type org_repo:
142 :param org_ref:
146 :param org_ref:
143 :type org_ref:
147 :type org_ref:
144 :param other_repo:
148 :param other_repo:
145 :type other_repo:
149 :type other_repo:
146 :param other_ref:
150 :param other_ref:
147 :type other_ref:
151 :type other_ref:
148 :param tmp:
152 :param tmp:
149 :type tmp:
153 :type tmp:
150 """
154 """
151 changesets = []
155 changesets = []
152 #case two independent repos
156 #case two independent repos
153 common, incoming, rheads = discovery_data
157 common, incoming, rheads = discovery_data
154 if org_repo != other_repo and incoming:
158 if org_repo != other_repo and incoming:
155 revs = org_repo._repo.changelog.findmissing(common, rheads)
159 revs = org_repo._repo.changelog.findmissing(common, rheads)
156
160
157 for cs in reversed(map(binascii.hexlify, revs)):
161 for cs in reversed(map(binascii.hexlify, revs)):
158 changesets.append(org_repo.get_changeset(cs))
162 changesets.append(org_repo.get_changeset(cs))
159 else:
163 else:
160 _revset_predicates = {
164 _revset_predicates = {
161 'branch': 'branch',
165 'branch': 'branch',
162 'book': 'bookmark',
166 'book': 'bookmark',
163 'tag': 'tag',
167 'tag': 'tag',
164 'rev': 'id',
168 'rev': 'id',
165 }
169 }
166
170
167 revs = [
171 revs = [
168 "ancestors(%s('%s')) and not ancestors(%s('%s'))" % (
172 "ancestors(%s('%s')) and not ancestors(%s('%s'))" % (
169 _revset_predicates[org_ref[0]], org_ref[1],
173 _revset_predicates[org_ref[0]], org_ref[1],
170 _revset_predicates[other_ref[0]], other_ref[1]
174 _revset_predicates[other_ref[0]], other_ref[1]
171 )
175 )
172 ]
176 ]
173
177
174 out = scmutil.revrange(org_repo._repo, revs)
178 out = scmutil.revrange(org_repo._repo, revs)
175 for cs in reversed(out):
179 for cs in reversed(out):
176 changesets.append(org_repo.get_changeset(cs))
180 changesets.append(org_repo.get_changeset(cs))
177
181
178 return changesets
182 return changesets
179
183
180 def _get_discovery(self, org_repo, org_ref, other_repo, other_ref):
184 def _get_discovery(self, org_repo, org_ref, other_repo, other_ref):
181 """
185 """
182 Get's mercurial discovery data used to calculate difference between
186 Get's mercurial discovery data used to calculate difference between
183 repos and refs
187 repos and refs
184
188
185 :param org_repo:
189 :param org_repo:
186 :type org_repo:
190 :type org_repo:
187 :param org_ref:
191 :param org_ref:
188 :type org_ref:
192 :type org_ref:
189 :param other_repo:
193 :param other_repo:
190 :type other_repo:
194 :type other_repo:
191 :param other_ref:
195 :param other_ref:
192 :type other_ref:
196 :type other_ref:
193 """
197 """
194
198
195 _org_repo = org_repo._repo
199 _org_repo = org_repo._repo
196 org_rev_type, org_rev = org_ref
200 org_rev_type, org_rev = org_ref
197
201
198 _other_repo = other_repo._repo
202 _other_repo = other_repo._repo
199 other_rev_type, other_rev = other_ref
203 other_rev_type, other_rev = other_ref
200
204
201 log.debug('Doing discovery for %s@%s vs %s@%s' % (
205 log.debug('Doing discovery for %s@%s vs %s@%s' % (
202 org_repo, org_ref, other_repo, other_ref)
206 org_repo, org_ref, other_repo, other_ref)
203 )
207 )
204 #log.debug('Filter heads are %s[%s]' % ('', org_ref[1]))
208 #log.debug('Filter heads are %s[%s]' % ('', org_ref[1]))
205 org_peer = localrepo.locallegacypeer(_org_repo.local())
209 org_peer = localrepo.locallegacypeer(_org_repo.local())
206 tmp = discovery.findcommonincoming(
210 tmp = discovery.findcommonincoming(
207 repo=_other_repo, # other_repo we check for incoming
211 repo=_other_repo, # other_repo we check for incoming
208 remote=org_peer, # org_repo source for incoming
212 remote=org_peer, # org_repo source for incoming
209 heads=[_other_repo[other_rev].node(),
213 heads=[_other_repo[other_rev].node(),
210 _org_repo[org_rev].node()],
214 _org_repo[org_rev].node()],
211 force=False
215 force=False
212 )
216 )
213 return tmp
217 return tmp
214
218
215 def get_compare_data(self, org_repo, org_ref, other_repo, other_ref):
219 def get_compare_data(self, org_repo, org_ref, other_repo, other_ref):
216 """
220 """
217 Returns a tuple of incomming changesets, and discoverydata cache
221 Returns a tuple of incomming changesets, and discoverydata cache
218
222
219 :param org_repo:
223 :param org_repo:
220 :type org_repo:
224 :type org_repo:
221 :param org_ref:
225 :param org_ref:
222 :type org_ref:
226 :type org_ref:
223 :param other_repo:
227 :param other_repo:
224 :type other_repo:
228 :type other_repo:
225 :param other_ref:
229 :param other_ref:
226 :type other_ref:
230 :type other_ref:
227 """
231 """
228
232
229 if len(org_ref) != 2 or not isinstance(org_ref, (list, tuple)):
233 if len(org_ref) != 2 or not isinstance(org_ref, (list, tuple)):
230 raise Exception('org_ref must be a two element list/tuple')
234 raise Exception('org_ref must be a two element list/tuple')
231
235
232 if len(other_ref) != 2 or not isinstance(org_ref, (list, tuple)):
236 if len(other_ref) != 2 or not isinstance(org_ref, (list, tuple)):
233 raise Exception('other_ref must be a two element list/tuple')
237 raise Exception('other_ref must be a two element list/tuple')
234
238
235 discovery_data = self._get_discovery(org_repo.scm_instance,
239 discovery_data = self._get_discovery(org_repo.scm_instance,
236 org_ref,
240 org_ref,
237 other_repo.scm_instance,
241 other_repo.scm_instance,
238 other_ref)
242 other_ref)
239 cs_ranges = self._get_changesets(org_repo.scm_instance,
243 cs_ranges = self._get_changesets(org_repo.scm_instance,
240 org_ref,
244 org_ref,
241 other_repo.scm_instance,
245 other_repo.scm_instance,
242 other_ref,
246 other_ref,
243 discovery_data)
247 discovery_data)
244
248
245 return cs_ranges, discovery_data
249 return cs_ranges, discovery_data
@@ -1,30 +1,37
1
1
2 <div class="pullrequests_section_head">${_('Opened by me')}</div>
2 <div class="pullrequests_section_head">${_('Opened by me')}</div>
3 <ul>
3 <ul>
4 %if c.my_pull_requests:
4 %if c.my_pull_requests:
5 %for pull_request in c.my_pull_requests:
5 %for pull_request in c.my_pull_requests:
6 <li>
6 <li>
7 <div style="float:left">
7 <a href="${h.url('pullrequest_show',repo_name=pull_request.other_repo.repo_name,pull_request_id=pull_request.pull_request_id)}">
8 <a href="${h.url('pullrequest_show',repo_name=pull_request.other_repo.repo_name,pull_request_id=pull_request.pull_request_id)}">
8 ${_('Pull request #%s opened on %s') % (pull_request.pull_request_id, h.fmt_date(pull_request.created_on))}
9 ${_('Pull request #%s opened on %s') % (pull_request.pull_request_id, h.fmt_date(pull_request.created_on))}
9 </a>
10 </a>
11 </div>
12 <div style="float:left;margin-top: -5px">
13 ${h.form(url('pullrequest_delete', repo_name=pull_request.other_repo.repo_name, pull_request_id=pull_request.pull_request_id),method='delete')}
14 ${h.submit('remove_%s' % pull_request.pull_request_id,'',class_="delete_icon action_button",onclick="return confirm('"+_('Confirm to delete this pull request')+"');")}
15 ${h.end_form()}
16 </div>
10 </li>
17 </li>
11 %endfor
18 %endfor
12 %else:
19 %else:
13 <li><span class="empty_data">${_('Nothing here yet')}</span></li>
20 <li><span class="empty_data">${_('Nothing here yet')}</span></li>
14 %endif
21 %endif
15 </ul>
22 </ul>
16
23
17 <div class="pullrequests_section_head">${_('I participate in')}</div>
24 <div class="pullrequests_section_head" style="clear:both">${_('I participate in')}</div>
18 <ul>
25 <ul>
19 %if c.my_pull_requests:
26 %if c.my_pull_requests:
20 %for pull_request in c.participate_in_pull_requests:
27 %for pull_request in c.participate_in_pull_requests:
21 <li>
28 <li>
22 <a href="${h.url('pullrequest_show',repo_name=pull_request.other_repo.repo_name,pull_request_id=pull_request.pull_request_id)}">
29 <a href="${h.url('pullrequest_show',repo_name=pull_request.other_repo.repo_name,pull_request_id=pull_request.pull_request_id)}">
23 ${_('Pull request #%s opened by %s on %s') % (pull_request.pull_request_id, pull_request.author.full_name, h.fmt_date(pull_request.created_on))}
30 ${_('Pull request #%s opened by %s on %s') % (pull_request.pull_request_id, pull_request.author.full_name, h.fmt_date(pull_request.created_on))}
24 </a>
31 </a>
25 </li>
32 </li>
26 %endfor
33 %endfor
27 %else:
34 %else:
28 <li><span class="empty_data">${_('Nothing here yet')}</span></li>
35 <li><span class="empty_data">${_('Nothing here yet')}</span></li>
29 %endif
36 %endif
30 </ul>
37 </ul>
General Comments 0
You need to be logged in to leave comments. Login now