##// END OF EJS Templates
utils: added code for sending test emails.
marcink -
r4439:1d4ce874 default
parent child Browse files
Show More
@@ -1,784 +1,800 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 """
21 """
22 Utilities library for RhodeCode
22 Utilities library for RhodeCode
23 """
23 """
24
24
25 import datetime
25 import datetime
26 import decorator
26 import decorator
27 import json
27 import json
28 import logging
28 import logging
29 import os
29 import os
30 import re
30 import re
31 import sys
31 import sys
32 import shutil
32 import shutil
33 import socket
33 import tempfile
34 import tempfile
34 import traceback
35 import traceback
35 import tarfile
36 import tarfile
36 import warnings
37 import warnings
37 import hashlib
38 import hashlib
38 from os.path import join as jn
39 from os.path import join as jn
39
40
40 import paste
41 import paste
41 import pkg_resources
42 import pkg_resources
42 from webhelpers2.text import collapse, remove_formatting
43 from webhelpers2.text import collapse, remove_formatting
43 from mako import exceptions
44 from mako import exceptions
44 from pyramid.threadlocal import get_current_registry
45 from pyramid.threadlocal import get_current_registry
45 from rhodecode.lib.request import Request
46 from rhodecode.lib.request import Request
46
47
47 from rhodecode.lib.vcs.backends.base import Config
48 from rhodecode.lib.vcs.backends.base import Config
48 from rhodecode.lib.vcs.exceptions import VCSError
49 from rhodecode.lib.vcs.exceptions import VCSError
49 from rhodecode.lib.vcs.utils.helpers import get_scm, get_scm_backend
50 from rhodecode.lib.vcs.utils.helpers import get_scm, get_scm_backend
50 from rhodecode.lib.utils2 import (
51 from rhodecode.lib.utils2 import (
51 safe_str, safe_unicode, get_current_rhodecode_user, md5, sha1)
52 safe_str, safe_unicode, get_current_rhodecode_user, md5, sha1)
52 from rhodecode.model import meta
53 from rhodecode.model import meta
53 from rhodecode.model.db import (
54 from rhodecode.model.db import (
54 Repository, User, RhodeCodeUi, UserLog, RepoGroup, UserGroup)
55 Repository, User, RhodeCodeUi, UserLog, RepoGroup, UserGroup)
55 from rhodecode.model.meta import Session
56 from rhodecode.model.meta import Session
56
57
57
58
58 log = logging.getLogger(__name__)
59 log = logging.getLogger(__name__)
59
60
60 REMOVED_REPO_PAT = re.compile(r'rm__\d{8}_\d{6}_\d{6}__.*')
61 REMOVED_REPO_PAT = re.compile(r'rm__\d{8}_\d{6}_\d{6}__.*')
61
62
62 # String which contains characters that are not allowed in slug names for
63 # String which contains characters that are not allowed in slug names for
63 # repositories or repository groups. It is properly escaped to use it in
64 # repositories or repository groups. It is properly escaped to use it in
64 # regular expressions.
65 # regular expressions.
65 SLUG_BAD_CHARS = re.escape('`?=[]\;\'"<>,/~!@#$%^&*()+{}|:')
66 SLUG_BAD_CHARS = re.escape('`?=[]\;\'"<>,/~!@#$%^&*()+{}|:')
66
67
67 # Regex that matches forbidden characters in repo/group slugs.
68 # Regex that matches forbidden characters in repo/group slugs.
68 SLUG_BAD_CHAR_RE = re.compile('[{}]'.format(SLUG_BAD_CHARS))
69 SLUG_BAD_CHAR_RE = re.compile('[{}]'.format(SLUG_BAD_CHARS))
69
70
70 # Regex that matches allowed characters in repo/group slugs.
71 # Regex that matches allowed characters in repo/group slugs.
71 SLUG_GOOD_CHAR_RE = re.compile('[^{}]'.format(SLUG_BAD_CHARS))
72 SLUG_GOOD_CHAR_RE = re.compile('[^{}]'.format(SLUG_BAD_CHARS))
72
73
73 # Regex that matches whole repo/group slugs.
74 # Regex that matches whole repo/group slugs.
74 SLUG_RE = re.compile('[^{}]+'.format(SLUG_BAD_CHARS))
75 SLUG_RE = re.compile('[^{}]+'.format(SLUG_BAD_CHARS))
75
76
76 _license_cache = None
77 _license_cache = None
77
78
78
79
79 def repo_name_slug(value):
80 def repo_name_slug(value):
80 """
81 """
81 Return slug of name of repository
82 Return slug of name of repository
82 This function is called on each creation/modification
83 This function is called on each creation/modification
83 of repository to prevent bad names in repo
84 of repository to prevent bad names in repo
84 """
85 """
85 replacement_char = '-'
86 replacement_char = '-'
86
87
87 slug = remove_formatting(value)
88 slug = remove_formatting(value)
88 slug = SLUG_BAD_CHAR_RE.sub('', slug)
89 slug = SLUG_BAD_CHAR_RE.sub('', slug)
89 slug = re.sub('[\s]+', '-', slug)
90 slug = re.sub('[\s]+', '-', slug)
90 slug = collapse(slug, replacement_char)
91 slug = collapse(slug, replacement_char)
91 return slug
92 return slug
92
93
93
94
94 #==============================================================================
95 #==============================================================================
95 # PERM DECORATOR HELPERS FOR EXTRACTING NAMES FOR PERM CHECKS
96 # PERM DECORATOR HELPERS FOR EXTRACTING NAMES FOR PERM CHECKS
96 #==============================================================================
97 #==============================================================================
97 def get_repo_slug(request):
98 def get_repo_slug(request):
98 _repo = ''
99 _repo = ''
99
100
100 if hasattr(request, 'db_repo'):
101 if hasattr(request, 'db_repo'):
101 # if our requests has set db reference use it for name, this
102 # if our requests has set db reference use it for name, this
102 # translates the example.com/_<id> into proper repo names
103 # translates the example.com/_<id> into proper repo names
103 _repo = request.db_repo.repo_name
104 _repo = request.db_repo.repo_name
104 elif getattr(request, 'matchdict', None):
105 elif getattr(request, 'matchdict', None):
105 # pyramid
106 # pyramid
106 _repo = request.matchdict.get('repo_name')
107 _repo = request.matchdict.get('repo_name')
107
108
108 if _repo:
109 if _repo:
109 _repo = _repo.rstrip('/')
110 _repo = _repo.rstrip('/')
110 return _repo
111 return _repo
111
112
112
113
113 def get_repo_group_slug(request):
114 def get_repo_group_slug(request):
114 _group = ''
115 _group = ''
115 if hasattr(request, 'db_repo_group'):
116 if hasattr(request, 'db_repo_group'):
116 # if our requests has set db reference use it for name, this
117 # if our requests has set db reference use it for name, this
117 # translates the example.com/_<id> into proper repo group names
118 # translates the example.com/_<id> into proper repo group names
118 _group = request.db_repo_group.group_name
119 _group = request.db_repo_group.group_name
119 elif getattr(request, 'matchdict', None):
120 elif getattr(request, 'matchdict', None):
120 # pyramid
121 # pyramid
121 _group = request.matchdict.get('repo_group_name')
122 _group = request.matchdict.get('repo_group_name')
122
123
123 if _group:
124 if _group:
124 _group = _group.rstrip('/')
125 _group = _group.rstrip('/')
125 return _group
126 return _group
126
127
127
128
128 def get_user_group_slug(request):
129 def get_user_group_slug(request):
129 _user_group = ''
130 _user_group = ''
130
131
131 if hasattr(request, 'db_user_group'):
132 if hasattr(request, 'db_user_group'):
132 _user_group = request.db_user_group.users_group_name
133 _user_group = request.db_user_group.users_group_name
133 elif getattr(request, 'matchdict', None):
134 elif getattr(request, 'matchdict', None):
134 # pyramid
135 # pyramid
135 _user_group = request.matchdict.get('user_group_id')
136 _user_group = request.matchdict.get('user_group_id')
136 _user_group_name = request.matchdict.get('user_group_name')
137 _user_group_name = request.matchdict.get('user_group_name')
137 try:
138 try:
138 if _user_group:
139 if _user_group:
139 _user_group = UserGroup.get(_user_group)
140 _user_group = UserGroup.get(_user_group)
140 elif _user_group_name:
141 elif _user_group_name:
141 _user_group = UserGroup.get_by_group_name(_user_group_name)
142 _user_group = UserGroup.get_by_group_name(_user_group_name)
142
143
143 if _user_group:
144 if _user_group:
144 _user_group = _user_group.users_group_name
145 _user_group = _user_group.users_group_name
145 except Exception:
146 except Exception:
146 log.exception('Failed to get user group by id and name')
147 log.exception('Failed to get user group by id and name')
147 # catch all failures here
148 # catch all failures here
148 return None
149 return None
149
150
150 return _user_group
151 return _user_group
151
152
152
153
153 def get_filesystem_repos(path, recursive=False, skip_removed_repos=True):
154 def get_filesystem_repos(path, recursive=False, skip_removed_repos=True):
154 """
155 """
155 Scans given path for repos and return (name,(type,path)) tuple
156 Scans given path for repos and return (name,(type,path)) tuple
156
157
157 :param path: path to scan for repositories
158 :param path: path to scan for repositories
158 :param recursive: recursive search and return names with subdirs in front
159 :param recursive: recursive search and return names with subdirs in front
159 """
160 """
160
161
161 # remove ending slash for better results
162 # remove ending slash for better results
162 path = path.rstrip(os.sep)
163 path = path.rstrip(os.sep)
163 log.debug('now scanning in %s location recursive:%s...', path, recursive)
164 log.debug('now scanning in %s location recursive:%s...', path, recursive)
164
165
165 def _get_repos(p):
166 def _get_repos(p):
166 dirpaths = _get_dirpaths(p)
167 dirpaths = _get_dirpaths(p)
167 if not _is_dir_writable(p):
168 if not _is_dir_writable(p):
168 log.warning('repo path without write access: %s', p)
169 log.warning('repo path without write access: %s', p)
169
170
170 for dirpath in dirpaths:
171 for dirpath in dirpaths:
171 if os.path.isfile(os.path.join(p, dirpath)):
172 if os.path.isfile(os.path.join(p, dirpath)):
172 continue
173 continue
173 cur_path = os.path.join(p, dirpath)
174 cur_path = os.path.join(p, dirpath)
174
175
175 # skip removed repos
176 # skip removed repos
176 if skip_removed_repos and REMOVED_REPO_PAT.match(dirpath):
177 if skip_removed_repos and REMOVED_REPO_PAT.match(dirpath):
177 continue
178 continue
178
179
179 #skip .<somethin> dirs
180 #skip .<somethin> dirs
180 if dirpath.startswith('.'):
181 if dirpath.startswith('.'):
181 continue
182 continue
182
183
183 try:
184 try:
184 scm_info = get_scm(cur_path)
185 scm_info = get_scm(cur_path)
185 yield scm_info[1].split(path, 1)[-1].lstrip(os.sep), scm_info
186 yield scm_info[1].split(path, 1)[-1].lstrip(os.sep), scm_info
186 except VCSError:
187 except VCSError:
187 if not recursive:
188 if not recursive:
188 continue
189 continue
189 #check if this dir containts other repos for recursive scan
190 #check if this dir containts other repos for recursive scan
190 rec_path = os.path.join(p, dirpath)
191 rec_path = os.path.join(p, dirpath)
191 if os.path.isdir(rec_path):
192 if os.path.isdir(rec_path):
192 for inner_scm in _get_repos(rec_path):
193 for inner_scm in _get_repos(rec_path):
193 yield inner_scm
194 yield inner_scm
194
195
195 return _get_repos(path)
196 return _get_repos(path)
196
197
197
198
198 def _get_dirpaths(p):
199 def _get_dirpaths(p):
199 try:
200 try:
200 # OS-independable way of checking if we have at least read-only
201 # OS-independable way of checking if we have at least read-only
201 # access or not.
202 # access or not.
202 dirpaths = os.listdir(p)
203 dirpaths = os.listdir(p)
203 except OSError:
204 except OSError:
204 log.warning('ignoring repo path without read access: %s', p)
205 log.warning('ignoring repo path without read access: %s', p)
205 return []
206 return []
206
207
207 # os.listpath has a tweak: If a unicode is passed into it, then it tries to
208 # os.listpath has a tweak: If a unicode is passed into it, then it tries to
208 # decode paths and suddenly returns unicode objects itself. The items it
209 # decode paths and suddenly returns unicode objects itself. The items it
209 # cannot decode are returned as strings and cause issues.
210 # cannot decode are returned as strings and cause issues.
210 #
211 #
211 # Those paths are ignored here until a solid solution for path handling has
212 # Those paths are ignored here until a solid solution for path handling has
212 # been built.
213 # been built.
213 expected_type = type(p)
214 expected_type = type(p)
214
215
215 def _has_correct_type(item):
216 def _has_correct_type(item):
216 if type(item) is not expected_type:
217 if type(item) is not expected_type:
217 log.error(
218 log.error(
218 u"Ignoring path %s since it cannot be decoded into unicode.",
219 u"Ignoring path %s since it cannot be decoded into unicode.",
219 # Using "repr" to make sure that we see the byte value in case
220 # Using "repr" to make sure that we see the byte value in case
220 # of support.
221 # of support.
221 repr(item))
222 repr(item))
222 return False
223 return False
223 return True
224 return True
224
225
225 dirpaths = [item for item in dirpaths if _has_correct_type(item)]
226 dirpaths = [item for item in dirpaths if _has_correct_type(item)]
226
227
227 return dirpaths
228 return dirpaths
228
229
229
230
230 def _is_dir_writable(path):
231 def _is_dir_writable(path):
231 """
232 """
232 Probe if `path` is writable.
233 Probe if `path` is writable.
233
234
234 Due to trouble on Cygwin / Windows, this is actually probing if it is
235 Due to trouble on Cygwin / Windows, this is actually probing if it is
235 possible to create a file inside of `path`, stat does not produce reliable
236 possible to create a file inside of `path`, stat does not produce reliable
236 results in this case.
237 results in this case.
237 """
238 """
238 try:
239 try:
239 with tempfile.TemporaryFile(dir=path):
240 with tempfile.TemporaryFile(dir=path):
240 pass
241 pass
241 except OSError:
242 except OSError:
242 return False
243 return False
243 return True
244 return True
244
245
245
246
246 def is_valid_repo(repo_name, base_path, expect_scm=None, explicit_scm=None, config=None):
247 def is_valid_repo(repo_name, base_path, expect_scm=None, explicit_scm=None, config=None):
247 """
248 """
248 Returns True if given path is a valid repository False otherwise.
249 Returns True if given path is a valid repository False otherwise.
249 If expect_scm param is given also, compare if given scm is the same
250 If expect_scm param is given also, compare if given scm is the same
250 as expected from scm parameter. If explicit_scm is given don't try to
251 as expected from scm parameter. If explicit_scm is given don't try to
251 detect the scm, just use the given one to check if repo is valid
252 detect the scm, just use the given one to check if repo is valid
252
253
253 :param repo_name:
254 :param repo_name:
254 :param base_path:
255 :param base_path:
255 :param expect_scm:
256 :param expect_scm:
256 :param explicit_scm:
257 :param explicit_scm:
257 :param config:
258 :param config:
258
259
259 :return True: if given path is a valid repository
260 :return True: if given path is a valid repository
260 """
261 """
261 full_path = os.path.join(safe_str(base_path), safe_str(repo_name))
262 full_path = os.path.join(safe_str(base_path), safe_str(repo_name))
262 log.debug('Checking if `%s` is a valid path for repository. '
263 log.debug('Checking if `%s` is a valid path for repository. '
263 'Explicit type: %s', repo_name, explicit_scm)
264 'Explicit type: %s', repo_name, explicit_scm)
264
265
265 try:
266 try:
266 if explicit_scm:
267 if explicit_scm:
267 detected_scms = [get_scm_backend(explicit_scm)(
268 detected_scms = [get_scm_backend(explicit_scm)(
268 full_path, config=config).alias]
269 full_path, config=config).alias]
269 else:
270 else:
270 detected_scms = get_scm(full_path)
271 detected_scms = get_scm(full_path)
271
272
272 if expect_scm:
273 if expect_scm:
273 return detected_scms[0] == expect_scm
274 return detected_scms[0] == expect_scm
274 log.debug('path: %s is an vcs object:%s', full_path, detected_scms)
275 log.debug('path: %s is an vcs object:%s', full_path, detected_scms)
275 return True
276 return True
276 except VCSError:
277 except VCSError:
277 log.debug('path: %s is not a valid repo !', full_path)
278 log.debug('path: %s is not a valid repo !', full_path)
278 return False
279 return False
279
280
280
281
281 def is_valid_repo_group(repo_group_name, base_path, skip_path_check=False):
282 def is_valid_repo_group(repo_group_name, base_path, skip_path_check=False):
282 """
283 """
283 Returns True if given path is a repository group, False otherwise
284 Returns True if given path is a repository group, False otherwise
284
285
285 :param repo_name:
286 :param repo_name:
286 :param base_path:
287 :param base_path:
287 """
288 """
288 full_path = os.path.join(safe_str(base_path), safe_str(repo_group_name))
289 full_path = os.path.join(safe_str(base_path), safe_str(repo_group_name))
289 log.debug('Checking if `%s` is a valid path for repository group',
290 log.debug('Checking if `%s` is a valid path for repository group',
290 repo_group_name)
291 repo_group_name)
291
292
292 # check if it's not a repo
293 # check if it's not a repo
293 if is_valid_repo(repo_group_name, base_path):
294 if is_valid_repo(repo_group_name, base_path):
294 log.debug('Repo called %s exist, it is not a valid repo group', repo_group_name)
295 log.debug('Repo called %s exist, it is not a valid repo group', repo_group_name)
295 return False
296 return False
296
297
297 try:
298 try:
298 # we need to check bare git repos at higher level
299 # we need to check bare git repos at higher level
299 # since we might match branches/hooks/info/objects or possible
300 # since we might match branches/hooks/info/objects or possible
300 # other things inside bare git repo
301 # other things inside bare git repo
301 maybe_repo = os.path.dirname(full_path)
302 maybe_repo = os.path.dirname(full_path)
302 if maybe_repo == base_path:
303 if maybe_repo == base_path:
303 # skip root level repo check, we know root location CANNOT BE a repo group
304 # skip root level repo check, we know root location CANNOT BE a repo group
304 return False
305 return False
305
306
306 scm_ = get_scm(maybe_repo)
307 scm_ = get_scm(maybe_repo)
307 log.debug('path: %s is a vcs object:%s, not valid repo group', full_path, scm_)
308 log.debug('path: %s is a vcs object:%s, not valid repo group', full_path, scm_)
308 return False
309 return False
309 except VCSError:
310 except VCSError:
310 pass
311 pass
311
312
312 # check if it's a valid path
313 # check if it's a valid path
313 if skip_path_check or os.path.isdir(full_path):
314 if skip_path_check or os.path.isdir(full_path):
314 log.debug('path: %s is a valid repo group !', full_path)
315 log.debug('path: %s is a valid repo group !', full_path)
315 return True
316 return True
316
317
317 log.debug('path: %s is not a valid repo group !', full_path)
318 log.debug('path: %s is not a valid repo group !', full_path)
318 return False
319 return False
319
320
320
321
321 def ask_ok(prompt, retries=4, complaint='[y]es or [n]o please!'):
322 def ask_ok(prompt, retries=4, complaint='[y]es or [n]o please!'):
322 while True:
323 while True:
323 ok = raw_input(prompt)
324 ok = raw_input(prompt)
324 if ok.lower() in ('y', 'ye', 'yes'):
325 if ok.lower() in ('y', 'ye', 'yes'):
325 return True
326 return True
326 if ok.lower() in ('n', 'no', 'nop', 'nope'):
327 if ok.lower() in ('n', 'no', 'nop', 'nope'):
327 return False
328 return False
328 retries = retries - 1
329 retries = retries - 1
329 if retries < 0:
330 if retries < 0:
330 raise IOError
331 raise IOError
331 print(complaint)
332 print(complaint)
332
333
333 # propagated from mercurial documentation
334 # propagated from mercurial documentation
334 ui_sections = [
335 ui_sections = [
335 'alias', 'auth',
336 'alias', 'auth',
336 'decode/encode', 'defaults',
337 'decode/encode', 'defaults',
337 'diff', 'email',
338 'diff', 'email',
338 'extensions', 'format',
339 'extensions', 'format',
339 'merge-patterns', 'merge-tools',
340 'merge-patterns', 'merge-tools',
340 'hooks', 'http_proxy',
341 'hooks', 'http_proxy',
341 'smtp', 'patch',
342 'smtp', 'patch',
342 'paths', 'profiling',
343 'paths', 'profiling',
343 'server', 'trusted',
344 'server', 'trusted',
344 'ui', 'web', ]
345 'ui', 'web', ]
345
346
346
347
347 def config_data_from_db(clear_session=True, repo=None):
348 def config_data_from_db(clear_session=True, repo=None):
348 """
349 """
349 Read the configuration data from the database and return configuration
350 Read the configuration data from the database and return configuration
350 tuples.
351 tuples.
351 """
352 """
352 from rhodecode.model.settings import VcsSettingsModel
353 from rhodecode.model.settings import VcsSettingsModel
353
354
354 config = []
355 config = []
355
356
356 sa = meta.Session()
357 sa = meta.Session()
357 settings_model = VcsSettingsModel(repo=repo, sa=sa)
358 settings_model = VcsSettingsModel(repo=repo, sa=sa)
358
359
359 ui_settings = settings_model.get_ui_settings()
360 ui_settings = settings_model.get_ui_settings()
360
361
361 ui_data = []
362 ui_data = []
362 for setting in ui_settings:
363 for setting in ui_settings:
363 if setting.active:
364 if setting.active:
364 ui_data.append((setting.section, setting.key, setting.value))
365 ui_data.append((setting.section, setting.key, setting.value))
365 config.append((
366 config.append((
366 safe_str(setting.section), safe_str(setting.key),
367 safe_str(setting.section), safe_str(setting.key),
367 safe_str(setting.value)))
368 safe_str(setting.value)))
368 if setting.key == 'push_ssl':
369 if setting.key == 'push_ssl':
369 # force set push_ssl requirement to False, rhodecode
370 # force set push_ssl requirement to False, rhodecode
370 # handles that
371 # handles that
371 config.append((
372 config.append((
372 safe_str(setting.section), safe_str(setting.key), False))
373 safe_str(setting.section), safe_str(setting.key), False))
373 log.debug(
374 log.debug(
374 'settings ui from db@repo[%s]: %s',
375 'settings ui from db@repo[%s]: %s',
375 repo,
376 repo,
376 ','.join(map(lambda s: '[{}] {}={}'.format(*s), ui_data)))
377 ','.join(map(lambda s: '[{}] {}={}'.format(*s), ui_data)))
377 if clear_session:
378 if clear_session:
378 meta.Session.remove()
379 meta.Session.remove()
379
380
380 # TODO: mikhail: probably it makes no sense to re-read hooks information.
381 # TODO: mikhail: probably it makes no sense to re-read hooks information.
381 # It's already there and activated/deactivated
382 # It's already there and activated/deactivated
382 skip_entries = []
383 skip_entries = []
383 enabled_hook_classes = get_enabled_hook_classes(ui_settings)
384 enabled_hook_classes = get_enabled_hook_classes(ui_settings)
384 if 'pull' not in enabled_hook_classes:
385 if 'pull' not in enabled_hook_classes:
385 skip_entries.append(('hooks', RhodeCodeUi.HOOK_PRE_PULL))
386 skip_entries.append(('hooks', RhodeCodeUi.HOOK_PRE_PULL))
386 if 'push' not in enabled_hook_classes:
387 if 'push' not in enabled_hook_classes:
387 skip_entries.append(('hooks', RhodeCodeUi.HOOK_PRE_PUSH))
388 skip_entries.append(('hooks', RhodeCodeUi.HOOK_PRE_PUSH))
388 skip_entries.append(('hooks', RhodeCodeUi.HOOK_PRETX_PUSH))
389 skip_entries.append(('hooks', RhodeCodeUi.HOOK_PRETX_PUSH))
389 skip_entries.append(('hooks', RhodeCodeUi.HOOK_PUSH_KEY))
390 skip_entries.append(('hooks', RhodeCodeUi.HOOK_PUSH_KEY))
390
391
391 config = [entry for entry in config if entry[:2] not in skip_entries]
392 config = [entry for entry in config if entry[:2] not in skip_entries]
392
393
393 return config
394 return config
394
395
395
396
396 def make_db_config(clear_session=True, repo=None):
397 def make_db_config(clear_session=True, repo=None):
397 """
398 """
398 Create a :class:`Config` instance based on the values in the database.
399 Create a :class:`Config` instance based on the values in the database.
399 """
400 """
400 config = Config()
401 config = Config()
401 config_data = config_data_from_db(clear_session=clear_session, repo=repo)
402 config_data = config_data_from_db(clear_session=clear_session, repo=repo)
402 for section, option, value in config_data:
403 for section, option, value in config_data:
403 config.set(section, option, value)
404 config.set(section, option, value)
404 return config
405 return config
405
406
406
407
407 def get_enabled_hook_classes(ui_settings):
408 def get_enabled_hook_classes(ui_settings):
408 """
409 """
409 Return the enabled hook classes.
410 Return the enabled hook classes.
410
411
411 :param ui_settings: List of ui_settings as returned
412 :param ui_settings: List of ui_settings as returned
412 by :meth:`VcsSettingsModel.get_ui_settings`
413 by :meth:`VcsSettingsModel.get_ui_settings`
413
414
414 :return: a list with the enabled hook classes. The order is not guaranteed.
415 :return: a list with the enabled hook classes. The order is not guaranteed.
415 :rtype: list
416 :rtype: list
416 """
417 """
417 enabled_hooks = []
418 enabled_hooks = []
418 active_hook_keys = [
419 active_hook_keys = [
419 key for section, key, value, active in ui_settings
420 key for section, key, value, active in ui_settings
420 if section == 'hooks' and active]
421 if section == 'hooks' and active]
421
422
422 hook_names = {
423 hook_names = {
423 RhodeCodeUi.HOOK_PUSH: 'push',
424 RhodeCodeUi.HOOK_PUSH: 'push',
424 RhodeCodeUi.HOOK_PULL: 'pull',
425 RhodeCodeUi.HOOK_PULL: 'pull',
425 RhodeCodeUi.HOOK_REPO_SIZE: 'repo_size'
426 RhodeCodeUi.HOOK_REPO_SIZE: 'repo_size'
426 }
427 }
427
428
428 for key in active_hook_keys:
429 for key in active_hook_keys:
429 hook = hook_names.get(key)
430 hook = hook_names.get(key)
430 if hook:
431 if hook:
431 enabled_hooks.append(hook)
432 enabled_hooks.append(hook)
432
433
433 return enabled_hooks
434 return enabled_hooks
434
435
435
436
436 def set_rhodecode_config(config):
437 def set_rhodecode_config(config):
437 """
438 """
438 Updates pyramid config with new settings from database
439 Updates pyramid config with new settings from database
439
440
440 :param config:
441 :param config:
441 """
442 """
442 from rhodecode.model.settings import SettingsModel
443 from rhodecode.model.settings import SettingsModel
443 app_settings = SettingsModel().get_all_settings()
444 app_settings = SettingsModel().get_all_settings()
444
445
445 for k, v in app_settings.items():
446 for k, v in app_settings.items():
446 config[k] = v
447 config[k] = v
447
448
448
449
449 def get_rhodecode_realm():
450 def get_rhodecode_realm():
450 """
451 """
451 Return the rhodecode realm from database.
452 Return the rhodecode realm from database.
452 """
453 """
453 from rhodecode.model.settings import SettingsModel
454 from rhodecode.model.settings import SettingsModel
454 realm = SettingsModel().get_setting_by_name('realm')
455 realm = SettingsModel().get_setting_by_name('realm')
455 return safe_str(realm.app_settings_value)
456 return safe_str(realm.app_settings_value)
456
457
457
458
458 def get_rhodecode_base_path():
459 def get_rhodecode_base_path():
459 """
460 """
460 Returns the base path. The base path is the filesystem path which points
461 Returns the base path. The base path is the filesystem path which points
461 to the repository store.
462 to the repository store.
462 """
463 """
463 from rhodecode.model.settings import SettingsModel
464 from rhodecode.model.settings import SettingsModel
464 paths_ui = SettingsModel().get_ui_by_section_and_key('paths', '/')
465 paths_ui = SettingsModel().get_ui_by_section_and_key('paths', '/')
465 return safe_str(paths_ui.ui_value)
466 return safe_str(paths_ui.ui_value)
466
467
467
468
468 def map_groups(path):
469 def map_groups(path):
469 """
470 """
470 Given a full path to a repository, create all nested groups that this
471 Given a full path to a repository, create all nested groups that this
471 repo is inside. This function creates parent-child relationships between
472 repo is inside. This function creates parent-child relationships between
472 groups and creates default perms for all new groups.
473 groups and creates default perms for all new groups.
473
474
474 :param paths: full path to repository
475 :param paths: full path to repository
475 """
476 """
476 from rhodecode.model.repo_group import RepoGroupModel
477 from rhodecode.model.repo_group import RepoGroupModel
477 sa = meta.Session()
478 sa = meta.Session()
478 groups = path.split(Repository.NAME_SEP)
479 groups = path.split(Repository.NAME_SEP)
479 parent = None
480 parent = None
480 group = None
481 group = None
481
482
482 # last element is repo in nested groups structure
483 # last element is repo in nested groups structure
483 groups = groups[:-1]
484 groups = groups[:-1]
484 rgm = RepoGroupModel(sa)
485 rgm = RepoGroupModel(sa)
485 owner = User.get_first_super_admin()
486 owner = User.get_first_super_admin()
486 for lvl, group_name in enumerate(groups):
487 for lvl, group_name in enumerate(groups):
487 group_name = '/'.join(groups[:lvl] + [group_name])
488 group_name = '/'.join(groups[:lvl] + [group_name])
488 group = RepoGroup.get_by_group_name(group_name)
489 group = RepoGroup.get_by_group_name(group_name)
489 desc = '%s group' % group_name
490 desc = '%s group' % group_name
490
491
491 # skip folders that are now removed repos
492 # skip folders that are now removed repos
492 if REMOVED_REPO_PAT.match(group_name):
493 if REMOVED_REPO_PAT.match(group_name):
493 break
494 break
494
495
495 if group is None:
496 if group is None:
496 log.debug('creating group level: %s group_name: %s',
497 log.debug('creating group level: %s group_name: %s',
497 lvl, group_name)
498 lvl, group_name)
498 group = RepoGroup(group_name, parent)
499 group = RepoGroup(group_name, parent)
499 group.group_description = desc
500 group.group_description = desc
500 group.user = owner
501 group.user = owner
501 sa.add(group)
502 sa.add(group)
502 perm_obj = rgm._create_default_perms(group)
503 perm_obj = rgm._create_default_perms(group)
503 sa.add(perm_obj)
504 sa.add(perm_obj)
504 sa.flush()
505 sa.flush()
505
506
506 parent = group
507 parent = group
507 return group
508 return group
508
509
509
510
510 def repo2db_mapper(initial_repo_list, remove_obsolete=False):
511 def repo2db_mapper(initial_repo_list, remove_obsolete=False):
511 """
512 """
512 maps all repos given in initial_repo_list, non existing repositories
513 maps all repos given in initial_repo_list, non existing repositories
513 are created, if remove_obsolete is True it also checks for db entries
514 are created, if remove_obsolete is True it also checks for db entries
514 that are not in initial_repo_list and removes them.
515 that are not in initial_repo_list and removes them.
515
516
516 :param initial_repo_list: list of repositories found by scanning methods
517 :param initial_repo_list: list of repositories found by scanning methods
517 :param remove_obsolete: check for obsolete entries in database
518 :param remove_obsolete: check for obsolete entries in database
518 """
519 """
519 from rhodecode.model.repo import RepoModel
520 from rhodecode.model.repo import RepoModel
520 from rhodecode.model.repo_group import RepoGroupModel
521 from rhodecode.model.repo_group import RepoGroupModel
521 from rhodecode.model.settings import SettingsModel
522 from rhodecode.model.settings import SettingsModel
522
523
523 sa = meta.Session()
524 sa = meta.Session()
524 repo_model = RepoModel()
525 repo_model = RepoModel()
525 user = User.get_first_super_admin()
526 user = User.get_first_super_admin()
526 added = []
527 added = []
527
528
528 # creation defaults
529 # creation defaults
529 defs = SettingsModel().get_default_repo_settings(strip_prefix=True)
530 defs = SettingsModel().get_default_repo_settings(strip_prefix=True)
530 enable_statistics = defs.get('repo_enable_statistics')
531 enable_statistics = defs.get('repo_enable_statistics')
531 enable_locking = defs.get('repo_enable_locking')
532 enable_locking = defs.get('repo_enable_locking')
532 enable_downloads = defs.get('repo_enable_downloads')
533 enable_downloads = defs.get('repo_enable_downloads')
533 private = defs.get('repo_private')
534 private = defs.get('repo_private')
534
535
535 for name, repo in initial_repo_list.items():
536 for name, repo in initial_repo_list.items():
536 group = map_groups(name)
537 group = map_groups(name)
537 unicode_name = safe_unicode(name)
538 unicode_name = safe_unicode(name)
538 db_repo = repo_model.get_by_repo_name(unicode_name)
539 db_repo = repo_model.get_by_repo_name(unicode_name)
539 # found repo that is on filesystem not in RhodeCode database
540 # found repo that is on filesystem not in RhodeCode database
540 if not db_repo:
541 if not db_repo:
541 log.info('repository %s not found, creating now', name)
542 log.info('repository %s not found, creating now', name)
542 added.append(name)
543 added.append(name)
543 desc = (repo.description
544 desc = (repo.description
544 if repo.description != 'unknown'
545 if repo.description != 'unknown'
545 else '%s repository' % name)
546 else '%s repository' % name)
546
547
547 db_repo = repo_model._create_repo(
548 db_repo = repo_model._create_repo(
548 repo_name=name,
549 repo_name=name,
549 repo_type=repo.alias,
550 repo_type=repo.alias,
550 description=desc,
551 description=desc,
551 repo_group=getattr(group, 'group_id', None),
552 repo_group=getattr(group, 'group_id', None),
552 owner=user,
553 owner=user,
553 enable_locking=enable_locking,
554 enable_locking=enable_locking,
554 enable_downloads=enable_downloads,
555 enable_downloads=enable_downloads,
555 enable_statistics=enable_statistics,
556 enable_statistics=enable_statistics,
556 private=private,
557 private=private,
557 state=Repository.STATE_CREATED
558 state=Repository.STATE_CREATED
558 )
559 )
559 sa.commit()
560 sa.commit()
560 # we added that repo just now, and make sure we updated server info
561 # we added that repo just now, and make sure we updated server info
561 if db_repo.repo_type == 'git':
562 if db_repo.repo_type == 'git':
562 git_repo = db_repo.scm_instance()
563 git_repo = db_repo.scm_instance()
563 # update repository server-info
564 # update repository server-info
564 log.debug('Running update server info')
565 log.debug('Running update server info')
565 git_repo._update_server_info()
566 git_repo._update_server_info()
566
567
567 db_repo.update_commit_cache()
568 db_repo.update_commit_cache()
568
569
569 config = db_repo._config
570 config = db_repo._config
570 config.set('extensions', 'largefiles', '')
571 config.set('extensions', 'largefiles', '')
571 repo = db_repo.scm_instance(config=config)
572 repo = db_repo.scm_instance(config=config)
572 repo.install_hooks()
573 repo.install_hooks()
573
574
574 removed = []
575 removed = []
575 if remove_obsolete:
576 if remove_obsolete:
576 # remove from database those repositories that are not in the filesystem
577 # remove from database those repositories that are not in the filesystem
577 for repo in sa.query(Repository).all():
578 for repo in sa.query(Repository).all():
578 if repo.repo_name not in initial_repo_list.keys():
579 if repo.repo_name not in initial_repo_list.keys():
579 log.debug("Removing non-existing repository found in db `%s`",
580 log.debug("Removing non-existing repository found in db `%s`",
580 repo.repo_name)
581 repo.repo_name)
581 try:
582 try:
582 RepoModel(sa).delete(repo, forks='detach', fs_remove=False)
583 RepoModel(sa).delete(repo, forks='detach', fs_remove=False)
583 sa.commit()
584 sa.commit()
584 removed.append(repo.repo_name)
585 removed.append(repo.repo_name)
585 except Exception:
586 except Exception:
586 # don't hold further removals on error
587 # don't hold further removals on error
587 log.error(traceback.format_exc())
588 log.error(traceback.format_exc())
588 sa.rollback()
589 sa.rollback()
589
590
590 def splitter(full_repo_name):
591 def splitter(full_repo_name):
591 _parts = full_repo_name.rsplit(RepoGroup.url_sep(), 1)
592 _parts = full_repo_name.rsplit(RepoGroup.url_sep(), 1)
592 gr_name = None
593 gr_name = None
593 if len(_parts) == 2:
594 if len(_parts) == 2:
594 gr_name = _parts[0]
595 gr_name = _parts[0]
595 return gr_name
596 return gr_name
596
597
597 initial_repo_group_list = [splitter(x) for x in
598 initial_repo_group_list = [splitter(x) for x in
598 initial_repo_list.keys() if splitter(x)]
599 initial_repo_list.keys() if splitter(x)]
599
600
600 # remove from database those repository groups that are not in the
601 # remove from database those repository groups that are not in the
601 # filesystem due to parent child relationships we need to delete them
602 # filesystem due to parent child relationships we need to delete them
602 # in a specific order of most nested first
603 # in a specific order of most nested first
603 all_groups = [x.group_name for x in sa.query(RepoGroup).all()]
604 all_groups = [x.group_name for x in sa.query(RepoGroup).all()]
604 nested_sort = lambda gr: len(gr.split('/'))
605 nested_sort = lambda gr: len(gr.split('/'))
605 for group_name in sorted(all_groups, key=nested_sort, reverse=True):
606 for group_name in sorted(all_groups, key=nested_sort, reverse=True):
606 if group_name not in initial_repo_group_list:
607 if group_name not in initial_repo_group_list:
607 repo_group = RepoGroup.get_by_group_name(group_name)
608 repo_group = RepoGroup.get_by_group_name(group_name)
608 if (repo_group.children.all() or
609 if (repo_group.children.all() or
609 not RepoGroupModel().check_exist_filesystem(
610 not RepoGroupModel().check_exist_filesystem(
610 group_name=group_name, exc_on_failure=False)):
611 group_name=group_name, exc_on_failure=False)):
611 continue
612 continue
612
613
613 log.info(
614 log.info(
614 'Removing non-existing repository group found in db `%s`',
615 'Removing non-existing repository group found in db `%s`',
615 group_name)
616 group_name)
616 try:
617 try:
617 RepoGroupModel(sa).delete(group_name, fs_remove=False)
618 RepoGroupModel(sa).delete(group_name, fs_remove=False)
618 sa.commit()
619 sa.commit()
619 removed.append(group_name)
620 removed.append(group_name)
620 except Exception:
621 except Exception:
621 # don't hold further removals on error
622 # don't hold further removals on error
622 log.exception(
623 log.exception(
623 'Unable to remove repository group `%s`',
624 'Unable to remove repository group `%s`',
624 group_name)
625 group_name)
625 sa.rollback()
626 sa.rollback()
626 raise
627 raise
627
628
628 return added, removed
629 return added, removed
629
630
630
631
631 def load_rcextensions(root_path):
632 def load_rcextensions(root_path):
632 import rhodecode
633 import rhodecode
633 from rhodecode.config import conf
634 from rhodecode.config import conf
634
635
635 path = os.path.join(root_path)
636 path = os.path.join(root_path)
636 sys.path.append(path)
637 sys.path.append(path)
637
638
638 try:
639 try:
639 rcextensions = __import__('rcextensions')
640 rcextensions = __import__('rcextensions')
640 except ImportError:
641 except ImportError:
641 if os.path.isdir(os.path.join(path, 'rcextensions')):
642 if os.path.isdir(os.path.join(path, 'rcextensions')):
642 log.warn('Unable to load rcextensions from %s', path)
643 log.warn('Unable to load rcextensions from %s', path)
643 rcextensions = None
644 rcextensions = None
644
645
645 if rcextensions:
646 if rcextensions:
646 log.debug('Found rcextensions module loaded %s...', rcextensions)
647 log.debug('Found rcextensions module loaded %s...', rcextensions)
647 rhodecode.EXTENSIONS = rcextensions
648 rhodecode.EXTENSIONS = rcextensions
648
649
649 # Additional mappings that are not present in the pygments lexers
650 # Additional mappings that are not present in the pygments lexers
650 conf.LANGUAGES_EXTENSIONS_MAP.update(
651 conf.LANGUAGES_EXTENSIONS_MAP.update(
651 getattr(rhodecode.EXTENSIONS, 'EXTRA_MAPPINGS', {}))
652 getattr(rhodecode.EXTENSIONS, 'EXTRA_MAPPINGS', {}))
652
653
653
654
654 def get_custom_lexer(extension):
655 def get_custom_lexer(extension):
655 """
656 """
656 returns a custom lexer if it is defined in rcextensions module, or None
657 returns a custom lexer if it is defined in rcextensions module, or None
657 if there's no custom lexer defined
658 if there's no custom lexer defined
658 """
659 """
659 import rhodecode
660 import rhodecode
660 from pygments import lexers
661 from pygments import lexers
661
662
662 # custom override made by RhodeCode
663 # custom override made by RhodeCode
663 if extension in ['mako']:
664 if extension in ['mako']:
664 return lexers.get_lexer_by_name('html+mako')
665 return lexers.get_lexer_by_name('html+mako')
665
666
666 # check if we didn't define this extension as other lexer
667 # check if we didn't define this extension as other lexer
667 extensions = rhodecode.EXTENSIONS and getattr(rhodecode.EXTENSIONS, 'EXTRA_LEXERS', None)
668 extensions = rhodecode.EXTENSIONS and getattr(rhodecode.EXTENSIONS, 'EXTRA_LEXERS', None)
668 if extensions and extension in rhodecode.EXTENSIONS.EXTRA_LEXERS:
669 if extensions and extension in rhodecode.EXTENSIONS.EXTRA_LEXERS:
669 _lexer_name = rhodecode.EXTENSIONS.EXTRA_LEXERS[extension]
670 _lexer_name = rhodecode.EXTENSIONS.EXTRA_LEXERS[extension]
670 return lexers.get_lexer_by_name(_lexer_name)
671 return lexers.get_lexer_by_name(_lexer_name)
671
672
672
673
673 #==============================================================================
674 #==============================================================================
674 # TEST FUNCTIONS AND CREATORS
675 # TEST FUNCTIONS AND CREATORS
675 #==============================================================================
676 #==============================================================================
676 def create_test_index(repo_location, config):
677 def create_test_index(repo_location, config):
677 """
678 """
678 Makes default test index.
679 Makes default test index.
679 """
680 """
680 import rc_testdata
681 import rc_testdata
681
682
682 rc_testdata.extract_search_index(
683 rc_testdata.extract_search_index(
683 'vcs_search_index', os.path.dirname(config['search.location']))
684 'vcs_search_index', os.path.dirname(config['search.location']))
684
685
685
686
686 def create_test_directory(test_path):
687 def create_test_directory(test_path):
687 """
688 """
688 Create test directory if it doesn't exist.
689 Create test directory if it doesn't exist.
689 """
690 """
690 if not os.path.isdir(test_path):
691 if not os.path.isdir(test_path):
691 log.debug('Creating testdir %s', test_path)
692 log.debug('Creating testdir %s', test_path)
692 os.makedirs(test_path)
693 os.makedirs(test_path)
693
694
694
695
695 def create_test_database(test_path, config):
696 def create_test_database(test_path, config):
696 """
697 """
697 Makes a fresh database.
698 Makes a fresh database.
698 """
699 """
699 from rhodecode.lib.db_manage import DbManage
700 from rhodecode.lib.db_manage import DbManage
700
701
701 # PART ONE create db
702 # PART ONE create db
702 dbconf = config['sqlalchemy.db1.url']
703 dbconf = config['sqlalchemy.db1.url']
703 log.debug('making test db %s', dbconf)
704 log.debug('making test db %s', dbconf)
704
705
705 dbmanage = DbManage(log_sql=False, dbconf=dbconf, root=config['here'],
706 dbmanage = DbManage(log_sql=False, dbconf=dbconf, root=config['here'],
706 tests=True, cli_args={'force_ask': True})
707 tests=True, cli_args={'force_ask': True})
707 dbmanage.create_tables(override=True)
708 dbmanage.create_tables(override=True)
708 dbmanage.set_db_version()
709 dbmanage.set_db_version()
709 # for tests dynamically set new root paths based on generated content
710 # for tests dynamically set new root paths based on generated content
710 dbmanage.create_settings(dbmanage.config_prompt(test_path))
711 dbmanage.create_settings(dbmanage.config_prompt(test_path))
711 dbmanage.create_default_user()
712 dbmanage.create_default_user()
712 dbmanage.create_test_admin_and_users()
713 dbmanage.create_test_admin_and_users()
713 dbmanage.create_permissions()
714 dbmanage.create_permissions()
714 dbmanage.populate_default_permissions()
715 dbmanage.populate_default_permissions()
715 Session().commit()
716 Session().commit()
716
717
717
718
718 def create_test_repositories(test_path, config):
719 def create_test_repositories(test_path, config):
719 """
720 """
720 Creates test repositories in the temporary directory. Repositories are
721 Creates test repositories in the temporary directory. Repositories are
721 extracted from archives within the rc_testdata package.
722 extracted from archives within the rc_testdata package.
722 """
723 """
723 import rc_testdata
724 import rc_testdata
724 from rhodecode.tests import HG_REPO, GIT_REPO, SVN_REPO
725 from rhodecode.tests import HG_REPO, GIT_REPO, SVN_REPO
725
726
726 log.debug('making test vcs repositories')
727 log.debug('making test vcs repositories')
727
728
728 idx_path = config['search.location']
729 idx_path = config['search.location']
729 data_path = config['cache_dir']
730 data_path = config['cache_dir']
730
731
731 # clean index and data
732 # clean index and data
732 if idx_path and os.path.exists(idx_path):
733 if idx_path and os.path.exists(idx_path):
733 log.debug('remove %s', idx_path)
734 log.debug('remove %s', idx_path)
734 shutil.rmtree(idx_path)
735 shutil.rmtree(idx_path)
735
736
736 if data_path and os.path.exists(data_path):
737 if data_path and os.path.exists(data_path):
737 log.debug('remove %s', data_path)
738 log.debug('remove %s', data_path)
738 shutil.rmtree(data_path)
739 shutil.rmtree(data_path)
739
740
740 rc_testdata.extract_hg_dump('vcs_test_hg', jn(test_path, HG_REPO))
741 rc_testdata.extract_hg_dump('vcs_test_hg', jn(test_path, HG_REPO))
741 rc_testdata.extract_git_dump('vcs_test_git', jn(test_path, GIT_REPO))
742 rc_testdata.extract_git_dump('vcs_test_git', jn(test_path, GIT_REPO))
742
743
743 # Note: Subversion is in the process of being integrated with the system,
744 # Note: Subversion is in the process of being integrated with the system,
744 # until we have a properly packed version of the test svn repository, this
745 # until we have a properly packed version of the test svn repository, this
745 # tries to copy over the repo from a package "rc_testdata"
746 # tries to copy over the repo from a package "rc_testdata"
746 svn_repo_path = rc_testdata.get_svn_repo_archive()
747 svn_repo_path = rc_testdata.get_svn_repo_archive()
747 with tarfile.open(svn_repo_path) as tar:
748 with tarfile.open(svn_repo_path) as tar:
748 tar.extractall(jn(test_path, SVN_REPO))
749 tar.extractall(jn(test_path, SVN_REPO))
749
750
750
751
751 def password_changed(auth_user, session):
752 def password_changed(auth_user, session):
752 # Never report password change in case of default user or anonymous user.
753 # Never report password change in case of default user or anonymous user.
753 if auth_user.username == User.DEFAULT_USER or auth_user.user_id is None:
754 if auth_user.username == User.DEFAULT_USER or auth_user.user_id is None:
754 return False
755 return False
755
756
756 password_hash = md5(auth_user.password) if auth_user.password else None
757 password_hash = md5(auth_user.password) if auth_user.password else None
757 rhodecode_user = session.get('rhodecode_user', {})
758 rhodecode_user = session.get('rhodecode_user', {})
758 session_password_hash = rhodecode_user.get('password', '')
759 session_password_hash = rhodecode_user.get('password', '')
759 return password_hash != session_password_hash
760 return password_hash != session_password_hash
760
761
761
762
762 def read_opensource_licenses():
763 def read_opensource_licenses():
763 global _license_cache
764 global _license_cache
764
765
765 if not _license_cache:
766 if not _license_cache:
766 licenses = pkg_resources.resource_string(
767 licenses = pkg_resources.resource_string(
767 'rhodecode', 'config/licenses.json')
768 'rhodecode', 'config/licenses.json')
768 _license_cache = json.loads(licenses)
769 _license_cache = json.loads(licenses)
769
770
770 return _license_cache
771 return _license_cache
771
772
772
773
773 def generate_platform_uuid():
774 def generate_platform_uuid():
774 """
775 """
775 Generates platform UUID based on it's name
776 Generates platform UUID based on it's name
776 """
777 """
777 import platform
778 import platform
778
779
779 try:
780 try:
780 uuid_list = [platform.platform()]
781 uuid_list = [platform.platform()]
781 return hashlib.sha256(':'.join(uuid_list)).hexdigest()
782 return hashlib.sha256(':'.join(uuid_list)).hexdigest()
782 except Exception as e:
783 except Exception as e:
783 log.error('Failed to generate host uuid: %s', e)
784 log.error('Failed to generate host uuid: %s', e)
784 return 'UNDEFINED'
785 return 'UNDEFINED'
786
787
788 def send_test_email(recipients, email_body='TEST EMAIL'):
789 """
790 Simple code for generating test emails.
791 Usage::
792
793 from rhodecode.lib import utils
794 utils.send_test_email()
795 """
796 from rhodecode.lib.celerylib import tasks, run_task
797
798 email_body = email_body_plaintext = email_body
799 subject = 'SUBJECT FROM: {}'.format(socket.gethostname())
800 tasks.send_email(recipients, subject, email_body_plaintext, email_body)
General Comments 0
You need to be logged in to leave comments. Login now