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