##// END OF EJS Templates
file-store: changed for stream upload endpoint.
milka -
r4611:29d668ad stable
parent child Browse files
Show More

The requested changes are too big and content was truncated. Show full diff

@@ -1,261 +1,269 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2016-2020 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
7 7 # (only), as published by the Free Software Foundation.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU Affero General Public License
15 15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 16 #
17 17 # This program is dual-licensed. If you wish to learn more about the
18 18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 20
21 21 import os
22 22 import time
23 23 import errno
24 import shutil
25 24 import hashlib
26 25
27 26 from rhodecode.lib.ext_json import json
28 27 from rhodecode.apps.file_store import utils
29 28 from rhodecode.apps.file_store.extensions import resolve_extensions
30 29 from rhodecode.apps.file_store.exceptions import (
31 30 FileNotAllowedException, FileOverSizeException)
32 31
33 32 METADATA_VER = 'v1'
34 33
35 34
36 35 def safe_make_dirs(dir_path):
37 36 if not os.path.exists(dir_path):
38 37 try:
39 38 os.makedirs(dir_path)
40 39 except OSError as e:
41 40 if e.errno != errno.EEXIST:
42 41 raise
43 42 return
44 43
45 44
46 45 class LocalFileStorage(object):
47 46
48 47 @classmethod
49 48 def apply_counter(cls, counter, filename):
50 49 name_counted = '%d-%s' % (counter, filename)
51 50 return name_counted
52 51
53 52 @classmethod
54 53 def resolve_name(cls, name, directory):
55 54 """
56 55 Resolves a unique name and the correct path. If a filename
57 56 for that path already exists then a numeric prefix with values > 0 will be
58 57 added, for example test.jpg -> 1-test.jpg etc. initially file would have 0 prefix.
59 58
60 59 :param name: base name of file
61 60 :param directory: absolute directory path
62 61 """
63 62
64 63 counter = 0
65 64 while True:
66 65 name_counted = cls.apply_counter(counter, name)
67 66
68 67 # sub_store prefix to optimize disk usage, e.g some_path/ab/final_file
69 68 sub_store = cls._sub_store_from_filename(name_counted)
70 69 sub_store_path = os.path.join(directory, sub_store)
71 70 safe_make_dirs(sub_store_path)
72 71
73 72 path = os.path.join(sub_store_path, name_counted)
74 73 if not os.path.exists(path):
75 74 return name_counted, path
76 75 counter += 1
77 76
78 77 @classmethod
79 78 def _sub_store_from_filename(cls, filename):
80 79 return filename[:2]
81 80
82 81 @classmethod
83 82 def calculate_path_hash(cls, file_path):
84 83 """
85 84 Efficient calculation of file_path sha256 sum
86 85
87 86 :param file_path:
88 87 :return: sha256sum
89 88 """
90 89 digest = hashlib.sha256()
91 90 with open(file_path, 'rb') as f:
92 91 for chunk in iter(lambda: f.read(1024 * 100), b""):
93 92 digest.update(chunk)
94 93
95 94 return digest.hexdigest()
96 95
97 96 def __init__(self, base_path, extension_groups=None):
98 97
99 98 """
100 99 Local file storage
101 100
102 101 :param base_path: the absolute base path where uploads are stored
103 102 :param extension_groups: extensions string
104 103 """
105 104
106 105 extension_groups = extension_groups or ['any']
107 106 self.base_path = base_path
108 107 self.extensions = resolve_extensions([], groups=extension_groups)
109 108
110 109 def __repr__(self):
111 110 return '{}@{}'.format(self.__class__, self.base_path)
112 111
113 112 def store_path(self, filename):
114 113 """
115 114 Returns absolute file path of the filename, joined to the
116 115 base_path.
117 116
118 117 :param filename: base name of file
119 118 """
120 119 prefix_dir = ''
121 120 if '/' in filename:
122 121 prefix_dir, filename = filename.split('/')
123 122 sub_store = self._sub_store_from_filename(filename)
124 123 else:
125 124 sub_store = self._sub_store_from_filename(filename)
126 125 return os.path.join(self.base_path, prefix_dir, sub_store, filename)
127 126
128 127 def delete(self, filename):
129 128 """
130 129 Deletes the filename. Filename is resolved with the
131 130 absolute path based on base_path. If file does not exist,
132 131 returns **False**, otherwise **True**
133 132
134 133 :param filename: base name of file
135 134 """
136 135 if self.exists(filename):
137 136 os.remove(self.store_path(filename))
138 137 return True
139 138 return False
140 139
141 140 def exists(self, filename):
142 141 """
143 142 Checks if file exists. Resolves filename's absolute
144 143 path based on base_path.
145 144
146 145 :param filename: file_uid name of file, e.g 0-f62b2b2d-9708-4079-a071-ec3f958448d4.svg
147 146 """
148 147 return os.path.exists(self.store_path(filename))
149 148
150 149 def filename_allowed(self, filename, extensions=None):
151 150 """Checks if a filename has an allowed extension
152 151
153 152 :param filename: base name of file
154 153 :param extensions: iterable of extensions (or self.extensions)
155 154 """
156 155 _, ext = os.path.splitext(filename)
157 156 return self.extension_allowed(ext, extensions)
158 157
159 158 def extension_allowed(self, ext, extensions=None):
160 159 """
161 160 Checks if an extension is permitted. Both e.g. ".jpg" and
162 161 "jpg" can be passed in. Extension lookup is case-insensitive.
163 162
164 163 :param ext: extension to check
165 164 :param extensions: iterable of extensions to validate against (or self.extensions)
166 165 """
167 166 def normalize_ext(_ext):
168 167 if _ext.startswith('.'):
169 168 _ext = _ext[1:]
170 169 return _ext.lower()
171 170
172 171 extensions = extensions or self.extensions
173 172 if not extensions:
174 173 return True
175 174
176 175 ext = normalize_ext(ext)
177 176
178 177 return ext in [normalize_ext(x) for x in extensions]
179 178
180 179 def save_file(self, file_obj, filename, directory=None, extensions=None,
181 180 extra_metadata=None, max_filesize=None, randomized_name=True, **kwargs):
182 181 """
183 182 Saves a file object to the uploads location.
184 183 Returns the resolved filename, i.e. the directory +
185 184 the (randomized/incremented) base name.
186 185
187 186 :param file_obj: **cgi.FieldStorage** object (or similar)
188 187 :param filename: original filename
189 188 :param directory: relative path of sub-directory
190 189 :param extensions: iterable of allowed extensions, if not default
191 190 :param max_filesize: maximum size of file that should be allowed
192 191 :param randomized_name: generate random generated UID or fixed based on the filename
193 192 :param extra_metadata: extra JSON metadata to store next to the file with .meta suffix
194 193
195 194 """
196 195
197 196 extensions = extensions or self.extensions
198 197
199 198 if not self.filename_allowed(filename, extensions):
200 199 raise FileNotAllowedException()
201 200
202 201 if directory:
203 202 dest_directory = os.path.join(self.base_path, directory)
204 203 else:
205 204 dest_directory = self.base_path
206 205
207 206 safe_make_dirs(dest_directory)
208 207
209 208 uid_filename = utils.uid_filename(filename, randomized=randomized_name)
210 209
211 210 # resolve also produces special sub-dir for file optimized store
212 211 filename, path = self.resolve_name(uid_filename, dest_directory)
213 212 stored_file_dir = os.path.dirname(path)
214 213
215 file_obj.seek(0)
214 no_body_seek = kwargs.pop('no_body_seek', False)
215 if no_body_seek:
216 pass
217 else:
218 file_obj.seek(0)
216 219
217 220 with open(path, "wb") as dest:
218 shutil.copyfileobj(file_obj, dest)
221 length = 256 * 1024
222 while 1:
223 buf = file_obj.read(length)
224 if not buf:
225 break
226 dest.write(buf)
219 227
220 228 metadata = {}
221 229 if extra_metadata:
222 230 metadata = extra_metadata
223 231
224 232 size = os.stat(path).st_size
225 233
226 234 if max_filesize and size > max_filesize:
227 235 # free up the copied file, and raise exc
228 236 os.remove(path)
229 237 raise FileOverSizeException()
230 238
231 239 file_hash = self.calculate_path_hash(path)
232 240
233 241 metadata.update({
234 242 "filename": filename,
235 243 "size": size,
236 244 "time": time.time(),
237 245 "sha256": file_hash,
238 246 "meta_ver": METADATA_VER
239 247 })
240 248
241 249 filename_meta = filename + '.meta'
242 250 with open(os.path.join(stored_file_dir, filename_meta), "wb") as dest_meta:
243 251 dest_meta.write(json.dumps(metadata))
244 252
245 253 if directory:
246 254 filename = os.path.join(directory, filename)
247 255
248 256 return filename, metadata
249 257
250 258 def get_metadata(self, filename):
251 259 """
252 260 Reads JSON stored metadata for a file
253 261
254 262 :param filename:
255 263 :return:
256 264 """
257 265 filename = self.store_path(filename)
258 266 filename_meta = filename + '.meta'
259 267
260 268 with open(filename_meta, "rb") as source_meta:
261 269 return json.loads(source_meta.read())
@@ -1,37 +1,40 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2010-2020 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
7 7 # (only), as published by the Free Software Foundation.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU Affero General Public License
15 15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 16 #
17 17 # This program is dual-licensed. If you wish to learn more about the
18 18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 20
21 21 from rhodecode.lib.ext_json import json
22 22
23 23
24 24 def pyramid_ext_json(info):
25 25 """
26 26 Custom json renderer for pyramid to use our ext_json lib
27 27 """
28 28 def _render(value, system):
29 29 request = system.get('request')
30 indent = None
30 31 if request is not None:
31 32 response = request.response
32 33 ct = response.content_type
33 34 if ct == response.default_content_type:
34 35 response.content_type = 'application/json'
35 return json.dumps(value)
36 indent = getattr(request, 'ext_json_indent', None)
37
38 return json.dumps(value, indent=indent)
36 39
37 40 return _render
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
@@ -1,884 +1,887 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2011-2020 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
7 7 # (only), as published by the Free Software Foundation.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU Affero General Public License
15 15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 16 #
17 17 # This program is dual-licensed. If you wish to learn more about the
18 18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 20
21 21
22 22 """
23 23 repo group model for RhodeCode
24 24 """
25 25
26 26 import os
27 27 import datetime
28 28 import itertools
29 29 import logging
30 30 import shutil
31 31 import time
32 32 import traceback
33 33 import string
34 34
35 35 from zope.cachedescriptors.property import Lazy as LazyProperty
36 36
37 37 from rhodecode import events
38 38 from rhodecode.model import BaseModel
39 39 from rhodecode.model.db import (_hash_key, func, or_, in_filter_generator,
40 40 Session, RepoGroup, UserRepoGroupToPerm, User, Permission, UserGroupRepoGroupToPerm,
41 41 UserGroup, Repository)
42 42 from rhodecode.model.settings import VcsSettingsModel, SettingsModel
43 43 from rhodecode.lib.caching_query import FromCache
44 44 from rhodecode.lib.utils2 import action_logger_generic
45 45
46 46 log = logging.getLogger(__name__)
47 47
48 48
49 49 class RepoGroupModel(BaseModel):
50 50
51 51 cls = RepoGroup
52 52 PERSONAL_GROUP_DESC = 'personal repo group of user `%(username)s`'
53 53 PERSONAL_GROUP_PATTERN = '${username}' # default
54 54
55 55 def _get_user_group(self, users_group):
56 56 return self._get_instance(UserGroup, users_group,
57 57 callback=UserGroup.get_by_group_name)
58 58
59 59 def _get_repo_group(self, repo_group):
60 60 return self._get_instance(RepoGroup, repo_group,
61 61 callback=RepoGroup.get_by_group_name)
62 62
63 def get_repo_group(self, repo_group):
64 return self._get_repo_group(repo_group)
65
63 66 @LazyProperty
64 67 def repos_path(self):
65 68 """
66 69 Gets the repositories root path from database
67 70 """
68 71
69 72 settings_model = VcsSettingsModel(sa=self.sa)
70 73 return settings_model.get_repos_location()
71 74
72 75 def get_by_group_name(self, repo_group_name, cache=None):
73 76 repo = self.sa.query(RepoGroup) \
74 77 .filter(RepoGroup.group_name == repo_group_name)
75 78
76 79 if cache:
77 80 name_key = _hash_key(repo_group_name)
78 81 repo = repo.options(
79 82 FromCache("sql_cache_short", "get_repo_group_%s" % name_key))
80 83 return repo.scalar()
81 84
82 85 def get_default_create_personal_repo_group(self):
83 86 value = SettingsModel().get_setting_by_name(
84 87 'create_personal_repo_group')
85 88 return value.app_settings_value if value else None or False
86 89
87 90 def get_personal_group_name_pattern(self):
88 91 value = SettingsModel().get_setting_by_name(
89 92 'personal_repo_group_pattern')
90 93 val = value.app_settings_value if value else None
91 94 group_template = val or self.PERSONAL_GROUP_PATTERN
92 95
93 96 group_template = group_template.lstrip('/')
94 97 return group_template
95 98
96 99 def get_personal_group_name(self, user):
97 100 template = self.get_personal_group_name_pattern()
98 101 return string.Template(template).safe_substitute(
99 102 username=user.username,
100 103 user_id=user.user_id,
101 104 first_name=user.first_name,
102 105 last_name=user.last_name,
103 106 )
104 107
105 108 def create_personal_repo_group(self, user, commit_early=True):
106 109 desc = self.PERSONAL_GROUP_DESC % {'username': user.username}
107 110 personal_repo_group_name = self.get_personal_group_name(user)
108 111
109 112 # create a new one
110 113 RepoGroupModel().create(
111 114 group_name=personal_repo_group_name,
112 115 group_description=desc,
113 116 owner=user.username,
114 117 personal=True,
115 118 commit_early=commit_early)
116 119
117 120 def _create_default_perms(self, new_group):
118 121 # create default permission
119 122 default_perm = 'group.read'
120 123 def_user = User.get_default_user()
121 124 for p in def_user.user_perms:
122 125 if p.permission.permission_name.startswith('group.'):
123 126 default_perm = p.permission.permission_name
124 127 break
125 128
126 129 repo_group_to_perm = UserRepoGroupToPerm()
127 130 repo_group_to_perm.permission = Permission.get_by_key(default_perm)
128 131
129 132 repo_group_to_perm.group = new_group
130 133 repo_group_to_perm.user_id = def_user.user_id
131 134 return repo_group_to_perm
132 135
133 136 def _get_group_name_and_parent(self, group_name_full, repo_in_path=False,
134 137 get_object=False):
135 138 """
136 139 Get's the group name and a parent group name from given group name.
137 140 If repo_in_path is set to truth, we asume the full path also includes
138 141 repo name, in such case we clean the last element.
139 142
140 143 :param group_name_full:
141 144 """
142 145 split_paths = 1
143 146 if repo_in_path:
144 147 split_paths = 2
145 148 _parts = group_name_full.rsplit(RepoGroup.url_sep(), split_paths)
146 149
147 150 if repo_in_path and len(_parts) > 1:
148 151 # such case last element is the repo_name
149 152 _parts.pop(-1)
150 153 group_name_cleaned = _parts[-1] # just the group name
151 154 parent_repo_group_name = None
152 155
153 156 if len(_parts) > 1:
154 157 parent_repo_group_name = _parts[0]
155 158
156 159 parent_group = None
157 160 if parent_repo_group_name:
158 161 parent_group = RepoGroup.get_by_group_name(parent_repo_group_name)
159 162
160 163 if get_object:
161 164 return group_name_cleaned, parent_repo_group_name, parent_group
162 165
163 166 return group_name_cleaned, parent_repo_group_name
164 167
165 168 def check_exist_filesystem(self, group_name, exc_on_failure=True):
166 169 create_path = os.path.join(self.repos_path, group_name)
167 170 log.debug('creating new group in %s', create_path)
168 171
169 172 if os.path.isdir(create_path):
170 173 if exc_on_failure:
171 174 abs_create_path = os.path.abspath(create_path)
172 175 raise Exception('Directory `{}` already exists !'.format(abs_create_path))
173 176 return False
174 177 return True
175 178
176 179 def _create_group(self, group_name):
177 180 """
178 181 makes repository group on filesystem
179 182
180 183 :param repo_name:
181 184 :param parent_id:
182 185 """
183 186
184 187 self.check_exist_filesystem(group_name)
185 188 create_path = os.path.join(self.repos_path, group_name)
186 189 log.debug('creating new group in %s', create_path)
187 190 os.makedirs(create_path, mode=0o755)
188 191 log.debug('created group in %s', create_path)
189 192
190 193 def _rename_group(self, old, new):
191 194 """
192 195 Renames a group on filesystem
193 196
194 197 :param group_name:
195 198 """
196 199
197 200 if old == new:
198 201 log.debug('skipping group rename')
199 202 return
200 203
201 204 log.debug('renaming repository group from %s to %s', old, new)
202 205
203 206 old_path = os.path.join(self.repos_path, old)
204 207 new_path = os.path.join(self.repos_path, new)
205 208
206 209 log.debug('renaming repos paths from %s to %s', old_path, new_path)
207 210
208 211 if os.path.isdir(new_path):
209 212 raise Exception('Was trying to rename to already '
210 213 'existing dir %s' % new_path)
211 214 shutil.move(old_path, new_path)
212 215
213 216 def _delete_filesystem_group(self, group, force_delete=False):
214 217 """
215 218 Deletes a group from a filesystem
216 219
217 220 :param group: instance of group from database
218 221 :param force_delete: use shutil rmtree to remove all objects
219 222 """
220 223 paths = group.full_path.split(RepoGroup.url_sep())
221 224 paths = os.sep.join(paths)
222 225
223 226 rm_path = os.path.join(self.repos_path, paths)
224 227 log.info("Removing group %s", rm_path)
225 228 # delete only if that path really exists
226 229 if os.path.isdir(rm_path):
227 230 if force_delete:
228 231 shutil.rmtree(rm_path)
229 232 else:
230 233 # archive that group`
231 234 _now = datetime.datetime.now()
232 235 _ms = str(_now.microsecond).rjust(6, '0')
233 236 _d = 'rm__%s_GROUP_%s' % (
234 237 _now.strftime('%Y%m%d_%H%M%S_' + _ms), group.name)
235 238 shutil.move(rm_path, os.path.join(self.repos_path, _d))
236 239
237 240 def create(self, group_name, group_description, owner, just_db=False,
238 241 copy_permissions=False, personal=None, commit_early=True):
239 242
240 243 (group_name_cleaned,
241 244 parent_group_name) = RepoGroupModel()._get_group_name_and_parent(group_name)
242 245
243 246 parent_group = None
244 247 if parent_group_name:
245 248 parent_group = self._get_repo_group(parent_group_name)
246 249 if not parent_group:
247 250 # we tried to create a nested group, but the parent is not
248 251 # existing
249 252 raise ValueError(
250 253 'Parent group `%s` given in `%s` group name '
251 254 'is not yet existing.' % (parent_group_name, group_name))
252 255
253 256 # because we are doing a cleanup, we need to check if such directory
254 257 # already exists. If we don't do that we can accidentally delete
255 258 # existing directory via cleanup that can cause data issues, since
256 259 # delete does a folder rename to special syntax later cleanup
257 260 # functions can delete this
258 261 cleanup_group = self.check_exist_filesystem(group_name,
259 262 exc_on_failure=False)
260 263 user = self._get_user(owner)
261 264 if not user:
262 265 raise ValueError('Owner %s not found as rhodecode user', owner)
263 266
264 267 try:
265 268 new_repo_group = RepoGroup()
266 269 new_repo_group.user = user
267 270 new_repo_group.group_description = group_description or group_name
268 271 new_repo_group.parent_group = parent_group
269 272 new_repo_group.group_name = group_name
270 273 new_repo_group.personal = personal
271 274
272 275 self.sa.add(new_repo_group)
273 276
274 277 # create an ADMIN permission for owner except if we're super admin,
275 278 # later owner should go into the owner field of groups
276 279 if not user.is_admin:
277 280 self.grant_user_permission(repo_group=new_repo_group,
278 281 user=owner, perm='group.admin')
279 282
280 283 if parent_group and copy_permissions:
281 284 # copy permissions from parent
282 285 user_perms = UserRepoGroupToPerm.query() \
283 286 .filter(UserRepoGroupToPerm.group == parent_group).all()
284 287
285 288 group_perms = UserGroupRepoGroupToPerm.query() \
286 289 .filter(UserGroupRepoGroupToPerm.group == parent_group).all()
287 290
288 291 for perm in user_perms:
289 292 # don't copy over the permission for user who is creating
290 293 # this group, if he is not super admin he get's admin
291 294 # permission set above
292 295 if perm.user != user or user.is_admin:
293 296 UserRepoGroupToPerm.create(
294 297 perm.user, new_repo_group, perm.permission)
295 298
296 299 for perm in group_perms:
297 300 UserGroupRepoGroupToPerm.create(
298 301 perm.users_group, new_repo_group, perm.permission)
299 302 else:
300 303 perm_obj = self._create_default_perms(new_repo_group)
301 304 self.sa.add(perm_obj)
302 305
303 306 # now commit the changes, earlier so we are sure everything is in
304 307 # the database.
305 308 if commit_early:
306 309 self.sa.commit()
307 310 if not just_db:
308 311 self._create_group(new_repo_group.group_name)
309 312
310 313 # trigger the post hook
311 314 from rhodecode.lib import hooks_base
312 315 repo_group = RepoGroup.get_by_group_name(group_name)
313 316
314 317 # update repo group commit caches initially
315 318 repo_group.update_commit_cache()
316 319
317 320 hooks_base.create_repository_group(
318 321 created_by=user.username, **repo_group.get_dict())
319 322
320 323 # Trigger create event.
321 324 events.trigger(events.RepoGroupCreateEvent(repo_group))
322 325
323 326 return new_repo_group
324 327 except Exception:
325 328 self.sa.rollback()
326 329 log.exception('Exception occurred when creating repository group, '
327 330 'doing cleanup...')
328 331 # rollback things manually !
329 332 repo_group = RepoGroup.get_by_group_name(group_name)
330 333 if repo_group:
331 334 RepoGroup.delete(repo_group.group_id)
332 335 self.sa.commit()
333 336 if cleanup_group:
334 337 RepoGroupModel()._delete_filesystem_group(repo_group)
335 338 raise
336 339
337 340 def update_permissions(
338 341 self, repo_group, perm_additions=None, perm_updates=None,
339 342 perm_deletions=None, recursive=None, check_perms=True,
340 343 cur_user=None):
341 344 from rhodecode.model.repo import RepoModel
342 345 from rhodecode.lib.auth import HasUserGroupPermissionAny
343 346
344 347 if not perm_additions:
345 348 perm_additions = []
346 349 if not perm_updates:
347 350 perm_updates = []
348 351 if not perm_deletions:
349 352 perm_deletions = []
350 353
351 354 req_perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin')
352 355
353 356 changes = {
354 357 'added': [],
355 358 'updated': [],
356 359 'deleted': [],
357 360 'default_user_changed': None
358 361 }
359 362
360 363 def _set_perm_user(obj, user, perm):
361 364 if isinstance(obj, RepoGroup):
362 365 self.grant_user_permission(
363 366 repo_group=obj, user=user, perm=perm)
364 367 elif isinstance(obj, Repository):
365 368 # private repos will not allow to change the default
366 369 # permissions using recursive mode
367 370 if obj.private and user == User.DEFAULT_USER:
368 371 return
369 372
370 373 # we set group permission but we have to switch to repo
371 374 # permission
372 375 perm = perm.replace('group.', 'repository.')
373 376 RepoModel().grant_user_permission(
374 377 repo=obj, user=user, perm=perm)
375 378
376 379 def _set_perm_group(obj, users_group, perm):
377 380 if isinstance(obj, RepoGroup):
378 381 self.grant_user_group_permission(
379 382 repo_group=obj, group_name=users_group, perm=perm)
380 383 elif isinstance(obj, Repository):
381 384 # we set group permission but we have to switch to repo
382 385 # permission
383 386 perm = perm.replace('group.', 'repository.')
384 387 RepoModel().grant_user_group_permission(
385 388 repo=obj, group_name=users_group, perm=perm)
386 389
387 390 def _revoke_perm_user(obj, user):
388 391 if isinstance(obj, RepoGroup):
389 392 self.revoke_user_permission(repo_group=obj, user=user)
390 393 elif isinstance(obj, Repository):
391 394 RepoModel().revoke_user_permission(repo=obj, user=user)
392 395
393 396 def _revoke_perm_group(obj, user_group):
394 397 if isinstance(obj, RepoGroup):
395 398 self.revoke_user_group_permission(
396 399 repo_group=obj, group_name=user_group)
397 400 elif isinstance(obj, Repository):
398 401 RepoModel().revoke_user_group_permission(
399 402 repo=obj, group_name=user_group)
400 403
401 404 # start updates
402 405 log.debug('Now updating permissions for %s in recursive mode:%s',
403 406 repo_group, recursive)
404 407
405 408 # initialize check function, we'll call that multiple times
406 409 has_group_perm = HasUserGroupPermissionAny(*req_perms)
407 410
408 411 for obj in repo_group.recursive_groups_and_repos():
409 412 # iterated obj is an instance of a repos group or repository in
410 413 # that group, recursive option can be: none, repos, groups, all
411 414 if recursive == 'all':
412 415 obj = obj
413 416 elif recursive == 'repos':
414 417 # skip groups, other than this one
415 418 if isinstance(obj, RepoGroup) and not obj == repo_group:
416 419 continue
417 420 elif recursive == 'groups':
418 421 # skip repos
419 422 if isinstance(obj, Repository):
420 423 continue
421 424 else: # recursive == 'none':
422 425 # DEFAULT option - don't apply to iterated objects
423 426 # also we do a break at the end of this loop. if we are not
424 427 # in recursive mode
425 428 obj = repo_group
426 429
427 430 change_obj = obj.get_api_data()
428 431
429 432 # update permissions
430 433 for member_id, perm, member_type in perm_updates:
431 434 member_id = int(member_id)
432 435 if member_type == 'user':
433 436 member_name = User.get(member_id).username
434 437 if isinstance(obj, RepoGroup) and obj == repo_group and member_name == User.DEFAULT_USER:
435 438 # NOTE(dan): detect if we changed permissions for default user
436 439 perm_obj = self.sa.query(UserRepoGroupToPerm) \
437 440 .filter(UserRepoGroupToPerm.user_id == member_id) \
438 441 .filter(UserRepoGroupToPerm.group == repo_group) \
439 442 .scalar()
440 443 if perm_obj and perm_obj.permission.permission_name != perm:
441 444 changes['default_user_changed'] = True
442 445
443 446 # this updates also current one if found
444 447 _set_perm_user(obj, user=member_id, perm=perm)
445 448 elif member_type == 'user_group':
446 449 member_name = UserGroup.get(member_id).users_group_name
447 450 if not check_perms or has_group_perm(member_name,
448 451 user=cur_user):
449 452 _set_perm_group(obj, users_group=member_id, perm=perm)
450 453 else:
451 454 raise ValueError("member_type must be 'user' or 'user_group' "
452 455 "got {} instead".format(member_type))
453 456
454 457 changes['updated'].append(
455 458 {'change_obj': change_obj, 'type': member_type,
456 459 'id': member_id, 'name': member_name, 'new_perm': perm})
457 460
458 461 # set new permissions
459 462 for member_id, perm, member_type in perm_additions:
460 463 member_id = int(member_id)
461 464 if member_type == 'user':
462 465 member_name = User.get(member_id).username
463 466 _set_perm_user(obj, user=member_id, perm=perm)
464 467 elif member_type == 'user_group':
465 468 # check if we have permissions to alter this usergroup
466 469 member_name = UserGroup.get(member_id).users_group_name
467 470 if not check_perms or has_group_perm(member_name,
468 471 user=cur_user):
469 472 _set_perm_group(obj, users_group=member_id, perm=perm)
470 473 else:
471 474 raise ValueError("member_type must be 'user' or 'user_group' "
472 475 "got {} instead".format(member_type))
473 476
474 477 changes['added'].append(
475 478 {'change_obj': change_obj, 'type': member_type,
476 479 'id': member_id, 'name': member_name, 'new_perm': perm})
477 480
478 481 # delete permissions
479 482 for member_id, perm, member_type in perm_deletions:
480 483 member_id = int(member_id)
481 484 if member_type == 'user':
482 485 member_name = User.get(member_id).username
483 486 _revoke_perm_user(obj, user=member_id)
484 487 elif member_type == 'user_group':
485 488 # check if we have permissions to alter this usergroup
486 489 member_name = UserGroup.get(member_id).users_group_name
487 490 if not check_perms or has_group_perm(member_name,
488 491 user=cur_user):
489 492 _revoke_perm_group(obj, user_group=member_id)
490 493 else:
491 494 raise ValueError("member_type must be 'user' or 'user_group' "
492 495 "got {} instead".format(member_type))
493 496
494 497 changes['deleted'].append(
495 498 {'change_obj': change_obj, 'type': member_type,
496 499 'id': member_id, 'name': member_name, 'new_perm': perm})
497 500
498 501 # if it's not recursive call for all,repos,groups
499 502 # break the loop and don't proceed with other changes
500 503 if recursive not in ['all', 'repos', 'groups']:
501 504 break
502 505
503 506 return changes
504 507
505 508 def update(self, repo_group, form_data):
506 509 try:
507 510 repo_group = self._get_repo_group(repo_group)
508 511 old_path = repo_group.full_path
509 512
510 513 # change properties
511 514 if 'group_description' in form_data:
512 515 repo_group.group_description = form_data['group_description']
513 516
514 517 if 'enable_locking' in form_data:
515 518 repo_group.enable_locking = form_data['enable_locking']
516 519
517 520 if 'group_parent_id' in form_data:
518 521 parent_group = (
519 522 self._get_repo_group(form_data['group_parent_id']))
520 523 repo_group.group_parent_id = (
521 524 parent_group.group_id if parent_group else None)
522 525 repo_group.parent_group = parent_group
523 526
524 527 # mikhail: to update the full_path, we have to explicitly
525 528 # update group_name
526 529 group_name = form_data.get('group_name', repo_group.name)
527 530 repo_group.group_name = repo_group.get_new_name(group_name)
528 531
529 532 new_path = repo_group.full_path
530 533
531 534 if 'user' in form_data:
532 535 repo_group.user = User.get_by_username(form_data['user'])
533 536
534 537 self.sa.add(repo_group)
535 538
536 539 # iterate over all members of this groups and do fixes
537 540 # set locking if given
538 541 # if obj is a repoGroup also fix the name of the group according
539 542 # to the parent
540 543 # if obj is a Repo fix it's name
541 544 # this can be potentially heavy operation
542 545 for obj in repo_group.recursive_groups_and_repos():
543 546 # set the value from it's parent
544 547 obj.enable_locking = repo_group.enable_locking
545 548 if isinstance(obj, RepoGroup):
546 549 new_name = obj.get_new_name(obj.name)
547 550 log.debug('Fixing group %s to new name %s',
548 551 obj.group_name, new_name)
549 552 obj.group_name = new_name
550 553
551 554 elif isinstance(obj, Repository):
552 555 # we need to get all repositories from this new group and
553 556 # rename them accordingly to new group path
554 557 new_name = obj.get_new_name(obj.just_name)
555 558 log.debug('Fixing repo %s to new name %s',
556 559 obj.repo_name, new_name)
557 560 obj.repo_name = new_name
558 561
559 562 self.sa.add(obj)
560 563
561 564 self._rename_group(old_path, new_path)
562 565
563 566 # Trigger update event.
564 567 events.trigger(events.RepoGroupUpdateEvent(repo_group))
565 568
566 569 return repo_group
567 570 except Exception:
568 571 log.error(traceback.format_exc())
569 572 raise
570 573
571 574 def delete(self, repo_group, force_delete=False, fs_remove=True):
572 575 repo_group = self._get_repo_group(repo_group)
573 576 if not repo_group:
574 577 return False
575 578 try:
576 579 self.sa.delete(repo_group)
577 580 if fs_remove:
578 581 self._delete_filesystem_group(repo_group, force_delete)
579 582 else:
580 583 log.debug('skipping removal from filesystem')
581 584
582 585 # Trigger delete event.
583 586 events.trigger(events.RepoGroupDeleteEvent(repo_group))
584 587 return True
585 588
586 589 except Exception:
587 590 log.error('Error removing repo_group %s', repo_group)
588 591 raise
589 592
590 593 def grant_user_permission(self, repo_group, user, perm):
591 594 """
592 595 Grant permission for user on given repository group, or update
593 596 existing one if found
594 597
595 598 :param repo_group: Instance of RepoGroup, repositories_group_id,
596 599 or repositories_group name
597 600 :param user: Instance of User, user_id or username
598 601 :param perm: Instance of Permission, or permission_name
599 602 """
600 603
601 604 repo_group = self._get_repo_group(repo_group)
602 605 user = self._get_user(user)
603 606 permission = self._get_perm(perm)
604 607
605 608 # check if we have that permission already
606 609 obj = self.sa.query(UserRepoGroupToPerm)\
607 610 .filter(UserRepoGroupToPerm.user == user)\
608 611 .filter(UserRepoGroupToPerm.group == repo_group)\
609 612 .scalar()
610 613 if obj is None:
611 614 # create new !
612 615 obj = UserRepoGroupToPerm()
613 616 obj.group = repo_group
614 617 obj.user = user
615 618 obj.permission = permission
616 619 self.sa.add(obj)
617 620 log.debug('Granted perm %s to %s on %s', perm, user, repo_group)
618 621 action_logger_generic(
619 622 'granted permission: {} to user: {} on repogroup: {}'.format(
620 623 perm, user, repo_group), namespace='security.repogroup')
621 624 return obj
622 625
623 626 def revoke_user_permission(self, repo_group, user):
624 627 """
625 628 Revoke permission for user on given repository group
626 629
627 630 :param repo_group: Instance of RepoGroup, repositories_group_id,
628 631 or repositories_group name
629 632 :param user: Instance of User, user_id or username
630 633 """
631 634
632 635 repo_group = self._get_repo_group(repo_group)
633 636 user = self._get_user(user)
634 637
635 638 obj = self.sa.query(UserRepoGroupToPerm)\
636 639 .filter(UserRepoGroupToPerm.user == user)\
637 640 .filter(UserRepoGroupToPerm.group == repo_group)\
638 641 .scalar()
639 642 if obj:
640 643 self.sa.delete(obj)
641 644 log.debug('Revoked perm on %s on %s', repo_group, user)
642 645 action_logger_generic(
643 646 'revoked permission from user: {} on repogroup: {}'.format(
644 647 user, repo_group), namespace='security.repogroup')
645 648
646 649 def grant_user_group_permission(self, repo_group, group_name, perm):
647 650 """
648 651 Grant permission for user group on given repository group, or update
649 652 existing one if found
650 653
651 654 :param repo_group: Instance of RepoGroup, repositories_group_id,
652 655 or repositories_group name
653 656 :param group_name: Instance of UserGroup, users_group_id,
654 657 or user group name
655 658 :param perm: Instance of Permission, or permission_name
656 659 """
657 660 repo_group = self._get_repo_group(repo_group)
658 661 group_name = self._get_user_group(group_name)
659 662 permission = self._get_perm(perm)
660 663
661 664 # check if we have that permission already
662 665 obj = self.sa.query(UserGroupRepoGroupToPerm)\
663 666 .filter(UserGroupRepoGroupToPerm.group == repo_group)\
664 667 .filter(UserGroupRepoGroupToPerm.users_group == group_name)\
665 668 .scalar()
666 669
667 670 if obj is None:
668 671 # create new
669 672 obj = UserGroupRepoGroupToPerm()
670 673
671 674 obj.group = repo_group
672 675 obj.users_group = group_name
673 676 obj.permission = permission
674 677 self.sa.add(obj)
675 678 log.debug('Granted perm %s to %s on %s', perm, group_name, repo_group)
676 679 action_logger_generic(
677 680 'granted permission: {} to usergroup: {} on repogroup: {}'.format(
678 681 perm, group_name, repo_group), namespace='security.repogroup')
679 682 return obj
680 683
681 684 def revoke_user_group_permission(self, repo_group, group_name):
682 685 """
683 686 Revoke permission for user group on given repository group
684 687
685 688 :param repo_group: Instance of RepoGroup, repositories_group_id,
686 689 or repositories_group name
687 690 :param group_name: Instance of UserGroup, users_group_id,
688 691 or user group name
689 692 """
690 693 repo_group = self._get_repo_group(repo_group)
691 694 group_name = self._get_user_group(group_name)
692 695
693 696 obj = self.sa.query(UserGroupRepoGroupToPerm)\
694 697 .filter(UserGroupRepoGroupToPerm.group == repo_group)\
695 698 .filter(UserGroupRepoGroupToPerm.users_group == group_name)\
696 699 .scalar()
697 700 if obj:
698 701 self.sa.delete(obj)
699 702 log.debug('Revoked perm to %s on %s', repo_group, group_name)
700 703 action_logger_generic(
701 704 'revoked permission from usergroup: {} on repogroup: {}'.format(
702 705 group_name, repo_group), namespace='security.repogroup')
703 706
704 707 @classmethod
705 708 def update_commit_cache(cls, repo_groups=None):
706 709 if not repo_groups:
707 710 repo_groups = RepoGroup.getAll()
708 711 for repo_group in repo_groups:
709 712 repo_group.update_commit_cache()
710 713
711 714 def get_repo_groups_as_dict(self, repo_group_list=None, admin=False,
712 715 super_user_actions=False):
713 716
714 717 from pyramid.threadlocal import get_current_request
715 718 _render = get_current_request().get_partial_renderer(
716 719 'rhodecode:templates/data_table/_dt_elements.mako')
717 720 c = _render.get_call_context()
718 721 h = _render.get_helpers()
719 722
720 723 def quick_menu(repo_group_name):
721 724 return _render('quick_repo_group_menu', repo_group_name)
722 725
723 726 def repo_group_lnk(repo_group_name):
724 727 return _render('repo_group_name', repo_group_name)
725 728
726 729 def last_change(last_change):
727 730 if admin and isinstance(last_change, datetime.datetime) and not last_change.tzinfo:
728 731 ts = time.time()
729 732 utc_offset = (datetime.datetime.fromtimestamp(ts)
730 733 - datetime.datetime.utcfromtimestamp(ts)).total_seconds()
731 734 last_change = last_change + datetime.timedelta(seconds=utc_offset)
732 735 return _render("last_change", last_change)
733 736
734 737 def desc(desc, personal):
735 738 return _render(
736 739 'repo_group_desc', desc, personal, c.visual.stylify_metatags)
737 740
738 741 def repo_group_actions(repo_group_id, repo_group_name, gr_count):
739 742 return _render(
740 743 'repo_group_actions', repo_group_id, repo_group_name, gr_count)
741 744
742 745 def repo_group_name(repo_group_name, children_groups):
743 746 return _render("repo_group_name", repo_group_name, children_groups)
744 747
745 748 def user_profile(username):
746 749 return _render('user_profile', username)
747 750
748 751 repo_group_data = []
749 752 for group in repo_group_list:
750 753 # NOTE(marcink): because we use only raw column we need to load it like that
751 754 changeset_cache = RepoGroup._load_changeset_cache(
752 755 '', group._changeset_cache)
753 756 last_commit_change = RepoGroup._load_commit_change(changeset_cache)
754 757 row = {
755 758 "menu": quick_menu(group.group_name),
756 759 "name": repo_group_lnk(group.group_name),
757 760 "name_raw": group.group_name,
758 761
759 762 "last_change": last_change(last_commit_change),
760 763
761 764 "last_changeset": "",
762 765 "last_changeset_raw": "",
763 766
764 767 "desc": desc(h.escape(group.group_description), group.personal),
765 768 "top_level_repos": 0,
766 769 "owner": user_profile(group.User.username)
767 770 }
768 771 if admin:
769 772 repo_count = group.repositories.count()
770 773 children_groups = map(
771 774 h.safe_unicode,
772 775 itertools.chain((g.name for g in group.parents),
773 776 (x.name for x in [group])))
774 777 row.update({
775 778 "action": repo_group_actions(
776 779 group.group_id, group.group_name, repo_count),
777 780 "top_level_repos": repo_count,
778 781 "name": repo_group_name(group.group_name, children_groups),
779 782
780 783 })
781 784 repo_group_data.append(row)
782 785
783 786 return repo_group_data
784 787
785 788 def get_repo_groups_data_table(
786 789 self, draw, start, limit,
787 790 search_q, order_by, order_dir,
788 791 auth_user, repo_group_id):
789 792 from rhodecode.model.scm import RepoGroupList
790 793
791 794 _perms = ['group.read', 'group.write', 'group.admin']
792 795 repo_groups = RepoGroup.query() \
793 796 .filter(RepoGroup.group_parent_id == repo_group_id) \
794 797 .all()
795 798 auth_repo_group_list = RepoGroupList(
796 799 repo_groups, perm_set=_perms,
797 800 extra_kwargs=dict(user=auth_user))
798 801
799 802 allowed_ids = [-1]
800 803 for repo_group in auth_repo_group_list:
801 804 allowed_ids.append(repo_group.group_id)
802 805
803 806 repo_groups_data_total_count = RepoGroup.query() \
804 807 .filter(RepoGroup.group_parent_id == repo_group_id) \
805 808 .filter(or_(
806 809 # generate multiple IN to fix limitation problems
807 810 *in_filter_generator(RepoGroup.group_id, allowed_ids))
808 811 ) \
809 812 .count()
810 813
811 814 base_q = Session.query(
812 815 RepoGroup.group_name,
813 816 RepoGroup.group_name_hash,
814 817 RepoGroup.group_description,
815 818 RepoGroup.group_id,
816 819 RepoGroup.personal,
817 820 RepoGroup.updated_on,
818 821 RepoGroup._changeset_cache,
819 822 User,
820 823 ) \
821 824 .filter(RepoGroup.group_parent_id == repo_group_id) \
822 825 .filter(or_(
823 826 # generate multiple IN to fix limitation problems
824 827 *in_filter_generator(RepoGroup.group_id, allowed_ids))
825 828 ) \
826 829 .join(User, User.user_id == RepoGroup.user_id) \
827 830 .group_by(RepoGroup, User)
828 831
829 832 repo_groups_data_total_filtered_count = base_q.count()
830 833
831 834 sort_defined = False
832 835
833 836 if order_by == 'group_name':
834 837 sort_col = func.lower(RepoGroup.group_name)
835 838 sort_defined = True
836 839 elif order_by == 'user_username':
837 840 sort_col = User.username
838 841 else:
839 842 sort_col = getattr(RepoGroup, order_by, None)
840 843
841 844 if sort_defined or sort_col:
842 845 if order_dir == 'asc':
843 846 sort_col = sort_col.asc()
844 847 else:
845 848 sort_col = sort_col.desc()
846 849
847 850 base_q = base_q.order_by(sort_col)
848 851 base_q = base_q.offset(start).limit(limit)
849 852
850 853 repo_group_list = base_q.all()
851 854
852 855 repo_groups_data = RepoGroupModel().get_repo_groups_as_dict(
853 856 repo_group_list=repo_group_list, admin=False)
854 857
855 858 data = ({
856 859 'draw': draw,
857 860 'data': repo_groups_data,
858 861 'recordsTotal': repo_groups_data_total_count,
859 862 'recordsFiltered': repo_groups_data_total_filtered_count,
860 863 })
861 864 return data
862 865
863 866 def _get_defaults(self, repo_group_name):
864 867 repo_group = RepoGroup.get_by_group_name(repo_group_name)
865 868
866 869 if repo_group is None:
867 870 return None
868 871
869 872 defaults = repo_group.get_dict()
870 873 defaults['repo_group_name'] = repo_group.name
871 874 defaults['repo_group_description'] = repo_group.group_description
872 875 defaults['repo_group_enable_locking'] = repo_group.enable_locking
873 876
874 877 # we use -1 as this is how in HTML, we mark an empty group
875 878 defaults['repo_group'] = defaults['group_parent_id'] or -1
876 879
877 880 # fill owner
878 881 if repo_group.user:
879 882 defaults.update({'user': repo_group.user.username})
880 883 else:
881 884 replacement_user = User.get_first_super_admin().username
882 885 defaults.update({'user': replacement_user})
883 886
884 887 return defaults
@@ -1,403 +1,405 b''
1 1
2 2 /******************************************************************************
3 3 * *
4 4 * DO NOT CHANGE THIS FILE MANUALLY *
5 5 * *
6 6 * *
7 7 * This file is automatically generated when the app starts up with *
8 8 * generate_js_files = true *
9 9 * *
10 10 * To add a route here pass jsroute=True to the route definition in the app *
11 11 * *
12 12 ******************************************************************************/
13 13 function registerRCRoutes() {
14 14 // routes registration
15 15 pyroutes.register('admin_audit_log_entry', '/_admin/audit_logs/%(audit_log_id)s', ['audit_log_id']);
16 16 pyroutes.register('admin_audit_logs', '/_admin/audit_logs', []);
17 17 pyroutes.register('admin_defaults_repositories', '/_admin/defaults/repositories', []);
18 18 pyroutes.register('admin_defaults_repositories_update', '/_admin/defaults/repositories/update', []);
19 19 pyroutes.register('admin_home', '/_admin', []);
20 20 pyroutes.register('admin_permissions_application', '/_admin/permissions/application', []);
21 21 pyroutes.register('admin_permissions_application_update', '/_admin/permissions/application/update', []);
22 22 pyroutes.register('admin_permissions_auth_token_access', '/_admin/permissions/auth_token_access', []);
23 23 pyroutes.register('admin_permissions_branch', '/_admin/permissions/branch', []);
24 24 pyroutes.register('admin_permissions_branch_update', '/_admin/permissions/branch/update', []);
25 25 pyroutes.register('admin_permissions_global', '/_admin/permissions/global', []);
26 26 pyroutes.register('admin_permissions_global_update', '/_admin/permissions/global/update', []);
27 27 pyroutes.register('admin_permissions_ips', '/_admin/permissions/ips', []);
28 28 pyroutes.register('admin_permissions_object', '/_admin/permissions/object', []);
29 29 pyroutes.register('admin_permissions_object_update', '/_admin/permissions/object/update', []);
30 30 pyroutes.register('admin_permissions_overview', '/_admin/permissions/overview', []);
31 31 pyroutes.register('admin_permissions_ssh_keys', '/_admin/permissions/ssh_keys', []);
32 32 pyroutes.register('admin_permissions_ssh_keys_data', '/_admin/permissions/ssh_keys/data', []);
33 33 pyroutes.register('admin_permissions_ssh_keys_update', '/_admin/permissions/ssh_keys/update', []);
34 34 pyroutes.register('admin_settings', '/_admin/settings', []);
35 35 pyroutes.register('admin_settings_automation', '/_admin/settings/automation', []);
36 36 pyroutes.register('admin_settings_automation_update', '/_admin/settings/automation/%(entry_id)s/update', ['entry_id']);
37 37 pyroutes.register('admin_settings_email', '/_admin/settings/email', []);
38 38 pyroutes.register('admin_settings_email_update', '/_admin/settings/email/update', []);
39 39 pyroutes.register('admin_settings_exception_tracker', '/_admin/settings/exceptions', []);
40 40 pyroutes.register('admin_settings_exception_tracker_delete', '/_admin/settings/exceptions/%(exception_id)s/delete', ['exception_id']);
41 41 pyroutes.register('admin_settings_exception_tracker_delete_all', '/_admin/settings/exceptions_delete_all', []);
42 42 pyroutes.register('admin_settings_exception_tracker_show', '/_admin/settings/exceptions/%(exception_id)s', ['exception_id']);
43 43 pyroutes.register('admin_settings_global', '/_admin/settings/global', []);
44 44 pyroutes.register('admin_settings_global_update', '/_admin/settings/global/update', []);
45 45 pyroutes.register('admin_settings_hooks', '/_admin/settings/hooks', []);
46 46 pyroutes.register('admin_settings_hooks_delete', '/_admin/settings/hooks/delete', []);
47 47 pyroutes.register('admin_settings_hooks_update', '/_admin/settings/hooks/update', []);
48 48 pyroutes.register('admin_settings_issuetracker', '/_admin/settings/issue-tracker', []);
49 49 pyroutes.register('admin_settings_issuetracker_delete', '/_admin/settings/issue-tracker/delete', []);
50 50 pyroutes.register('admin_settings_issuetracker_test', '/_admin/settings/issue-tracker/test', []);
51 51 pyroutes.register('admin_settings_issuetracker_update', '/_admin/settings/issue-tracker/update', []);
52 52 pyroutes.register('admin_settings_labs', '/_admin/settings/labs', []);
53 53 pyroutes.register('admin_settings_labs_update', '/_admin/settings/labs/update', []);
54 54 pyroutes.register('admin_settings_license', '/_admin/settings/license', []);
55 55 pyroutes.register('admin_settings_license_unlock', '/_admin/settings/license_unlock', []);
56 56 pyroutes.register('admin_settings_mapping', '/_admin/settings/mapping', []);
57 57 pyroutes.register('admin_settings_mapping_update', '/_admin/settings/mapping/update', []);
58 58 pyroutes.register('admin_settings_open_source', '/_admin/settings/open_source', []);
59 59 pyroutes.register('admin_settings_process_management', '/_admin/settings/process_management', []);
60 60 pyroutes.register('admin_settings_process_management_data', '/_admin/settings/process_management/data', []);
61 61 pyroutes.register('admin_settings_process_management_master_signal', '/_admin/settings/process_management/master_signal', []);
62 62 pyroutes.register('admin_settings_process_management_signal', '/_admin/settings/process_management/signal', []);
63 63 pyroutes.register('admin_settings_scheduler_create', '/_admin/settings/scheduler/create', []);
64 64 pyroutes.register('admin_settings_scheduler_delete', '/_admin/settings/scheduler/%(schedule_id)s/delete', ['schedule_id']);
65 65 pyroutes.register('admin_settings_scheduler_edit', '/_admin/settings/scheduler/%(schedule_id)s', ['schedule_id']);
66 66 pyroutes.register('admin_settings_scheduler_execute', '/_admin/settings/scheduler/%(schedule_id)s/execute', ['schedule_id']);
67 67 pyroutes.register('admin_settings_scheduler_new', '/_admin/settings/scheduler/new', []);
68 68 pyroutes.register('admin_settings_scheduler_show_all', '/_admin/settings/scheduler', []);
69 69 pyroutes.register('admin_settings_scheduler_show_tasks', '/_admin/settings/scheduler/_tasks', []);
70 70 pyroutes.register('admin_settings_scheduler_update', '/_admin/settings/scheduler/%(schedule_id)s/update', ['schedule_id']);
71 71 pyroutes.register('admin_settings_search', '/_admin/settings/search', []);
72 72 pyroutes.register('admin_settings_sessions', '/_admin/settings/sessions', []);
73 73 pyroutes.register('admin_settings_sessions_cleanup', '/_admin/settings/sessions/cleanup', []);
74 74 pyroutes.register('admin_settings_system', '/_admin/settings/system', []);
75 75 pyroutes.register('admin_settings_system_update', '/_admin/settings/system/updates', []);
76 76 pyroutes.register('admin_settings_update', '/_admin/settings/update', []);
77 77 pyroutes.register('admin_settings_vcs', '/_admin/settings/vcs', []);
78 78 pyroutes.register('admin_settings_vcs_svn_generate_cfg', '/_admin/settings/vcs/svn_generate_cfg', []);
79 79 pyroutes.register('admin_settings_vcs_svn_pattern_delete', '/_admin/settings/vcs/svn_pattern_delete', []);
80 80 pyroutes.register('admin_settings_vcs_update', '/_admin/settings/vcs/update', []);
81 81 pyroutes.register('admin_settings_visual', '/_admin/settings/visual', []);
82 82 pyroutes.register('admin_settings_visual_update', '/_admin/settings/visual/update', []);
83 83 pyroutes.register('apiv2', '/_admin/api', []);
84 84 pyroutes.register('atom_feed_home', '/%(repo_name)s/feed-atom', ['repo_name']);
85 85 pyroutes.register('atom_feed_home_old', '/%(repo_name)s/feed/atom', ['repo_name']);
86 86 pyroutes.register('auth_home', '/_admin/auth*traverse', []);
87 87 pyroutes.register('bookmarks_home', '/%(repo_name)s/bookmarks', ['repo_name']);
88 88 pyroutes.register('branches_home', '/%(repo_name)s/branches', ['repo_name']);
89 89 pyroutes.register('channelstream_connect', '/_admin/channelstream/connect', []);
90 90 pyroutes.register('channelstream_proxy', '/_channelstream', []);
91 91 pyroutes.register('channelstream_subscribe', '/_admin/channelstream/subscribe', []);
92 92 pyroutes.register('commit_draft_comments_submit', '/%(repo_name)s/changeset/%(commit_id)s/draft_comments_submit', ['repo_name', 'commit_id']);
93 93 pyroutes.register('debug_style_email', '/_admin/debug_style/email/%(email_id)s', ['email_id']);
94 94 pyroutes.register('debug_style_email_plain_rendered', '/_admin/debug_style/email-rendered/%(email_id)s', ['email_id']);
95 95 pyroutes.register('debug_style_home', '/_admin/debug_style', []);
96 96 pyroutes.register('debug_style_template', '/_admin/debug_style/t/%(t_path)s', ['t_path']);
97 97 pyroutes.register('download_file', '/_file_store/download/%(fid)s', ['fid']);
98 98 pyroutes.register('download_file_by_token', '/_file_store/token-download/%(_auth_token)s/%(fid)s', ['_auth_token', 'fid']);
99 99 pyroutes.register('edit_repo', '/%(repo_name)s/settings', ['repo_name']);
100 100 pyroutes.register('edit_repo_advanced', '/%(repo_name)s/settings/advanced', ['repo_name']);
101 101 pyroutes.register('edit_repo_advanced_archive', '/%(repo_name)s/settings/advanced/archive', ['repo_name']);
102 102 pyroutes.register('edit_repo_advanced_delete', '/%(repo_name)s/settings/advanced/delete', ['repo_name']);
103 103 pyroutes.register('edit_repo_advanced_fork', '/%(repo_name)s/settings/advanced/fork', ['repo_name']);
104 104 pyroutes.register('edit_repo_advanced_hooks', '/%(repo_name)s/settings/advanced/hooks', ['repo_name']);
105 105 pyroutes.register('edit_repo_advanced_journal', '/%(repo_name)s/settings/advanced/journal', ['repo_name']);
106 106 pyroutes.register('edit_repo_advanced_locking', '/%(repo_name)s/settings/advanced/locking', ['repo_name']);
107 107 pyroutes.register('edit_repo_audit_logs', '/%(repo_name)s/settings/audit_logs', ['repo_name']);
108 108 pyroutes.register('edit_repo_caches', '/%(repo_name)s/settings/caches', ['repo_name']);
109 109 pyroutes.register('edit_repo_fields', '/%(repo_name)s/settings/fields', ['repo_name']);
110 110 pyroutes.register('edit_repo_fields_create', '/%(repo_name)s/settings/fields/create', ['repo_name']);
111 111 pyroutes.register('edit_repo_fields_delete', '/%(repo_name)s/settings/fields/%(field_id)s/delete', ['repo_name', 'field_id']);
112 112 pyroutes.register('edit_repo_group', '/%(repo_group_name)s/_edit', ['repo_group_name']);
113 113 pyroutes.register('edit_repo_group_advanced', '/%(repo_group_name)s/_settings/advanced', ['repo_group_name']);
114 114 pyroutes.register('edit_repo_group_advanced_delete', '/%(repo_group_name)s/_settings/advanced/delete', ['repo_group_name']);
115 115 pyroutes.register('edit_repo_group_perms', '/%(repo_group_name)s/_settings/permissions', ['repo_group_name']);
116 116 pyroutes.register('edit_repo_group_perms_update', '/%(repo_group_name)s/_settings/permissions/update', ['repo_group_name']);
117 117 pyroutes.register('edit_repo_issuetracker', '/%(repo_name)s/settings/issue_trackers', ['repo_name']);
118 118 pyroutes.register('edit_repo_issuetracker_delete', '/%(repo_name)s/settings/issue_trackers/delete', ['repo_name']);
119 119 pyroutes.register('edit_repo_issuetracker_test', '/%(repo_name)s/settings/issue_trackers/test', ['repo_name']);
120 120 pyroutes.register('edit_repo_issuetracker_update', '/%(repo_name)s/settings/issue_trackers/update', ['repo_name']);
121 121 pyroutes.register('edit_repo_maintenance', '/%(repo_name)s/settings/maintenance', ['repo_name']);
122 122 pyroutes.register('edit_repo_maintenance_execute', '/%(repo_name)s/settings/maintenance/execute', ['repo_name']);
123 123 pyroutes.register('edit_repo_perms', '/%(repo_name)s/settings/permissions', ['repo_name']);
124 124 pyroutes.register('edit_repo_perms_branch', '/%(repo_name)s/settings/branch_permissions', ['repo_name']);
125 125 pyroutes.register('edit_repo_perms_branch_delete', '/%(repo_name)s/settings/branch_permissions/%(rule_id)s/delete', ['repo_name', 'rule_id']);
126 126 pyroutes.register('edit_repo_perms_set_private', '/%(repo_name)s/settings/permissions/set_private', ['repo_name']);
127 127 pyroutes.register('edit_repo_remote', '/%(repo_name)s/settings/remote', ['repo_name']);
128 128 pyroutes.register('edit_repo_remote_pull', '/%(repo_name)s/settings/remote/pull', ['repo_name']);
129 129 pyroutes.register('edit_repo_remote_push', '/%(repo_name)s/settings/remote/push', ['repo_name']);
130 130 pyroutes.register('edit_repo_statistics', '/%(repo_name)s/settings/statistics', ['repo_name']);
131 131 pyroutes.register('edit_repo_statistics_reset', '/%(repo_name)s/settings/statistics/update', ['repo_name']);
132 132 pyroutes.register('edit_repo_strip', '/%(repo_name)s/settings/strip', ['repo_name']);
133 133 pyroutes.register('edit_repo_vcs', '/%(repo_name)s/settings/vcs', ['repo_name']);
134 134 pyroutes.register('edit_repo_vcs_svn_pattern_delete', '/%(repo_name)s/settings/vcs/svn_pattern/delete', ['repo_name']);
135 135 pyroutes.register('edit_repo_vcs_update', '/%(repo_name)s/settings/vcs/update', ['repo_name']);
136 136 pyroutes.register('edit_user_audit_logs', '/_admin/users/%(user_id)s/edit/audit', ['user_id']);
137 137 pyroutes.register('edit_user_audit_logs_download', '/_admin/users/%(user_id)s/edit/audit/download', ['user_id']);
138 138 pyroutes.register('edit_user_auth_tokens', '/_admin/users/%(user_id)s/edit/auth_tokens', ['user_id']);
139 139 pyroutes.register('edit_user_auth_tokens_add', '/_admin/users/%(user_id)s/edit/auth_tokens/new', ['user_id']);
140 140 pyroutes.register('edit_user_auth_tokens_delete', '/_admin/users/%(user_id)s/edit/auth_tokens/delete', ['user_id']);
141 141 pyroutes.register('edit_user_auth_tokens_view', '/_admin/users/%(user_id)s/edit/auth_tokens/view', ['user_id']);
142 142 pyroutes.register('edit_user_caches', '/_admin/users/%(user_id)s/edit/caches', ['user_id']);
143 143 pyroutes.register('edit_user_caches_update', '/_admin/users/%(user_id)s/edit/caches/update', ['user_id']);
144 144 pyroutes.register('edit_user_emails', '/_admin/users/%(user_id)s/edit/emails', ['user_id']);
145 145 pyroutes.register('edit_user_emails_add', '/_admin/users/%(user_id)s/edit/emails/new', ['user_id']);
146 146 pyroutes.register('edit_user_emails_delete', '/_admin/users/%(user_id)s/edit/emails/delete', ['user_id']);
147 147 pyroutes.register('edit_user_group', '/_admin/user_groups/%(user_group_id)s/edit', ['user_group_id']);
148 148 pyroutes.register('edit_user_group_advanced', '/_admin/user_groups/%(user_group_id)s/edit/advanced', ['user_group_id']);
149 149 pyroutes.register('edit_user_group_advanced_sync', '/_admin/user_groups/%(user_group_id)s/edit/advanced/sync', ['user_group_id']);
150 150 pyroutes.register('edit_user_group_global_perms', '/_admin/user_groups/%(user_group_id)s/edit/global_permissions', ['user_group_id']);
151 151 pyroutes.register('edit_user_group_global_perms_update', '/_admin/user_groups/%(user_group_id)s/edit/global_permissions/update', ['user_group_id']);
152 152 pyroutes.register('edit_user_group_perms', '/_admin/user_groups/%(user_group_id)s/edit/permissions', ['user_group_id']);
153 153 pyroutes.register('edit_user_group_perms_summary', '/_admin/user_groups/%(user_group_id)s/edit/permissions_summary', ['user_group_id']);
154 154 pyroutes.register('edit_user_group_perms_summary_json', '/_admin/user_groups/%(user_group_id)s/edit/permissions_summary/json', ['user_group_id']);
155 155 pyroutes.register('edit_user_group_perms_update', '/_admin/user_groups/%(user_group_id)s/edit/permissions/update', ['user_group_id']);
156 156 pyroutes.register('edit_user_groups_management', '/_admin/users/%(user_id)s/edit/groups_management', ['user_id']);
157 157 pyroutes.register('edit_user_groups_management_updates', '/_admin/users/%(user_id)s/edit/edit_user_groups_management/updates', ['user_id']);
158 158 pyroutes.register('edit_user_ips', '/_admin/users/%(user_id)s/edit/ips', ['user_id']);
159 159 pyroutes.register('edit_user_ips_add', '/_admin/users/%(user_id)s/edit/ips/new', ['user_id']);
160 160 pyroutes.register('edit_user_ips_delete', '/_admin/users/%(user_id)s/edit/ips/delete', ['user_id']);
161 161 pyroutes.register('edit_user_perms_summary', '/_admin/users/%(user_id)s/edit/permissions_summary', ['user_id']);
162 162 pyroutes.register('edit_user_perms_summary_json', '/_admin/users/%(user_id)s/edit/permissions_summary/json', ['user_id']);
163 163 pyroutes.register('edit_user_ssh_keys', '/_admin/users/%(user_id)s/edit/ssh_keys', ['user_id']);
164 164 pyroutes.register('edit_user_ssh_keys_add', '/_admin/users/%(user_id)s/edit/ssh_keys/new', ['user_id']);
165 165 pyroutes.register('edit_user_ssh_keys_delete', '/_admin/users/%(user_id)s/edit/ssh_keys/delete', ['user_id']);
166 166 pyroutes.register('edit_user_ssh_keys_generate_keypair', '/_admin/users/%(user_id)s/edit/ssh_keys/generate', ['user_id']);
167 167 pyroutes.register('favicon', '/favicon.ico', []);
168 168 pyroutes.register('file_preview', '/_file_preview', []);
169 169 pyroutes.register('gist_delete', '/_admin/gists/%(gist_id)s/delete', ['gist_id']);
170 170 pyroutes.register('gist_edit', '/_admin/gists/%(gist_id)s/edit', ['gist_id']);
171 171 pyroutes.register('gist_edit_check_revision', '/_admin/gists/%(gist_id)s/edit/check_revision', ['gist_id']);
172 172 pyroutes.register('gist_show', '/_admin/gists/%(gist_id)s', ['gist_id']);
173 173 pyroutes.register('gist_show_formatted', '/_admin/gists/%(gist_id)s/rev/%(revision)s/%(format)s', ['gist_id', 'revision', 'format']);
174 174 pyroutes.register('gist_show_formatted_path', '/_admin/gists/%(gist_id)s/rev/%(revision)s/%(format)s/%(f_path)s', ['gist_id', 'revision', 'format', 'f_path']);
175 175 pyroutes.register('gist_show_rev', '/_admin/gists/%(gist_id)s/rev/%(revision)s', ['gist_id', 'revision']);
176 176 pyroutes.register('gist_update', '/_admin/gists/%(gist_id)s/update', ['gist_id']);
177 177 pyroutes.register('gists_create', '/_admin/gists/create', []);
178 178 pyroutes.register('gists_new', '/_admin/gists/new', []);
179 179 pyroutes.register('gists_show', '/_admin/gists', []);
180 180 pyroutes.register('global_integrations_create', '/_admin/integrations/%(integration)s/new', ['integration']);
181 181 pyroutes.register('global_integrations_edit', '/_admin/integrations/%(integration)s/%(integration_id)s', ['integration', 'integration_id']);
182 182 pyroutes.register('global_integrations_home', '/_admin/integrations', []);
183 183 pyroutes.register('global_integrations_list', '/_admin/integrations/%(integration)s', ['integration']);
184 184 pyroutes.register('global_integrations_new', '/_admin/integrations/new', []);
185 185 pyroutes.register('goto_switcher_data', '/_goto_data', []);
186 186 pyroutes.register('home', '/', []);
187 187 pyroutes.register('hovercard_pull_request', '/_hovercard/pull_request/%(pull_request_id)s', ['pull_request_id']);
188 188 pyroutes.register('hovercard_repo_commit', '/_hovercard/commit/%(repo_name)s/%(commit_id)s', ['repo_name', 'commit_id']);
189 189 pyroutes.register('hovercard_user', '/_hovercard/user/%(user_id)s', ['user_id']);
190 190 pyroutes.register('hovercard_user_group', '/_hovercard/user_group/%(user_group_id)s', ['user_group_id']);
191 191 pyroutes.register('hovercard_username', '/_hovercard/username/%(username)s', ['username']);
192 192 pyroutes.register('journal', '/_admin/journal', []);
193 193 pyroutes.register('journal_atom', '/_admin/journal/atom', []);
194 194 pyroutes.register('journal_public', '/_admin/public_journal', []);
195 195 pyroutes.register('journal_public_atom', '/_admin/public_journal/atom', []);
196 196 pyroutes.register('journal_public_atom_old', '/_admin/public_journal_atom', []);
197 197 pyroutes.register('journal_public_rss', '/_admin/public_journal/rss', []);
198 198 pyroutes.register('journal_public_rss_old', '/_admin/public_journal_rss', []);
199 199 pyroutes.register('journal_rss', '/_admin/journal/rss', []);
200 200 pyroutes.register('login', '/_admin/login', []);
201 201 pyroutes.register('logout', '/_admin/logout', []);
202 202 pyroutes.register('main_page_repo_groups_data', '/_home_repo_groups', []);
203 203 pyroutes.register('main_page_repos_data', '/_home_repos', []);
204 204 pyroutes.register('markup_preview', '/_markup_preview', []);
205 205 pyroutes.register('my_account_auth_tokens', '/_admin/my_account/auth_tokens', []);
206 206 pyroutes.register('my_account_auth_tokens_add', '/_admin/my_account/auth_tokens/new', []);
207 207 pyroutes.register('my_account_auth_tokens_delete', '/_admin/my_account/auth_tokens/delete', []);
208 208 pyroutes.register('my_account_auth_tokens_view', '/_admin/my_account/auth_tokens/view', []);
209 209 pyroutes.register('my_account_bookmarks', '/_admin/my_account/bookmarks', []);
210 210 pyroutes.register('my_account_bookmarks_update', '/_admin/my_account/bookmarks/update', []);
211 211 pyroutes.register('my_account_edit', '/_admin/my_account/edit', []);
212 212 pyroutes.register('my_account_emails', '/_admin/my_account/emails', []);
213 213 pyroutes.register('my_account_emails_add', '/_admin/my_account/emails/new', []);
214 214 pyroutes.register('my_account_emails_delete', '/_admin/my_account/emails/delete', []);
215 215 pyroutes.register('my_account_external_identity', '/_admin/my_account/external-identity', []);
216 216 pyroutes.register('my_account_external_identity_delete', '/_admin/my_account/external-identity/delete', []);
217 217 pyroutes.register('my_account_goto_bookmark', '/_admin/my_account/bookmark/%(bookmark_id)s', ['bookmark_id']);
218 218 pyroutes.register('my_account_notifications', '/_admin/my_account/notifications', []);
219 219 pyroutes.register('my_account_notifications_test_channelstream', '/_admin/my_account/test_channelstream', []);
220 220 pyroutes.register('my_account_notifications_toggle_visibility', '/_admin/my_account/toggle_visibility', []);
221 221 pyroutes.register('my_account_password', '/_admin/my_account/password', []);
222 222 pyroutes.register('my_account_password_update', '/_admin/my_account/password/update', []);
223 223 pyroutes.register('my_account_perms', '/_admin/my_account/perms', []);
224 224 pyroutes.register('my_account_profile', '/_admin/my_account/profile', []);
225 225 pyroutes.register('my_account_pullrequests', '/_admin/my_account/pull_requests', []);
226 226 pyroutes.register('my_account_pullrequests_data', '/_admin/my_account/pull_requests/data', []);
227 227 pyroutes.register('my_account_repos', '/_admin/my_account/repos', []);
228 228 pyroutes.register('my_account_ssh_keys', '/_admin/my_account/ssh_keys', []);
229 229 pyroutes.register('my_account_ssh_keys_add', '/_admin/my_account/ssh_keys/new', []);
230 230 pyroutes.register('my_account_ssh_keys_delete', '/_admin/my_account/ssh_keys/delete', []);
231 231 pyroutes.register('my_account_ssh_keys_generate', '/_admin/my_account/ssh_keys/generate', []);
232 232 pyroutes.register('my_account_update', '/_admin/my_account/update', []);
233 233 pyroutes.register('my_account_user_group_membership', '/_admin/my_account/user_group_membership', []);
234 234 pyroutes.register('my_account_watched', '/_admin/my_account/watched', []);
235 235 pyroutes.register('notifications_delete', '/_admin/notifications/%(notification_id)s/delete', ['notification_id']);
236 236 pyroutes.register('notifications_mark_all_read', '/_admin/notifications_mark_all_read', []);
237 237 pyroutes.register('notifications_show', '/_admin/notifications/%(notification_id)s', ['notification_id']);
238 238 pyroutes.register('notifications_show_all', '/_admin/notifications', []);
239 239 pyroutes.register('notifications_update', '/_admin/notifications/%(notification_id)s/update', ['notification_id']);
240 240 pyroutes.register('ops_error_test', '/_admin/ops/error', []);
241 241 pyroutes.register('ops_ping', '/_admin/ops/ping', []);
242 242 pyroutes.register('ops_redirect_test', '/_admin/ops/redirect', []);
243 243 pyroutes.register('plugin_admin_chat', '/_admin/plugin_admin_chat/%(action)s', ['action']);
244 244 pyroutes.register('pull_requests_global', '/_admin/pull-request/%(pull_request_id)s', ['pull_request_id']);
245 245 pyroutes.register('pull_requests_global_0', '/_admin/pull_requests/%(pull_request_id)s', ['pull_request_id']);
246 246 pyroutes.register('pull_requests_global_1', '/_admin/pull-requests/%(pull_request_id)s', ['pull_request_id']);
247 247 pyroutes.register('pullrequest_comment_create', '/%(repo_name)s/pull-request/%(pull_request_id)s/comment', ['repo_name', 'pull_request_id']);
248 248 pyroutes.register('pullrequest_comment_delete', '/%(repo_name)s/pull-request/%(pull_request_id)s/comment/%(comment_id)s/delete', ['repo_name', 'pull_request_id', 'comment_id']);
249 249 pyroutes.register('pullrequest_comment_edit', '/%(repo_name)s/pull-request/%(pull_request_id)s/comment/%(comment_id)s/edit', ['repo_name', 'pull_request_id', 'comment_id']);
250 250 pyroutes.register('pullrequest_comments', '/%(repo_name)s/pull-request/%(pull_request_id)s/comments', ['repo_name', 'pull_request_id']);
251 251 pyroutes.register('pullrequest_create', '/%(repo_name)s/pull-request/create', ['repo_name']);
252 252 pyroutes.register('pullrequest_delete', '/%(repo_name)s/pull-request/%(pull_request_id)s/delete', ['repo_name', 'pull_request_id']);
253 253 pyroutes.register('pullrequest_draft_comments_submit', '/%(repo_name)s/pull-request/%(pull_request_id)s/draft_comments_submit', ['repo_name', 'pull_request_id']);
254 254 pyroutes.register('pullrequest_drafts', '/%(repo_name)s/pull-request/%(pull_request_id)s/drafts', ['repo_name', 'pull_request_id']);
255 255 pyroutes.register('pullrequest_merge', '/%(repo_name)s/pull-request/%(pull_request_id)s/merge', ['repo_name', 'pull_request_id']);
256 256 pyroutes.register('pullrequest_new', '/%(repo_name)s/pull-request/new', ['repo_name']);
257 257 pyroutes.register('pullrequest_repo_refs', '/%(repo_name)s/pull-request/refs/%(target_repo_name)s', ['repo_name', 'target_repo_name']);
258 258 pyroutes.register('pullrequest_repo_targets', '/%(repo_name)s/pull-request/repo-targets', ['repo_name']);
259 259 pyroutes.register('pullrequest_show', '/%(repo_name)s/pull-request/%(pull_request_id)s', ['repo_name', 'pull_request_id']);
260 260 pyroutes.register('pullrequest_show_all', '/%(repo_name)s/pull-request', ['repo_name']);
261 261 pyroutes.register('pullrequest_show_all_data', '/%(repo_name)s/pull-request-data', ['repo_name']);
262 262 pyroutes.register('pullrequest_todos', '/%(repo_name)s/pull-request/%(pull_request_id)s/todos', ['repo_name', 'pull_request_id']);
263 263 pyroutes.register('pullrequest_update', '/%(repo_name)s/pull-request/%(pull_request_id)s/update', ['repo_name', 'pull_request_id']);
264 264 pyroutes.register('register', '/_admin/register', []);
265 265 pyroutes.register('repo_archivefile', '/%(repo_name)s/archive/%(fname)s', ['repo_name', 'fname']);
266 266 pyroutes.register('repo_artifacts_data', '/%(repo_name)s/artifacts_data', ['repo_name']);
267 267 pyroutes.register('repo_artifacts_delete', '/%(repo_name)s/artifacts/delete/%(uid)s', ['repo_name', 'uid']);
268 268 pyroutes.register('repo_artifacts_get', '/%(repo_name)s/artifacts/download/%(uid)s', ['repo_name', 'uid']);
269 269 pyroutes.register('repo_artifacts_info', '/%(repo_name)s/artifacts/info/%(uid)s', ['repo_name', 'uid']);
270 270 pyroutes.register('repo_artifacts_list', '/%(repo_name)s/artifacts', ['repo_name']);
271 271 pyroutes.register('repo_artifacts_new', '/%(repo_name)s/artifacts/new', ['repo_name']);
272 272 pyroutes.register('repo_artifacts_store', '/%(repo_name)s/artifacts/store', ['repo_name']);
273 pyroutes.register('repo_artifacts_stream_script', '/_file_store/stream-upload-script', []);
274 pyroutes.register('repo_artifacts_stream_store', '/_file_store/stream-upload', []);
273 275 pyroutes.register('repo_artifacts_update', '/%(repo_name)s/artifacts/update/%(uid)s', ['repo_name', 'uid']);
274 276 pyroutes.register('repo_automation', '/%(repo_name)s/settings/automation', ['repo_name']);
275 277 pyroutes.register('repo_automation_update', '/%(repo_name)s/settings/automation/%(entry_id)s/update', ['repo_name', 'entry_id']);
276 278 pyroutes.register('repo_changelog', '/%(repo_name)s/changelog', ['repo_name']);
277 279 pyroutes.register('repo_changelog_file', '/%(repo_name)s/changelog/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
278 280 pyroutes.register('repo_commit', '/%(repo_name)s/changeset/%(commit_id)s', ['repo_name', 'commit_id']);
279 281 pyroutes.register('repo_commit_children', '/%(repo_name)s/changeset_children/%(commit_id)s', ['repo_name', 'commit_id']);
280 282 pyroutes.register('repo_commit_comment_attachment_upload', '/%(repo_name)s/changeset/%(commit_id)s/comment/attachment_upload', ['repo_name', 'commit_id']);
281 283 pyroutes.register('repo_commit_comment_create', '/%(repo_name)s/changeset/%(commit_id)s/comment/create', ['repo_name', 'commit_id']);
282 284 pyroutes.register('repo_commit_comment_delete', '/%(repo_name)s/changeset/%(commit_id)s/comment/%(comment_id)s/delete', ['repo_name', 'commit_id', 'comment_id']);
283 285 pyroutes.register('repo_commit_comment_edit', '/%(repo_name)s/changeset/%(commit_id)s/comment/%(comment_id)s/edit', ['repo_name', 'commit_id', 'comment_id']);
284 286 pyroutes.register('repo_commit_comment_history_view', '/%(repo_name)s/changeset/%(commit_id)s/comment/%(comment_history_id)s/history_view', ['repo_name', 'commit_id', 'comment_history_id']);
285 287 pyroutes.register('repo_commit_comment_preview', '/%(repo_name)s/changeset/%(commit_id)s/comment/preview', ['repo_name', 'commit_id']);
286 288 pyroutes.register('repo_commit_data', '/%(repo_name)s/changeset-data/%(commit_id)s', ['repo_name', 'commit_id']);
287 289 pyroutes.register('repo_commit_download', '/%(repo_name)s/changeset-download/%(commit_id)s', ['repo_name', 'commit_id']);
288 290 pyroutes.register('repo_commit_parents', '/%(repo_name)s/changeset_parents/%(commit_id)s', ['repo_name', 'commit_id']);
289 291 pyroutes.register('repo_commit_patch', '/%(repo_name)s/changeset-patch/%(commit_id)s', ['repo_name', 'commit_id']);
290 292 pyroutes.register('repo_commit_raw', '/%(repo_name)s/changeset-diff/%(commit_id)s', ['repo_name', 'commit_id']);
291 293 pyroutes.register('repo_commit_raw_deprecated', '/%(repo_name)s/raw-changeset/%(commit_id)s', ['repo_name', 'commit_id']);
292 294 pyroutes.register('repo_commits', '/%(repo_name)s/commits', ['repo_name']);
293 295 pyroutes.register('repo_commits_elements', '/%(repo_name)s/commits_elements', ['repo_name']);
294 296 pyroutes.register('repo_commits_elements_file', '/%(repo_name)s/commits_elements/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
295 297 pyroutes.register('repo_commits_file', '/%(repo_name)s/commits/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
296 298 pyroutes.register('repo_compare', '/%(repo_name)s/compare/%(source_ref_type)s@%(source_ref)s...%(target_ref_type)s@%(target_ref)s', ['repo_name', 'source_ref_type', 'source_ref', 'target_ref_type', 'target_ref']);
297 299 pyroutes.register('repo_compare_select', '/%(repo_name)s/compare', ['repo_name']);
298 300 pyroutes.register('repo_create', '/_admin/repos/create', []);
299 301 pyroutes.register('repo_creating', '/%(repo_name)s/repo_creating', ['repo_name']);
300 302 pyroutes.register('repo_creating_check', '/%(repo_name)s/repo_creating_check', ['repo_name']);
301 303 pyroutes.register('repo_default_reviewers_data', '/%(repo_name)s/settings/review/default-reviewers', ['repo_name']);
302 304 pyroutes.register('repo_edit_toggle_locking', '/%(repo_name)s/settings/toggle_locking', ['repo_name']);
303 305 pyroutes.register('repo_file_authors', '/%(repo_name)s/authors/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
304 306 pyroutes.register('repo_file_download', '/%(repo_name)s/download/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
305 307 pyroutes.register('repo_file_download:legacy', '/%(repo_name)s/rawfile/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
306 308 pyroutes.register('repo_file_history', '/%(repo_name)s/history/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
307 309 pyroutes.register('repo_file_raw', '/%(repo_name)s/raw/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
308 310 pyroutes.register('repo_files', '/%(repo_name)s/files/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
309 311 pyroutes.register('repo_files:annotated', '/%(repo_name)s/annotate/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
310 312 pyroutes.register('repo_files:annotated_previous', '/%(repo_name)s/annotate-previous/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
311 313 pyroutes.register('repo_files:default_commit', '/%(repo_name)s/files', ['repo_name']);
312 314 pyroutes.register('repo_files:default_path', '/%(repo_name)s/files/%(commit_id)s/', ['repo_name', 'commit_id']);
313 315 pyroutes.register('repo_files:rendered', '/%(repo_name)s/render/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
314 316 pyroutes.register('repo_files_add_file', '/%(repo_name)s/add_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
315 317 pyroutes.register('repo_files_check_head', '/%(repo_name)s/check_head/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
316 318 pyroutes.register('repo_files_create_file', '/%(repo_name)s/create_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
317 319 pyroutes.register('repo_files_delete_file', '/%(repo_name)s/delete_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
318 320 pyroutes.register('repo_files_diff', '/%(repo_name)s/diff/%(f_path)s', ['repo_name', 'f_path']);
319 321 pyroutes.register('repo_files_diff_2way_redirect', '/%(repo_name)s/diff-2way/%(f_path)s', ['repo_name', 'f_path']);
320 322 pyroutes.register('repo_files_edit_file', '/%(repo_name)s/edit_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
321 323 pyroutes.register('repo_files_nodelist', '/%(repo_name)s/nodelist/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
322 324 pyroutes.register('repo_files_remove_file', '/%(repo_name)s/remove_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
323 325 pyroutes.register('repo_files_update_file', '/%(repo_name)s/update_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
324 326 pyroutes.register('repo_files_upload_file', '/%(repo_name)s/upload_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
325 327 pyroutes.register('repo_fork_create', '/%(repo_name)s/fork/create', ['repo_name']);
326 328 pyroutes.register('repo_fork_new', '/%(repo_name)s/fork', ['repo_name']);
327 329 pyroutes.register('repo_forks_data', '/%(repo_name)s/forks/data', ['repo_name']);
328 330 pyroutes.register('repo_forks_show_all', '/%(repo_name)s/forks', ['repo_name']);
329 331 pyroutes.register('repo_group_create', '/_admin/repo_group/create', []);
330 332 pyroutes.register('repo_group_home', '/%(repo_group_name)s', ['repo_group_name']);
331 333 pyroutes.register('repo_group_home_slash', '/%(repo_group_name)s/', ['repo_group_name']);
332 334 pyroutes.register('repo_group_integrations_create', '/%(repo_group_name)s/_settings/integrations/%(integration)s/new', ['repo_group_name', 'integration']);
333 335 pyroutes.register('repo_group_integrations_edit', '/%(repo_group_name)s/_settings/integrations/%(integration)s/%(integration_id)s', ['repo_group_name', 'integration', 'integration_id']);
334 336 pyroutes.register('repo_group_integrations_home', '/%(repo_group_name)s/_settings/integrations', ['repo_group_name']);
335 337 pyroutes.register('repo_group_integrations_list', '/%(repo_group_name)s/_settings/integrations/%(integration)s', ['repo_group_name', 'integration']);
336 338 pyroutes.register('repo_group_integrations_new', '/%(repo_group_name)s/_settings/integrations/new', ['repo_group_name']);
337 339 pyroutes.register('repo_group_list_data', '/_repo_groups', []);
338 340 pyroutes.register('repo_group_new', '/_admin/repo_group/new', []);
339 341 pyroutes.register('repo_groups', '/_admin/repo_groups', []);
340 342 pyroutes.register('repo_groups_data', '/_admin/repo_groups_data', []);
341 343 pyroutes.register('repo_integrations_create', '/%(repo_name)s/settings/integrations/%(integration)s/new', ['repo_name', 'integration']);
342 344 pyroutes.register('repo_integrations_edit', '/%(repo_name)s/settings/integrations/%(integration)s/%(integration_id)s', ['repo_name', 'integration', 'integration_id']);
343 345 pyroutes.register('repo_integrations_home', '/%(repo_name)s/settings/integrations', ['repo_name']);
344 346 pyroutes.register('repo_integrations_list', '/%(repo_name)s/settings/integrations/%(integration)s', ['repo_name', 'integration']);
345 347 pyroutes.register('repo_integrations_new', '/%(repo_name)s/settings/integrations/new', ['repo_name']);
346 348 pyroutes.register('repo_list_data', '/_repos', []);
347 349 pyroutes.register('repo_new', '/_admin/repos/new', []);
348 350 pyroutes.register('repo_nodetree_full', '/%(repo_name)s/nodetree_full/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
349 351 pyroutes.register('repo_nodetree_full:default_path', '/%(repo_name)s/nodetree_full/%(commit_id)s/', ['repo_name', 'commit_id']);
350 352 pyroutes.register('repo_refs_changelog_data', '/%(repo_name)s/refs-data-changelog', ['repo_name']);
351 353 pyroutes.register('repo_refs_data', '/%(repo_name)s/refs-data', ['repo_name']);
352 354 pyroutes.register('repo_reviewers', '/%(repo_name)s/settings/review/rules', ['repo_name']);
353 355 pyroutes.register('repo_reviewers_review_rule_delete', '/%(repo_name)s/settings/review/rules/%(rule_id)s/delete', ['repo_name', 'rule_id']);
354 356 pyroutes.register('repo_reviewers_review_rule_edit', '/%(repo_name)s/settings/review/rules/%(rule_id)s', ['repo_name', 'rule_id']);
355 357 pyroutes.register('repo_reviewers_review_rule_new', '/%(repo_name)s/settings/review/rules/new', ['repo_name']);
356 358 pyroutes.register('repo_stats', '/%(repo_name)s/repo_stats/%(commit_id)s', ['repo_name', 'commit_id']);
357 359 pyroutes.register('repo_summary', '/%(repo_name)s', ['repo_name']);
358 360 pyroutes.register('repo_summary_commits', '/%(repo_name)s/summary-commits', ['repo_name']);
359 361 pyroutes.register('repo_summary_explicit', '/%(repo_name)s/summary', ['repo_name']);
360 362 pyroutes.register('repo_summary_slash', '/%(repo_name)s/', ['repo_name']);
361 363 pyroutes.register('repos', '/_admin/repos', []);
362 364 pyroutes.register('repos_data', '/_admin/repos_data', []);
363 365 pyroutes.register('reset_password', '/_admin/password_reset', []);
364 366 pyroutes.register('reset_password_confirmation', '/_admin/password_reset_confirmation', []);
365 367 pyroutes.register('robots', '/robots.txt', []);
366 368 pyroutes.register('rss_feed_home', '/%(repo_name)s/feed-rss', ['repo_name']);
367 369 pyroutes.register('rss_feed_home_old', '/%(repo_name)s/feed/rss', ['repo_name']);
368 370 pyroutes.register('search', '/_admin/search', []);
369 371 pyroutes.register('search_repo', '/%(repo_name)s/_search', ['repo_name']);
370 372 pyroutes.register('search_repo_alt', '/%(repo_name)s/search', ['repo_name']);
371 373 pyroutes.register('search_repo_group', '/%(repo_group_name)s/_search', ['repo_group_name']);
372 374 pyroutes.register('store_user_session_value', '/_store_session_attr', []);
373 375 pyroutes.register('strip_check', '/%(repo_name)s/settings/strip_check', ['repo_name']);
374 376 pyroutes.register('strip_execute', '/%(repo_name)s/settings/strip_execute', ['repo_name']);
375 377 pyroutes.register('tags_home', '/%(repo_name)s/tags', ['repo_name']);
376 378 pyroutes.register('toggle_following', '/_admin/toggle_following', []);
377 379 pyroutes.register('upload_file', '/_file_store/upload', []);
378 380 pyroutes.register('user_autocomplete_data', '/_users', []);
379 381 pyroutes.register('user_create_personal_repo_group', '/_admin/users/%(user_id)s/create_repo_group', ['user_id']);
380 382 pyroutes.register('user_delete', '/_admin/users/%(user_id)s/delete', ['user_id']);
381 383 pyroutes.register('user_disable_force_password_reset', '/_admin/users/%(user_id)s/password_reset_disable', ['user_id']);
382 384 pyroutes.register('user_edit', '/_admin/users/%(user_id)s/edit', ['user_id']);
383 385 pyroutes.register('user_edit_advanced', '/_admin/users/%(user_id)s/edit/advanced', ['user_id']);
384 386 pyroutes.register('user_edit_global_perms', '/_admin/users/%(user_id)s/edit/global_permissions', ['user_id']);
385 387 pyroutes.register('user_edit_global_perms_update', '/_admin/users/%(user_id)s/edit/global_permissions/update', ['user_id']);
386 388 pyroutes.register('user_enable_force_password_reset', '/_admin/users/%(user_id)s/password_reset_enable', ['user_id']);
387 389 pyroutes.register('user_group_autocomplete_data', '/_user_groups', []);
388 390 pyroutes.register('user_group_members_data', '/_admin/user_groups/%(user_group_id)s/members', ['user_group_id']);
389 391 pyroutes.register('user_group_profile', '/_profile_user_group/%(user_group_name)s', ['user_group_name']);
390 392 pyroutes.register('user_groups', '/_admin/user_groups', []);
391 393 pyroutes.register('user_groups_create', '/_admin/user_groups/create', []);
392 394 pyroutes.register('user_groups_data', '/_admin/user_groups_data', []);
393 395 pyroutes.register('user_groups_delete', '/_admin/user_groups/%(user_group_id)s/delete', ['user_group_id']);
394 396 pyroutes.register('user_groups_new', '/_admin/user_groups/new', []);
395 397 pyroutes.register('user_groups_update', '/_admin/user_groups/%(user_group_id)s/update', ['user_group_id']);
396 398 pyroutes.register('user_notice_dismiss', '/_admin/users/%(user_id)s/notice_dismiss', ['user_id']);
397 399 pyroutes.register('user_profile', '/_profiles/%(username)s', ['username']);
398 400 pyroutes.register('user_update', '/_admin/users/%(user_id)s/update', ['user_id']);
399 401 pyroutes.register('users', '/_admin/users', []);
400 402 pyroutes.register('users_create', '/_admin/users/create', []);
401 403 pyroutes.register('users_data', '/_admin/users_data', []);
402 404 pyroutes.register('users_new', '/_admin/users/new', []);
403 405 }
General Comments 0
You need to be logged in to leave comments. Login now