##// END OF EJS Templates
Added optional flag to make_ui to not clean sqlalchemy Session....
marcink -
r2717:dd240b2b beta
parent child Browse files
Show More
@@ -1,668 +1,668 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.lib.utils
3 rhodecode.lib.utils
4 ~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~
5
5
6 Utilities library for RhodeCode
6 Utilities library for RhodeCode
7
7
8 :created_on: Apr 18, 2010
8 :created_on: Apr 18, 2010
9 :author: marcink
9 :author: marcink
10 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
10 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
11 :license: GPLv3, see COPYING for more details.
11 :license: GPLv3, see COPYING for more details.
12 """
12 """
13 # This program is free software: you can redistribute it and/or modify
13 # This program is free software: you can redistribute it and/or modify
14 # it under the terms of the GNU General Public License as published by
14 # it under the terms of the GNU General Public License as published by
15 # the Free Software Foundation, either version 3 of the License, or
15 # the Free Software Foundation, either version 3 of the License, or
16 # (at your option) any later version.
16 # (at your option) any later version.
17 #
17 #
18 # This program is distributed in the hope that it will be useful,
18 # This program is distributed in the hope that it will be useful,
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # GNU General Public License for more details.
21 # GNU General Public License for more details.
22 #
22 #
23 # You should have received a copy of the GNU General Public License
23 # You should have received a copy of the GNU General Public License
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25
25
26 import os
26 import os
27 import re
27 import re
28 import logging
28 import logging
29 import datetime
29 import datetime
30 import traceback
30 import traceback
31 import paste
31 import paste
32 import beaker
32 import beaker
33 import tarfile
33 import tarfile
34 import shutil
34 import shutil
35 from os.path import abspath
35 from os.path import abspath
36 from os.path import dirname as dn, join as jn
36 from os.path import dirname as dn, join as jn
37
37
38 from paste.script.command import Command, BadCommand
38 from paste.script.command import Command, BadCommand
39
39
40 from mercurial import ui, config
40 from mercurial import ui, config
41
41
42 from webhelpers.text import collapse, remove_formatting, strip_tags
42 from webhelpers.text import collapse, remove_formatting, strip_tags
43
43
44 from rhodecode.lib.vcs import get_backend
44 from rhodecode.lib.vcs import get_backend
45 from rhodecode.lib.vcs.backends.base import BaseChangeset
45 from rhodecode.lib.vcs.backends.base import BaseChangeset
46 from rhodecode.lib.vcs.utils.lazy import LazyProperty
46 from rhodecode.lib.vcs.utils.lazy import LazyProperty
47 from rhodecode.lib.vcs.utils.helpers import get_scm
47 from rhodecode.lib.vcs.utils.helpers import get_scm
48 from rhodecode.lib.vcs.exceptions import VCSError
48 from rhodecode.lib.vcs.exceptions import VCSError
49
49
50 from rhodecode.lib.caching_query import FromCache
50 from rhodecode.lib.caching_query import FromCache
51
51
52 from rhodecode.model import meta
52 from rhodecode.model import meta
53 from rhodecode.model.db import Repository, User, RhodeCodeUi, \
53 from rhodecode.model.db import Repository, User, RhodeCodeUi, \
54 UserLog, RepoGroup, RhodeCodeSetting, CacheInvalidation
54 UserLog, RepoGroup, RhodeCodeSetting, CacheInvalidation
55 from rhodecode.model.meta import Session
55 from rhodecode.model.meta import Session
56 from rhodecode.model.repos_group import ReposGroupModel
56 from rhodecode.model.repos_group import ReposGroupModel
57 from rhodecode.lib.utils2 import safe_str, safe_unicode
57 from rhodecode.lib.utils2 import safe_str, safe_unicode
58 from rhodecode.lib.vcs.utils.fakemod import create_module
58 from rhodecode.lib.vcs.utils.fakemod import create_module
59
59
60 log = logging.getLogger(__name__)
60 log = logging.getLogger(__name__)
61
61
62 REMOVED_REPO_PAT = re.compile(r'rm__\d{8}_\d{6}_\d{6}__.*')
62 REMOVED_REPO_PAT = re.compile(r'rm__\d{8}_\d{6}_\d{6}__.*')
63
63
64
64
65 def recursive_replace(str_, replace=' '):
65 def recursive_replace(str_, replace=' '):
66 """
66 """
67 Recursive replace of given sign to just one instance
67 Recursive replace of given sign to just one instance
68
68
69 :param str_: given string
69 :param str_: given string
70 :param replace: char to find and replace multiple instances
70 :param replace: char to find and replace multiple instances
71
71
72 Examples::
72 Examples::
73 >>> recursive_replace("Mighty---Mighty-Bo--sstones",'-')
73 >>> recursive_replace("Mighty---Mighty-Bo--sstones",'-')
74 'Mighty-Mighty-Bo-sstones'
74 'Mighty-Mighty-Bo-sstones'
75 """
75 """
76
76
77 if str_.find(replace * 2) == -1:
77 if str_.find(replace * 2) == -1:
78 return str_
78 return str_
79 else:
79 else:
80 str_ = str_.replace(replace * 2, replace)
80 str_ = str_.replace(replace * 2, replace)
81 return recursive_replace(str_, replace)
81 return recursive_replace(str_, replace)
82
82
83
83
84 def repo_name_slug(value):
84 def repo_name_slug(value):
85 """
85 """
86 Return slug of name of repository
86 Return slug of name of repository
87 This function is called on each creation/modification
87 This function is called on each creation/modification
88 of repository to prevent bad names in repo
88 of repository to prevent bad names in repo
89 """
89 """
90
90
91 slug = remove_formatting(value)
91 slug = remove_formatting(value)
92 slug = strip_tags(slug)
92 slug = strip_tags(slug)
93
93
94 for c in """=[]\;'"<>,/~!@#$%^&*()+{}|: """:
94 for c in """=[]\;'"<>,/~!@#$%^&*()+{}|: """:
95 slug = slug.replace(c, '-')
95 slug = slug.replace(c, '-')
96 slug = recursive_replace(slug, '-')
96 slug = recursive_replace(slug, '-')
97 slug = collapse(slug, '-')
97 slug = collapse(slug, '-')
98 return slug
98 return slug
99
99
100
100
101 def get_repo_slug(request):
101 def get_repo_slug(request):
102 _repo = request.environ['pylons.routes_dict'].get('repo_name')
102 _repo = request.environ['pylons.routes_dict'].get('repo_name')
103 if _repo:
103 if _repo:
104 _repo = _repo.rstrip('/')
104 _repo = _repo.rstrip('/')
105 return _repo
105 return _repo
106
106
107
107
108 def get_repos_group_slug(request):
108 def get_repos_group_slug(request):
109 _group = request.environ['pylons.routes_dict'].get('group_name')
109 _group = request.environ['pylons.routes_dict'].get('group_name')
110 if _group:
110 if _group:
111 _group = _group.rstrip('/')
111 _group = _group.rstrip('/')
112 return _group
112 return _group
113
113
114
114
115 def action_logger(user, action, repo, ipaddr='', sa=None, commit=False):
115 def action_logger(user, action, repo, ipaddr='', sa=None, commit=False):
116 """
116 """
117 Action logger for various actions made by users
117 Action logger for various actions made by users
118
118
119 :param user: user that made this action, can be a unique username string or
119 :param user: user that made this action, can be a unique username string or
120 object containing user_id attribute
120 object containing user_id attribute
121 :param action: action to log, should be on of predefined unique actions for
121 :param action: action to log, should be on of predefined unique actions for
122 easy translations
122 easy translations
123 :param repo: string name of repository or object containing repo_id,
123 :param repo: string name of repository or object containing repo_id,
124 that action was made on
124 that action was made on
125 :param ipaddr: optional ip address from what the action was made
125 :param ipaddr: optional ip address from what the action was made
126 :param sa: optional sqlalchemy session
126 :param sa: optional sqlalchemy session
127
127
128 """
128 """
129
129
130 if not sa:
130 if not sa:
131 sa = meta.Session()
131 sa = meta.Session()
132
132
133 try:
133 try:
134 if hasattr(user, 'user_id'):
134 if hasattr(user, 'user_id'):
135 user_obj = user
135 user_obj = user
136 elif isinstance(user, basestring):
136 elif isinstance(user, basestring):
137 user_obj = User.get_by_username(user)
137 user_obj = User.get_by_username(user)
138 else:
138 else:
139 raise Exception('You have to provide user object or username')
139 raise Exception('You have to provide user object or username')
140
140
141 if hasattr(repo, 'repo_id'):
141 if hasattr(repo, 'repo_id'):
142 repo_obj = Repository.get(repo.repo_id)
142 repo_obj = Repository.get(repo.repo_id)
143 repo_name = repo_obj.repo_name
143 repo_name = repo_obj.repo_name
144 elif isinstance(repo, basestring):
144 elif isinstance(repo, basestring):
145 repo_name = repo.lstrip('/')
145 repo_name = repo.lstrip('/')
146 repo_obj = Repository.get_by_repo_name(repo_name)
146 repo_obj = Repository.get_by_repo_name(repo_name)
147 else:
147 else:
148 repo_obj = None
148 repo_obj = None
149 repo_name = ''
149 repo_name = ''
150
150
151 user_log = UserLog()
151 user_log = UserLog()
152 user_log.user_id = user_obj.user_id
152 user_log.user_id = user_obj.user_id
153 user_log.action = safe_unicode(action)
153 user_log.action = safe_unicode(action)
154
154
155 user_log.repository = repo_obj
155 user_log.repository = repo_obj
156 user_log.repository_name = repo_name
156 user_log.repository_name = repo_name
157
157
158 user_log.action_date = datetime.datetime.now()
158 user_log.action_date = datetime.datetime.now()
159 user_log.user_ip = ipaddr
159 user_log.user_ip = ipaddr
160 sa.add(user_log)
160 sa.add(user_log)
161
161
162 log.info(
162 log.info(
163 'Adding user %s, action %s on %s' % (user_obj, action,
163 'Adding user %s, action %s on %s' % (user_obj, action,
164 safe_unicode(repo))
164 safe_unicode(repo))
165 )
165 )
166 if commit:
166 if commit:
167 sa.commit()
167 sa.commit()
168 except:
168 except:
169 log.error(traceback.format_exc())
169 log.error(traceback.format_exc())
170 raise
170 raise
171
171
172
172
173 def get_repos(path, recursive=False):
173 def get_repos(path, recursive=False):
174 """
174 """
175 Scans given path for repos and return (name,(type,path)) tuple
175 Scans given path for repos and return (name,(type,path)) tuple
176
176
177 :param path: path to scan for repositories
177 :param path: path to scan for repositories
178 :param recursive: recursive search and return names with subdirs in front
178 :param recursive: recursive search and return names with subdirs in front
179 """
179 """
180
180
181 # remove ending slash for better results
181 # remove ending slash for better results
182 path = path.rstrip(os.sep)
182 path = path.rstrip(os.sep)
183
183
184 def _get_repos(p):
184 def _get_repos(p):
185 if not os.access(p, os.W_OK):
185 if not os.access(p, os.W_OK):
186 return
186 return
187 for dirpath in os.listdir(p):
187 for dirpath in os.listdir(p):
188 if os.path.isfile(os.path.join(p, dirpath)):
188 if os.path.isfile(os.path.join(p, dirpath)):
189 continue
189 continue
190 cur_path = os.path.join(p, dirpath)
190 cur_path = os.path.join(p, dirpath)
191 try:
191 try:
192 scm_info = get_scm(cur_path)
192 scm_info = get_scm(cur_path)
193 yield scm_info[1].split(path, 1)[-1].lstrip(os.sep), scm_info
193 yield scm_info[1].split(path, 1)[-1].lstrip(os.sep), scm_info
194 except VCSError:
194 except VCSError:
195 if not recursive:
195 if not recursive:
196 continue
196 continue
197 #check if this dir containts other repos for recursive scan
197 #check if this dir containts other repos for recursive scan
198 rec_path = os.path.join(p, dirpath)
198 rec_path = os.path.join(p, dirpath)
199 if os.path.isdir(rec_path):
199 if os.path.isdir(rec_path):
200 for inner_scm in _get_repos(rec_path):
200 for inner_scm in _get_repos(rec_path):
201 yield inner_scm
201 yield inner_scm
202
202
203 return _get_repos(path)
203 return _get_repos(path)
204
204
205
205
206 def is_valid_repo(repo_name, base_path, scm=None):
206 def is_valid_repo(repo_name, base_path, scm=None):
207 """
207 """
208 Returns True if given path is a valid repository False otherwise.
208 Returns True if given path is a valid repository False otherwise.
209 If scm param is given also compare if given scm is the same as expected
209 If scm param is given also compare if given scm is the same as expected
210 from scm parameter
210 from scm parameter
211
211
212 :param repo_name:
212 :param repo_name:
213 :param base_path:
213 :param base_path:
214 :param scm:
214 :param scm:
215
215
216 :return True: if given path is a valid repository
216 :return True: if given path is a valid repository
217 """
217 """
218 full_path = os.path.join(safe_str(base_path), safe_str(repo_name))
218 full_path = os.path.join(safe_str(base_path), safe_str(repo_name))
219
219
220 try:
220 try:
221 scm_ = get_scm(full_path)
221 scm_ = get_scm(full_path)
222 if scm:
222 if scm:
223 return scm_[0] == scm
223 return scm_[0] == scm
224 return True
224 return True
225 except VCSError:
225 except VCSError:
226 return False
226 return False
227
227
228
228
229 def is_valid_repos_group(repos_group_name, base_path):
229 def is_valid_repos_group(repos_group_name, base_path):
230 """
230 """
231 Returns True if given path is a repos group False otherwise
231 Returns True if given path is a repos group False otherwise
232
232
233 :param repo_name:
233 :param repo_name:
234 :param base_path:
234 :param base_path:
235 """
235 """
236 full_path = os.path.join(safe_str(base_path), safe_str(repos_group_name))
236 full_path = os.path.join(safe_str(base_path), safe_str(repos_group_name))
237
237
238 # check if it's not a repo
238 # check if it's not a repo
239 if is_valid_repo(repos_group_name, base_path):
239 if is_valid_repo(repos_group_name, base_path):
240 return False
240 return False
241
241
242 try:
242 try:
243 # we need to check bare git repos at higher level
243 # we need to check bare git repos at higher level
244 # since we might match branches/hooks/info/objects or possible
244 # since we might match branches/hooks/info/objects or possible
245 # other things inside bare git repo
245 # other things inside bare git repo
246 get_scm(os.path.dirname(full_path))
246 get_scm(os.path.dirname(full_path))
247 return False
247 return False
248 except VCSError:
248 except VCSError:
249 pass
249 pass
250
250
251 # check if it's a valid path
251 # check if it's a valid path
252 if os.path.isdir(full_path):
252 if os.path.isdir(full_path):
253 return True
253 return True
254
254
255 return False
255 return False
256
256
257
257
258 def ask_ok(prompt, retries=4, complaint='Yes or no, please!'):
258 def ask_ok(prompt, retries=4, complaint='Yes or no, please!'):
259 while True:
259 while True:
260 ok = raw_input(prompt)
260 ok = raw_input(prompt)
261 if ok in ('y', 'ye', 'yes'):
261 if ok in ('y', 'ye', 'yes'):
262 return True
262 return True
263 if ok in ('n', 'no', 'nop', 'nope'):
263 if ok in ('n', 'no', 'nop', 'nope'):
264 return False
264 return False
265 retries = retries - 1
265 retries = retries - 1
266 if retries < 0:
266 if retries < 0:
267 raise IOError
267 raise IOError
268 print complaint
268 print complaint
269
269
270 #propagated from mercurial documentation
270 #propagated from mercurial documentation
271 ui_sections = ['alias', 'auth',
271 ui_sections = ['alias', 'auth',
272 'decode/encode', 'defaults',
272 'decode/encode', 'defaults',
273 'diff', 'email',
273 'diff', 'email',
274 'extensions', 'format',
274 'extensions', 'format',
275 'merge-patterns', 'merge-tools',
275 'merge-patterns', 'merge-tools',
276 'hooks', 'http_proxy',
276 'hooks', 'http_proxy',
277 'smtp', 'patch',
277 'smtp', 'patch',
278 'paths', 'profiling',
278 'paths', 'profiling',
279 'server', 'trusted',
279 'server', 'trusted',
280 'ui', 'web', ]
280 'ui', 'web', ]
281
281
282
282
283 def make_ui(read_from='file', path=None, checkpaths=True):
283 def make_ui(read_from='file', path=None, checkpaths=True, clear_session=True):
284 """
284 """
285 A function that will read python rc files or database
285 A function that will read python rc files or database
286 and make an mercurial ui object from read options
286 and make an mercurial ui object from read options
287
287
288 :param path: path to mercurial config file
288 :param path: path to mercurial config file
289 :param checkpaths: check the path
289 :param checkpaths: check the path
290 :param read_from: read from 'file' or 'db'
290 :param read_from: read from 'file' or 'db'
291 """
291 """
292
292
293 baseui = ui.ui()
293 baseui = ui.ui()
294
294
295 # clean the baseui object
295 # clean the baseui object
296 baseui._ocfg = config.config()
296 baseui._ocfg = config.config()
297 baseui._ucfg = config.config()
297 baseui._ucfg = config.config()
298 baseui._tcfg = config.config()
298 baseui._tcfg = config.config()
299
299
300 if read_from == 'file':
300 if read_from == 'file':
301 if not os.path.isfile(path):
301 if not os.path.isfile(path):
302 log.debug('hgrc file is not present at %s skipping...' % path)
302 log.debug('hgrc file is not present at %s skipping...' % path)
303 return False
303 return False
304 log.debug('reading hgrc from %s' % path)
304 log.debug('reading hgrc from %s' % path)
305 cfg = config.config()
305 cfg = config.config()
306 cfg.read(path)
306 cfg.read(path)
307 for section in ui_sections:
307 for section in ui_sections:
308 for k, v in cfg.items(section):
308 for k, v in cfg.items(section):
309 log.debug('settings ui from file[%s]%s:%s' % (section, k, v))
309 log.debug('settings ui from file[%s]%s:%s' % (section, k, v))
310 baseui.setconfig(section, k, v)
310 baseui.setconfig(section, k, v)
311
311
312 elif read_from == 'db':
312 elif read_from == 'db':
313 sa = meta.Session()
313 sa = meta.Session()
314 ret = sa.query(RhodeCodeUi)\
314 ret = sa.query(RhodeCodeUi)\
315 .options(FromCache("sql_cache_short", "get_hg_ui_settings"))\
315 .options(FromCache("sql_cache_short", "get_hg_ui_settings"))\
316 .all()
316 .all()
317
317
318 hg_ui = ret
318 hg_ui = ret
319 for ui_ in hg_ui:
319 for ui_ in hg_ui:
320 if ui_.ui_active:
320 if ui_.ui_active:
321 log.debug('settings ui from db[%s]%s:%s', ui_.ui_section,
321 log.debug('settings ui from db[%s]%s:%s', ui_.ui_section,
322 ui_.ui_key, ui_.ui_value)
322 ui_.ui_key, ui_.ui_value)
323 baseui.setconfig(ui_.ui_section, ui_.ui_key, ui_.ui_value)
323 baseui.setconfig(ui_.ui_section, ui_.ui_key, ui_.ui_value)
324 if ui_.ui_key == 'push_ssl':
324 if ui_.ui_key == 'push_ssl':
325 # force set push_ssl requirement to False, rhodecode
325 # force set push_ssl requirement to False, rhodecode
326 # handles that
326 # handles that
327 baseui.setconfig(ui_.ui_section, ui_.ui_key, False)
327 baseui.setconfig(ui_.ui_section, ui_.ui_key, False)
328
328 if clear_session:
329 meta.Session.remove()
329 meta.Session.remove()
330 return baseui
330 return baseui
331
331
332
332
333 def set_rhodecode_config(config):
333 def set_rhodecode_config(config):
334 """
334 """
335 Updates pylons config with new settings from database
335 Updates pylons config with new settings from database
336
336
337 :param config:
337 :param config:
338 """
338 """
339 hgsettings = RhodeCodeSetting.get_app_settings()
339 hgsettings = RhodeCodeSetting.get_app_settings()
340
340
341 for k, v in hgsettings.items():
341 for k, v in hgsettings.items():
342 config[k] = v
342 config[k] = v
343
343
344
344
345 def invalidate_cache(cache_key, *args):
345 def invalidate_cache(cache_key, *args):
346 """
346 """
347 Puts cache invalidation task into db for
347 Puts cache invalidation task into db for
348 further global cache invalidation
348 further global cache invalidation
349 """
349 """
350
350
351 from rhodecode.model.scm import ScmModel
351 from rhodecode.model.scm import ScmModel
352
352
353 if cache_key.startswith('get_repo_cached_'):
353 if cache_key.startswith('get_repo_cached_'):
354 name = cache_key.split('get_repo_cached_')[-1]
354 name = cache_key.split('get_repo_cached_')[-1]
355 ScmModel().mark_for_invalidation(name)
355 ScmModel().mark_for_invalidation(name)
356
356
357
357
358 def map_groups(path):
358 def map_groups(path):
359 """
359 """
360 Given a full path to a repository, create all nested groups that this
360 Given a full path to a repository, create all nested groups that this
361 repo is inside. This function creates parent-child relationships between
361 repo is inside. This function creates parent-child relationships between
362 groups and creates default perms for all new groups.
362 groups and creates default perms for all new groups.
363
363
364 :param paths: full path to repository
364 :param paths: full path to repository
365 """
365 """
366 sa = meta.Session()
366 sa = meta.Session()
367 groups = path.split(Repository.url_sep())
367 groups = path.split(Repository.url_sep())
368 parent = None
368 parent = None
369 group = None
369 group = None
370
370
371 # last element is repo in nested groups structure
371 # last element is repo in nested groups structure
372 groups = groups[:-1]
372 groups = groups[:-1]
373 rgm = ReposGroupModel(sa)
373 rgm = ReposGroupModel(sa)
374 for lvl, group_name in enumerate(groups):
374 for lvl, group_name in enumerate(groups):
375 group_name = '/'.join(groups[:lvl] + [group_name])
375 group_name = '/'.join(groups[:lvl] + [group_name])
376 group = RepoGroup.get_by_group_name(group_name)
376 group = RepoGroup.get_by_group_name(group_name)
377 desc = '%s group' % group_name
377 desc = '%s group' % group_name
378
378
379 # skip folders that are now removed repos
379 # skip folders that are now removed repos
380 if REMOVED_REPO_PAT.match(group_name):
380 if REMOVED_REPO_PAT.match(group_name):
381 break
381 break
382
382
383 if group is None:
383 if group is None:
384 log.debug('creating group level: %s group_name: %s' % (lvl,
384 log.debug('creating group level: %s group_name: %s' % (lvl,
385 group_name))
385 group_name))
386 group = RepoGroup(group_name, parent)
386 group = RepoGroup(group_name, parent)
387 group.group_description = desc
387 group.group_description = desc
388 sa.add(group)
388 sa.add(group)
389 rgm._create_default_perms(group)
389 rgm._create_default_perms(group)
390 sa.flush()
390 sa.flush()
391 parent = group
391 parent = group
392 return group
392 return group
393
393
394
394
395 def repo2db_mapper(initial_repo_list, remove_obsolete=False,
395 def repo2db_mapper(initial_repo_list, remove_obsolete=False,
396 install_git_hook=False):
396 install_git_hook=False):
397 """
397 """
398 maps all repos given in initial_repo_list, non existing repositories
398 maps all repos given in initial_repo_list, non existing repositories
399 are created, if remove_obsolete is True it also check for db entries
399 are created, if remove_obsolete is True it also check for db entries
400 that are not in initial_repo_list and removes them.
400 that are not in initial_repo_list and removes them.
401
401
402 :param initial_repo_list: list of repositories found by scanning methods
402 :param initial_repo_list: list of repositories found by scanning methods
403 :param remove_obsolete: check for obsolete entries in database
403 :param remove_obsolete: check for obsolete entries in database
404 :param install_git_hook: if this is True, also check and install githook
404 :param install_git_hook: if this is True, also check and install githook
405 for a repo if missing
405 for a repo if missing
406 """
406 """
407 from rhodecode.model.repo import RepoModel
407 from rhodecode.model.repo import RepoModel
408 from rhodecode.model.scm import ScmModel
408 from rhodecode.model.scm import ScmModel
409 sa = meta.Session()
409 sa = meta.Session()
410 rm = RepoModel()
410 rm = RepoModel()
411 user = sa.query(User).filter(User.admin == True).first()
411 user = sa.query(User).filter(User.admin == True).first()
412 if user is None:
412 if user is None:
413 raise Exception('Missing administrative account !')
413 raise Exception('Missing administrative account !')
414 added = []
414 added = []
415
415
416 for name, repo in initial_repo_list.items():
416 for name, repo in initial_repo_list.items():
417 group = map_groups(name)
417 group = map_groups(name)
418 db_repo = rm.get_by_repo_name(name)
418 db_repo = rm.get_by_repo_name(name)
419 # found repo that is on filesystem not in RhodeCode database
419 # found repo that is on filesystem not in RhodeCode database
420 if not db_repo:
420 if not db_repo:
421 log.info('repository %s not found creating now' % name)
421 log.info('repository %s not found creating now' % name)
422 added.append(name)
422 added.append(name)
423 desc = (repo.description
423 desc = (repo.description
424 if repo.description != 'unknown'
424 if repo.description != 'unknown'
425 else '%s repository' % name)
425 else '%s repository' % name)
426 new_repo = rm.create_repo(
426 new_repo = rm.create_repo(
427 repo_name=name,
427 repo_name=name,
428 repo_type=repo.alias,
428 repo_type=repo.alias,
429 description=desc,
429 description=desc,
430 repos_group=getattr(group, 'group_id', None),
430 repos_group=getattr(group, 'group_id', None),
431 owner=user,
431 owner=user,
432 just_db=True
432 just_db=True
433 )
433 )
434 # we added that repo just now, and make sure it has githook
434 # we added that repo just now, and make sure it has githook
435 # installed
435 # installed
436 if new_repo.repo_type == 'git':
436 if new_repo.repo_type == 'git':
437 ScmModel().install_git_hook(new_repo.scm_instance)
437 ScmModel().install_git_hook(new_repo.scm_instance)
438 elif install_git_hook:
438 elif install_git_hook:
439 if db_repo.repo_type == 'git':
439 if db_repo.repo_type == 'git':
440 ScmModel().install_git_hook(db_repo.scm_instance)
440 ScmModel().install_git_hook(db_repo.scm_instance)
441 sa.commit()
441 sa.commit()
442 removed = []
442 removed = []
443 if remove_obsolete:
443 if remove_obsolete:
444 # remove from database those repositories that are not in the filesystem
444 # remove from database those repositories that are not in the filesystem
445 for repo in sa.query(Repository).all():
445 for repo in sa.query(Repository).all():
446 if repo.repo_name not in initial_repo_list.keys():
446 if repo.repo_name not in initial_repo_list.keys():
447 log.debug("Removing non existing repository found in db `%s`" %
447 log.debug("Removing non existing repository found in db `%s`" %
448 repo.repo_name)
448 repo.repo_name)
449 try:
449 try:
450 sa.delete(repo)
450 sa.delete(repo)
451 sa.commit()
451 sa.commit()
452 removed.append(repo.repo_name)
452 removed.append(repo.repo_name)
453 except:
453 except:
454 #don't hold further removals on error
454 #don't hold further removals on error
455 log.error(traceback.format_exc())
455 log.error(traceback.format_exc())
456 sa.rollback()
456 sa.rollback()
457
457
458 # clear cache keys
458 # clear cache keys
459 log.debug("Clearing cache keys now...")
459 log.debug("Clearing cache keys now...")
460 CacheInvalidation.clear_cache()
460 CacheInvalidation.clear_cache()
461 sa.commit()
461 sa.commit()
462 return added, removed
462 return added, removed
463
463
464
464
465 # set cache regions for beaker so celery can utilise it
465 # set cache regions for beaker so celery can utilise it
466 def add_cache(settings):
466 def add_cache(settings):
467 cache_settings = {'regions': None}
467 cache_settings = {'regions': None}
468 for key in settings.keys():
468 for key in settings.keys():
469 for prefix in ['beaker.cache.', 'cache.']:
469 for prefix in ['beaker.cache.', 'cache.']:
470 if key.startswith(prefix):
470 if key.startswith(prefix):
471 name = key.split(prefix)[1].strip()
471 name = key.split(prefix)[1].strip()
472 cache_settings[name] = settings[key].strip()
472 cache_settings[name] = settings[key].strip()
473 if cache_settings['regions']:
473 if cache_settings['regions']:
474 for region in cache_settings['regions'].split(','):
474 for region in cache_settings['regions'].split(','):
475 region = region.strip()
475 region = region.strip()
476 region_settings = {}
476 region_settings = {}
477 for key, value in cache_settings.items():
477 for key, value in cache_settings.items():
478 if key.startswith(region):
478 if key.startswith(region):
479 region_settings[key.split('.')[1]] = value
479 region_settings[key.split('.')[1]] = value
480 region_settings['expire'] = int(region_settings.get('expire',
480 region_settings['expire'] = int(region_settings.get('expire',
481 60))
481 60))
482 region_settings.setdefault('lock_dir',
482 region_settings.setdefault('lock_dir',
483 cache_settings.get('lock_dir'))
483 cache_settings.get('lock_dir'))
484 region_settings.setdefault('data_dir',
484 region_settings.setdefault('data_dir',
485 cache_settings.get('data_dir'))
485 cache_settings.get('data_dir'))
486
486
487 if 'type' not in region_settings:
487 if 'type' not in region_settings:
488 region_settings['type'] = cache_settings.get('type',
488 region_settings['type'] = cache_settings.get('type',
489 'memory')
489 'memory')
490 beaker.cache.cache_regions[region] = region_settings
490 beaker.cache.cache_regions[region] = region_settings
491
491
492
492
493 def load_rcextensions(root_path):
493 def load_rcextensions(root_path):
494 import rhodecode
494 import rhodecode
495 from rhodecode.config import conf
495 from rhodecode.config import conf
496
496
497 path = os.path.join(root_path, 'rcextensions', '__init__.py')
497 path = os.path.join(root_path, 'rcextensions', '__init__.py')
498 if os.path.isfile(path):
498 if os.path.isfile(path):
499 rcext = create_module('rc', path)
499 rcext = create_module('rc', path)
500 EXT = rhodecode.EXTENSIONS = rcext
500 EXT = rhodecode.EXTENSIONS = rcext
501 log.debug('Found rcextensions now loading %s...' % rcext)
501 log.debug('Found rcextensions now loading %s...' % rcext)
502
502
503 # Additional mappings that are not present in the pygments lexers
503 # Additional mappings that are not present in the pygments lexers
504 conf.LANGUAGES_EXTENSIONS_MAP.update(getattr(EXT, 'EXTRA_MAPPINGS', {}))
504 conf.LANGUAGES_EXTENSIONS_MAP.update(getattr(EXT, 'EXTRA_MAPPINGS', {}))
505
505
506 #OVERRIDE OUR EXTENSIONS FROM RC-EXTENSIONS (if present)
506 #OVERRIDE OUR EXTENSIONS FROM RC-EXTENSIONS (if present)
507
507
508 if getattr(EXT, 'INDEX_EXTENSIONS', []) != []:
508 if getattr(EXT, 'INDEX_EXTENSIONS', []) != []:
509 log.debug('settings custom INDEX_EXTENSIONS')
509 log.debug('settings custom INDEX_EXTENSIONS')
510 conf.INDEX_EXTENSIONS = getattr(EXT, 'INDEX_EXTENSIONS', [])
510 conf.INDEX_EXTENSIONS = getattr(EXT, 'INDEX_EXTENSIONS', [])
511
511
512 #ADDITIONAL MAPPINGS
512 #ADDITIONAL MAPPINGS
513 log.debug('adding extra into INDEX_EXTENSIONS')
513 log.debug('adding extra into INDEX_EXTENSIONS')
514 conf.INDEX_EXTENSIONS.extend(getattr(EXT, 'EXTRA_INDEX_EXTENSIONS', []))
514 conf.INDEX_EXTENSIONS.extend(getattr(EXT, 'EXTRA_INDEX_EXTENSIONS', []))
515
515
516
516
517 #==============================================================================
517 #==============================================================================
518 # TEST FUNCTIONS AND CREATORS
518 # TEST FUNCTIONS AND CREATORS
519 #==============================================================================
519 #==============================================================================
520 def create_test_index(repo_location, config, full_index):
520 def create_test_index(repo_location, config, full_index):
521 """
521 """
522 Makes default test index
522 Makes default test index
523
523
524 :param config: test config
524 :param config: test config
525 :param full_index:
525 :param full_index:
526 """
526 """
527
527
528 from rhodecode.lib.indexers.daemon import WhooshIndexingDaemon
528 from rhodecode.lib.indexers.daemon import WhooshIndexingDaemon
529 from rhodecode.lib.pidlock import DaemonLock, LockHeld
529 from rhodecode.lib.pidlock import DaemonLock, LockHeld
530
530
531 repo_location = repo_location
531 repo_location = repo_location
532
532
533 index_location = os.path.join(config['app_conf']['index_dir'])
533 index_location = os.path.join(config['app_conf']['index_dir'])
534 if not os.path.exists(index_location):
534 if not os.path.exists(index_location):
535 os.makedirs(index_location)
535 os.makedirs(index_location)
536
536
537 try:
537 try:
538 l = DaemonLock(file_=jn(dn(index_location), 'make_index.lock'))
538 l = DaemonLock(file_=jn(dn(index_location), 'make_index.lock'))
539 WhooshIndexingDaemon(index_location=index_location,
539 WhooshIndexingDaemon(index_location=index_location,
540 repo_location=repo_location)\
540 repo_location=repo_location)\
541 .run(full_index=full_index)
541 .run(full_index=full_index)
542 l.release()
542 l.release()
543 except LockHeld:
543 except LockHeld:
544 pass
544 pass
545
545
546
546
547 def create_test_env(repos_test_path, config):
547 def create_test_env(repos_test_path, config):
548 """
548 """
549 Makes a fresh database and
549 Makes a fresh database and
550 install test repository into tmp dir
550 install test repository into tmp dir
551 """
551 """
552 from rhodecode.lib.db_manage import DbManage
552 from rhodecode.lib.db_manage import DbManage
553 from rhodecode.tests import HG_REPO, GIT_REPO, TESTS_TMP_PATH
553 from rhodecode.tests import HG_REPO, GIT_REPO, TESTS_TMP_PATH
554
554
555 # PART ONE create db
555 # PART ONE create db
556 dbconf = config['sqlalchemy.db1.url']
556 dbconf = config['sqlalchemy.db1.url']
557 log.debug('making test db %s' % dbconf)
557 log.debug('making test db %s' % dbconf)
558
558
559 # create test dir if it doesn't exist
559 # create test dir if it doesn't exist
560 if not os.path.isdir(repos_test_path):
560 if not os.path.isdir(repos_test_path):
561 log.debug('Creating testdir %s' % repos_test_path)
561 log.debug('Creating testdir %s' % repos_test_path)
562 os.makedirs(repos_test_path)
562 os.makedirs(repos_test_path)
563
563
564 dbmanage = DbManage(log_sql=True, dbconf=dbconf, root=config['here'],
564 dbmanage = DbManage(log_sql=True, dbconf=dbconf, root=config['here'],
565 tests=True)
565 tests=True)
566 dbmanage.create_tables(override=True)
566 dbmanage.create_tables(override=True)
567 dbmanage.create_settings(dbmanage.config_prompt(repos_test_path))
567 dbmanage.create_settings(dbmanage.config_prompt(repos_test_path))
568 dbmanage.create_default_user()
568 dbmanage.create_default_user()
569 dbmanage.admin_prompt()
569 dbmanage.admin_prompt()
570 dbmanage.create_permissions()
570 dbmanage.create_permissions()
571 dbmanage.populate_default_permissions()
571 dbmanage.populate_default_permissions()
572 Session().commit()
572 Session().commit()
573 # PART TWO make test repo
573 # PART TWO make test repo
574 log.debug('making test vcs repositories')
574 log.debug('making test vcs repositories')
575
575
576 idx_path = config['app_conf']['index_dir']
576 idx_path = config['app_conf']['index_dir']
577 data_path = config['app_conf']['cache_dir']
577 data_path = config['app_conf']['cache_dir']
578
578
579 #clean index and data
579 #clean index and data
580 if idx_path and os.path.exists(idx_path):
580 if idx_path and os.path.exists(idx_path):
581 log.debug('remove %s' % idx_path)
581 log.debug('remove %s' % idx_path)
582 shutil.rmtree(idx_path)
582 shutil.rmtree(idx_path)
583
583
584 if data_path and os.path.exists(data_path):
584 if data_path and os.path.exists(data_path):
585 log.debug('remove %s' % data_path)
585 log.debug('remove %s' % data_path)
586 shutil.rmtree(data_path)
586 shutil.rmtree(data_path)
587
587
588 #CREATE DEFAULT TEST REPOS
588 #CREATE DEFAULT TEST REPOS
589 cur_dir = dn(dn(abspath(__file__)))
589 cur_dir = dn(dn(abspath(__file__)))
590 tar = tarfile.open(jn(cur_dir, 'tests', "vcs_test_hg.tar.gz"))
590 tar = tarfile.open(jn(cur_dir, 'tests', "vcs_test_hg.tar.gz"))
591 tar.extractall(jn(TESTS_TMP_PATH, HG_REPO))
591 tar.extractall(jn(TESTS_TMP_PATH, HG_REPO))
592 tar.close()
592 tar.close()
593
593
594 cur_dir = dn(dn(abspath(__file__)))
594 cur_dir = dn(dn(abspath(__file__)))
595 tar = tarfile.open(jn(cur_dir, 'tests', "vcs_test_git.tar.gz"))
595 tar = tarfile.open(jn(cur_dir, 'tests', "vcs_test_git.tar.gz"))
596 tar.extractall(jn(TESTS_TMP_PATH, GIT_REPO))
596 tar.extractall(jn(TESTS_TMP_PATH, GIT_REPO))
597 tar.close()
597 tar.close()
598
598
599 #LOAD VCS test stuff
599 #LOAD VCS test stuff
600 from rhodecode.tests.vcs import setup_package
600 from rhodecode.tests.vcs import setup_package
601 setup_package()
601 setup_package()
602
602
603
603
604 #==============================================================================
604 #==============================================================================
605 # PASTER COMMANDS
605 # PASTER COMMANDS
606 #==============================================================================
606 #==============================================================================
607 class BasePasterCommand(Command):
607 class BasePasterCommand(Command):
608 """
608 """
609 Abstract Base Class for paster commands.
609 Abstract Base Class for paster commands.
610
610
611 The celery commands are somewhat aggressive about loading
611 The celery commands are somewhat aggressive about loading
612 celery.conf, and since our module sets the `CELERY_LOADER`
612 celery.conf, and since our module sets the `CELERY_LOADER`
613 environment variable to our loader, we have to bootstrap a bit and
613 environment variable to our loader, we have to bootstrap a bit and
614 make sure we've had a chance to load the pylons config off of the
614 make sure we've had a chance to load the pylons config off of the
615 command line, otherwise everything fails.
615 command line, otherwise everything fails.
616 """
616 """
617 min_args = 1
617 min_args = 1
618 min_args_error = "Please provide a paster config file as an argument."
618 min_args_error = "Please provide a paster config file as an argument."
619 takes_config_file = 1
619 takes_config_file = 1
620 requires_config_file = True
620 requires_config_file = True
621
621
622 def notify_msg(self, msg, log=False):
622 def notify_msg(self, msg, log=False):
623 """Make a notification to user, additionally if logger is passed
623 """Make a notification to user, additionally if logger is passed
624 it logs this action using given logger
624 it logs this action using given logger
625
625
626 :param msg: message that will be printed to user
626 :param msg: message that will be printed to user
627 :param log: logging instance, to use to additionally log this message
627 :param log: logging instance, to use to additionally log this message
628
628
629 """
629 """
630 if log and isinstance(log, logging):
630 if log and isinstance(log, logging):
631 log(msg)
631 log(msg)
632
632
633 def run(self, args):
633 def run(self, args):
634 """
634 """
635 Overrides Command.run
635 Overrides Command.run
636
636
637 Checks for a config file argument and loads it.
637 Checks for a config file argument and loads it.
638 """
638 """
639 if len(args) < self.min_args:
639 if len(args) < self.min_args:
640 raise BadCommand(
640 raise BadCommand(
641 self.min_args_error % {'min_args': self.min_args,
641 self.min_args_error % {'min_args': self.min_args,
642 'actual_args': len(args)})
642 'actual_args': len(args)})
643
643
644 # Decrement because we're going to lob off the first argument.
644 # Decrement because we're going to lob off the first argument.
645 # @@ This is hacky
645 # @@ This is hacky
646 self.min_args -= 1
646 self.min_args -= 1
647 self.bootstrap_config(args[0])
647 self.bootstrap_config(args[0])
648 self.update_parser()
648 self.update_parser()
649 return super(BasePasterCommand, self).run(args[1:])
649 return super(BasePasterCommand, self).run(args[1:])
650
650
651 def update_parser(self):
651 def update_parser(self):
652 """
652 """
653 Abstract method. Allows for the class's parser to be updated
653 Abstract method. Allows for the class's parser to be updated
654 before the superclass's `run` method is called. Necessary to
654 before the superclass's `run` method is called. Necessary to
655 allow options/arguments to be passed through to the underlying
655 allow options/arguments to be passed through to the underlying
656 celery command.
656 celery command.
657 """
657 """
658 raise NotImplementedError("Abstract Method.")
658 raise NotImplementedError("Abstract Method.")
659
659
660 def bootstrap_config(self, conf):
660 def bootstrap_config(self, conf):
661 """
661 """
662 Loads the pylons configuration.
662 Loads the pylons configuration.
663 """
663 """
664 from pylons import config as pylonsconfig
664 from pylons import config as pylonsconfig
665
665
666 self.path_to_ini_file = os.path.realpath(conf)
666 self.path_to_ini_file = os.path.realpath(conf)
667 conf = paste.deploy.appconfig('config:' + self.path_to_ini_file)
667 conf = paste.deploy.appconfig('config:' + self.path_to_ini_file)
668 pylonsconfig.init_app(conf.global_conf, conf.local_conf)
668 pylonsconfig.init_app(conf.global_conf, conf.local_conf)
@@ -1,601 +1,601 b''
1 """
1 """
2 Set of generic validators
2 Set of generic validators
3 """
3 """
4 import os
4 import os
5 import re
5 import re
6 import formencode
6 import formencode
7 import logging
7 import logging
8 from pylons.i18n.translation import _
8 from pylons.i18n.translation import _
9 from webhelpers.pylonslib.secure_form import authentication_token
9 from webhelpers.pylonslib.secure_form import authentication_token
10
10
11 from formencode.validators import (
11 from formencode.validators import (
12 UnicodeString, OneOf, Int, Number, Regex, Email, Bool, StringBoolean, Set,
12 UnicodeString, OneOf, Int, Number, Regex, Email, Bool, StringBoolean, Set,
13 )
13 )
14 from rhodecode.lib.utils import repo_name_slug
14 from rhodecode.lib.utils import repo_name_slug
15 from rhodecode.model.db import RepoGroup, Repository, UsersGroup, User
15 from rhodecode.model.db import RepoGroup, Repository, UsersGroup, User
16 from rhodecode.lib.exceptions import LdapImportError
16 from rhodecode.lib.exceptions import LdapImportError
17 from rhodecode.config.routing import ADMIN_PREFIX
17 from rhodecode.config.routing import ADMIN_PREFIX
18 # silence warnings and pylint
18 # silence warnings and pylint
19 UnicodeString, OneOf, Int, Number, Regex, Email, Bool, StringBoolean, Set
19 UnicodeString, OneOf, Int, Number, Regex, Email, Bool, StringBoolean, Set
20
20
21 log = logging.getLogger(__name__)
21 log = logging.getLogger(__name__)
22
22
23
23
24 class StateObj(object):
24 class StateObj(object):
25 """
25 """
26 this is needed to translate the messages using _() in validators
26 this is needed to translate the messages using _() in validators
27 """
27 """
28 _ = staticmethod(_)
28 _ = staticmethod(_)
29
29
30
30
31 def M(self, key, state=None, **kwargs):
31 def M(self, key, state=None, **kwargs):
32 """
32 """
33 returns string from self.message based on given key,
33 returns string from self.message based on given key,
34 passed kw params are used to substitute %(named)s params inside
34 passed kw params are used to substitute %(named)s params inside
35 translated strings
35 translated strings
36
36
37 :param msg:
37 :param msg:
38 :param state:
38 :param state:
39 """
39 """
40 if state is None:
40 if state is None:
41 state = StateObj()
41 state = StateObj()
42 else:
42 else:
43 state._ = staticmethod(_)
43 state._ = staticmethod(_)
44 #inject validator into state object
44 #inject validator into state object
45 return self.message(key, state, **kwargs)
45 return self.message(key, state, **kwargs)
46
46
47
47
48 def ValidUsername(edit=False, old_data={}):
48 def ValidUsername(edit=False, old_data={}):
49 class _validator(formencode.validators.FancyValidator):
49 class _validator(formencode.validators.FancyValidator):
50 messages = {
50 messages = {
51 'username_exists': _(u'Username "%(username)s" already exists'),
51 'username_exists': _(u'Username "%(username)s" already exists'),
52 'system_invalid_username':
52 'system_invalid_username':
53 _(u'Username "%(username)s" is forbidden'),
53 _(u'Username "%(username)s" is forbidden'),
54 'invalid_username':
54 'invalid_username':
55 _(u'Username may only contain alphanumeric characters '
55 _(u'Username may only contain alphanumeric characters '
56 'underscores, periods or dashes and must begin with '
56 'underscores, periods or dashes and must begin with '
57 'alphanumeric character')
57 'alphanumeric character')
58 }
58 }
59
59
60 def validate_python(self, value, state):
60 def validate_python(self, value, state):
61 if value in ['default', 'new_user']:
61 if value in ['default', 'new_user']:
62 msg = M(self, 'system_invalid_username', state, username=value)
62 msg = M(self, 'system_invalid_username', state, username=value)
63 raise formencode.Invalid(msg, value, state)
63 raise formencode.Invalid(msg, value, state)
64 #check if user is unique
64 #check if user is unique
65 old_un = None
65 old_un = None
66 if edit:
66 if edit:
67 old_un = User.get(old_data.get('user_id')).username
67 old_un = User.get(old_data.get('user_id')).username
68
68
69 if old_un != value or not edit:
69 if old_un != value or not edit:
70 if User.get_by_username(value, case_insensitive=True):
70 if User.get_by_username(value, case_insensitive=True):
71 msg = M(self, 'username_exists', state, username=value)
71 msg = M(self, 'username_exists', state, username=value)
72 raise formencode.Invalid(msg, value, state)
72 raise formencode.Invalid(msg, value, state)
73
73
74 if re.match(r'^[a-zA-Z0-9]{1}[a-zA-Z0-9\-\_\.]+$', value) is None:
74 if re.match(r'^[a-zA-Z0-9]{1}[a-zA-Z0-9\-\_\.]+$', value) is None:
75 msg = M(self, 'invalid_username', state)
75 msg = M(self, 'invalid_username', state)
76 raise formencode.Invalid(msg, value, state)
76 raise formencode.Invalid(msg, value, state)
77 return _validator
77 return _validator
78
78
79
79
80 def ValidRepoUser():
80 def ValidRepoUser():
81 class _validator(formencode.validators.FancyValidator):
81 class _validator(formencode.validators.FancyValidator):
82 messages = {
82 messages = {
83 'invalid_username': _(u'Username %(username)s is not valid')
83 'invalid_username': _(u'Username %(username)s is not valid')
84 }
84 }
85
85
86 def validate_python(self, value, state):
86 def validate_python(self, value, state):
87 try:
87 try:
88 User.query().filter(User.active == True)\
88 User.query().filter(User.active == True)\
89 .filter(User.username == value).one()
89 .filter(User.username == value).one()
90 except Exception:
90 except Exception:
91 msg = M(self, 'invalid_username', state, username=value)
91 msg = M(self, 'invalid_username', state, username=value)
92 raise formencode.Invalid(msg, value, state,
92 raise formencode.Invalid(msg, value, state,
93 error_dict=dict(username=msg)
93 error_dict=dict(username=msg)
94 )
94 )
95
95
96 return _validator
96 return _validator
97
97
98
98
99 def ValidUsersGroup(edit=False, old_data={}):
99 def ValidUsersGroup(edit=False, old_data={}):
100 class _validator(formencode.validators.FancyValidator):
100 class _validator(formencode.validators.FancyValidator):
101 messages = {
101 messages = {
102 'invalid_group': _(u'Invalid users group name'),
102 'invalid_group': _(u'Invalid users group name'),
103 'group_exist': _(u'Users group "%(usersgroup)s" already exists'),
103 'group_exist': _(u'Users group "%(usersgroup)s" already exists'),
104 'invalid_usersgroup_name':
104 'invalid_usersgroup_name':
105 _(u'users group name may only contain alphanumeric '
105 _(u'users group name may only contain alphanumeric '
106 'characters underscores, periods or dashes and must begin '
106 'characters underscores, periods or dashes and must begin '
107 'with alphanumeric character')
107 'with alphanumeric character')
108 }
108 }
109
109
110 def validate_python(self, value, state):
110 def validate_python(self, value, state):
111 if value in ['default']:
111 if value in ['default']:
112 msg = M(self, 'invalid_group', state)
112 msg = M(self, 'invalid_group', state)
113 raise formencode.Invalid(msg, value, state,
113 raise formencode.Invalid(msg, value, state,
114 error_dict=dict(users_group_name=msg)
114 error_dict=dict(users_group_name=msg)
115 )
115 )
116 #check if group is unique
116 #check if group is unique
117 old_ugname = None
117 old_ugname = None
118 if edit:
118 if edit:
119 old_id = old_data.get('users_group_id')
119 old_id = old_data.get('users_group_id')
120 old_ugname = UsersGroup.get(old_id).users_group_name
120 old_ugname = UsersGroup.get(old_id).users_group_name
121
121
122 if old_ugname != value or not edit:
122 if old_ugname != value or not edit:
123 is_existing_group = UsersGroup.get_by_group_name(value,
123 is_existing_group = UsersGroup.get_by_group_name(value,
124 case_insensitive=True)
124 case_insensitive=True)
125 if is_existing_group:
125 if is_existing_group:
126 msg = M(self, 'group_exist', state, usersgroup=value)
126 msg = M(self, 'group_exist', state, usersgroup=value)
127 raise formencode.Invalid(msg, value, state,
127 raise formencode.Invalid(msg, value, state,
128 error_dict=dict(users_group_name=msg)
128 error_dict=dict(users_group_name=msg)
129 )
129 )
130
130
131 if re.match(r'^[a-zA-Z0-9]{1}[a-zA-Z0-9\-\_\.]+$', value) is None:
131 if re.match(r'^[a-zA-Z0-9]{1}[a-zA-Z0-9\-\_\.]+$', value) is None:
132 msg = M(self, 'invalid_usersgroup_name', state)
132 msg = M(self, 'invalid_usersgroup_name', state)
133 raise formencode.Invalid(msg, value, state,
133 raise formencode.Invalid(msg, value, state,
134 error_dict=dict(users_group_name=msg)
134 error_dict=dict(users_group_name=msg)
135 )
135 )
136
136
137 return _validator
137 return _validator
138
138
139
139
140 def ValidReposGroup(edit=False, old_data={}):
140 def ValidReposGroup(edit=False, old_data={}):
141 class _validator(formencode.validators.FancyValidator):
141 class _validator(formencode.validators.FancyValidator):
142 messages = {
142 messages = {
143 'group_parent_id': _(u'Cannot assign this group as parent'),
143 'group_parent_id': _(u'Cannot assign this group as parent'),
144 'group_exists': _(u'Group "%(group_name)s" already exists'),
144 'group_exists': _(u'Group "%(group_name)s" already exists'),
145 'repo_exists':
145 'repo_exists':
146 _(u'Repository with name "%(group_name)s" already exists')
146 _(u'Repository with name "%(group_name)s" already exists')
147 }
147 }
148
148
149 def validate_python(self, value, state):
149 def validate_python(self, value, state):
150 # TODO WRITE VALIDATIONS
150 # TODO WRITE VALIDATIONS
151 group_name = value.get('group_name')
151 group_name = value.get('group_name')
152 group_parent_id = value.get('group_parent_id')
152 group_parent_id = value.get('group_parent_id')
153
153
154 # slugify repo group just in case :)
154 # slugify repo group just in case :)
155 slug = repo_name_slug(group_name)
155 slug = repo_name_slug(group_name)
156
156
157 # check for parent of self
157 # check for parent of self
158 parent_of_self = lambda: (
158 parent_of_self = lambda: (
159 old_data['group_id'] == int(group_parent_id)
159 old_data['group_id'] == int(group_parent_id)
160 if group_parent_id else False
160 if group_parent_id else False
161 )
161 )
162 if edit and parent_of_self():
162 if edit and parent_of_self():
163 msg = M(self, 'group_parent_id', state)
163 msg = M(self, 'group_parent_id', state)
164 raise formencode.Invalid(msg, value, state,
164 raise formencode.Invalid(msg, value, state,
165 error_dict=dict(group_parent_id=msg)
165 error_dict=dict(group_parent_id=msg)
166 )
166 )
167
167
168 old_gname = None
168 old_gname = None
169 if edit:
169 if edit:
170 old_gname = RepoGroup.get(old_data.get('group_id')).group_name
170 old_gname = RepoGroup.get(old_data.get('group_id')).group_name
171
171
172 if old_gname != group_name or not edit:
172 if old_gname != group_name or not edit:
173
173
174 # check group
174 # check group
175 gr = RepoGroup.query()\
175 gr = RepoGroup.query()\
176 .filter(RepoGroup.group_name == slug)\
176 .filter(RepoGroup.group_name == slug)\
177 .filter(RepoGroup.group_parent_id == group_parent_id)\
177 .filter(RepoGroup.group_parent_id == group_parent_id)\
178 .scalar()
178 .scalar()
179
179
180 if gr:
180 if gr:
181 msg = M(self, 'group_exists', state, group_name=slug)
181 msg = M(self, 'group_exists', state, group_name=slug)
182 raise formencode.Invalid(msg, value, state,
182 raise formencode.Invalid(msg, value, state,
183 error_dict=dict(group_name=msg)
183 error_dict=dict(group_name=msg)
184 )
184 )
185
185
186 # check for same repo
186 # check for same repo
187 repo = Repository.query()\
187 repo = Repository.query()\
188 .filter(Repository.repo_name == slug)\
188 .filter(Repository.repo_name == slug)\
189 .scalar()
189 .scalar()
190
190
191 if repo:
191 if repo:
192 msg = M(self, 'repo_exists', state, group_name=slug)
192 msg = M(self, 'repo_exists', state, group_name=slug)
193 raise formencode.Invalid(msg, value, state,
193 raise formencode.Invalid(msg, value, state,
194 error_dict=dict(group_name=msg)
194 error_dict=dict(group_name=msg)
195 )
195 )
196
196
197 return _validator
197 return _validator
198
198
199
199
200 def ValidPassword():
200 def ValidPassword():
201 class _validator(formencode.validators.FancyValidator):
201 class _validator(formencode.validators.FancyValidator):
202 messages = {
202 messages = {
203 'invalid_password':
203 'invalid_password':
204 _(u'Invalid characters (non-ascii) in password')
204 _(u'Invalid characters (non-ascii) in password')
205 }
205 }
206
206
207 def validate_python(self, value, state):
207 def validate_python(self, value, state):
208 try:
208 try:
209 (value or '').decode('ascii')
209 (value or '').decode('ascii')
210 except UnicodeError:
210 except UnicodeError:
211 msg = M(self, 'invalid_password', state)
211 msg = M(self, 'invalid_password', state)
212 raise formencode.Invalid(msg, value, state,)
212 raise formencode.Invalid(msg, value, state,)
213 return _validator
213 return _validator
214
214
215
215
216 def ValidPasswordsMatch():
216 def ValidPasswordsMatch():
217 class _validator(formencode.validators.FancyValidator):
217 class _validator(formencode.validators.FancyValidator):
218 messages = {
218 messages = {
219 'password_mismatch': _(u'Passwords do not match'),
219 'password_mismatch': _(u'Passwords do not match'),
220 }
220 }
221
221
222 def validate_python(self, value, state):
222 def validate_python(self, value, state):
223
223
224 pass_val = value.get('password') or value.get('new_password')
224 pass_val = value.get('password') or value.get('new_password')
225 if pass_val != value['password_confirmation']:
225 if pass_val != value['password_confirmation']:
226 msg = M(self, 'password_mismatch', state)
226 msg = M(self, 'password_mismatch', state)
227 raise formencode.Invalid(msg, value, state,
227 raise formencode.Invalid(msg, value, state,
228 error_dict=dict(password_confirmation=msg)
228 error_dict=dict(password_confirmation=msg)
229 )
229 )
230 return _validator
230 return _validator
231
231
232
232
233 def ValidAuth():
233 def ValidAuth():
234 class _validator(formencode.validators.FancyValidator):
234 class _validator(formencode.validators.FancyValidator):
235 messages = {
235 messages = {
236 'invalid_password': _(u'invalid password'),
236 'invalid_password': _(u'invalid password'),
237 'invalid_username': _(u'invalid user name'),
237 'invalid_username': _(u'invalid user name'),
238 'disabled_account': _(u'Your account is disabled')
238 'disabled_account': _(u'Your account is disabled')
239 }
239 }
240
240
241 def validate_python(self, value, state):
241 def validate_python(self, value, state):
242 from rhodecode.lib.auth import authenticate
242 from rhodecode.lib.auth import authenticate
243
243
244 password = value['password']
244 password = value['password']
245 username = value['username']
245 username = value['username']
246
246
247 if not authenticate(username, password):
247 if not authenticate(username, password):
248 user = User.get_by_username(username)
248 user = User.get_by_username(username)
249 if user and user.active is False:
249 if user and user.active is False:
250 log.warning('user %s is disabled' % username)
250 log.warning('user %s is disabled' % username)
251 msg = M(self, 'disabled_account', state)
251 msg = M(self, 'disabled_account', state)
252 raise formencode.Invalid(msg, value, state,
252 raise formencode.Invalid(msg, value, state,
253 error_dict=dict(username=msg)
253 error_dict=dict(username=msg)
254 )
254 )
255 else:
255 else:
256 log.warning('user %s failed to authenticate' % username)
256 log.warning('user %s failed to authenticate' % username)
257 msg = M(self, 'invalid_username', state)
257 msg = M(self, 'invalid_username', state)
258 msg2 = M(self, 'invalid_password', state)
258 msg2 = M(self, 'invalid_password', state)
259 raise formencode.Invalid(msg, value, state,
259 raise formencode.Invalid(msg, value, state,
260 error_dict=dict(username=msg, password=msg2)
260 error_dict=dict(username=msg, password=msg2)
261 )
261 )
262 return _validator
262 return _validator
263
263
264
264
265 def ValidAuthToken():
265 def ValidAuthToken():
266 class _validator(formencode.validators.FancyValidator):
266 class _validator(formencode.validators.FancyValidator):
267 messages = {
267 messages = {
268 'invalid_token': _(u'Token mismatch')
268 'invalid_token': _(u'Token mismatch')
269 }
269 }
270
270
271 def validate_python(self, value, state):
271 def validate_python(self, value, state):
272 if value != authentication_token():
272 if value != authentication_token():
273 msg = M(self, 'invalid_token', state)
273 msg = M(self, 'invalid_token', state)
274 raise formencode.Invalid(msg, value, state)
274 raise formencode.Invalid(msg, value, state)
275 return _validator
275 return _validator
276
276
277
277
278 def ValidRepoName(edit=False, old_data={}):
278 def ValidRepoName(edit=False, old_data={}):
279 class _validator(formencode.validators.FancyValidator):
279 class _validator(formencode.validators.FancyValidator):
280 messages = {
280 messages = {
281 'invalid_repo_name':
281 'invalid_repo_name':
282 _(u'Repository name %(repo)s is disallowed'),
282 _(u'Repository name %(repo)s is disallowed'),
283 'repository_exists':
283 'repository_exists':
284 _(u'Repository named %(repo)s already exists'),
284 _(u'Repository named %(repo)s already exists'),
285 'repository_in_group_exists': _(u'Repository "%(repo)s" already '
285 'repository_in_group_exists': _(u'Repository "%(repo)s" already '
286 'exists in group "%(group)s"'),
286 'exists in group "%(group)s"'),
287 'same_group_exists': _(u'Repositories group with name "%(repo)s" '
287 'same_group_exists': _(u'Repositories group with name "%(repo)s" '
288 'already exists')
288 'already exists')
289 }
289 }
290
290
291 def _to_python(self, value, state):
291 def _to_python(self, value, state):
292 repo_name = repo_name_slug(value.get('repo_name', ''))
292 repo_name = repo_name_slug(value.get('repo_name', ''))
293 repo_group = value.get('repo_group')
293 repo_group = value.get('repo_group')
294 if repo_group:
294 if repo_group:
295 gr = RepoGroup.get(repo_group)
295 gr = RepoGroup.get(repo_group)
296 group_path = gr.full_path
296 group_path = gr.full_path
297 group_name = gr.group_name
297 group_name = gr.group_name
298 # value needs to be aware of group name in order to check
298 # value needs to be aware of group name in order to check
299 # db key This is an actual just the name to store in the
299 # db key This is an actual just the name to store in the
300 # database
300 # database
301 repo_name_full = group_path + RepoGroup.url_sep() + repo_name
301 repo_name_full = group_path + RepoGroup.url_sep() + repo_name
302 else:
302 else:
303 group_name = group_path = ''
303 group_name = group_path = ''
304 repo_name_full = repo_name
304 repo_name_full = repo_name
305
305
306 value['repo_name'] = repo_name
306 value['repo_name'] = repo_name
307 value['repo_name_full'] = repo_name_full
307 value['repo_name_full'] = repo_name_full
308 value['group_path'] = group_path
308 value['group_path'] = group_path
309 value['group_name'] = group_name
309 value['group_name'] = group_name
310 return value
310 return value
311
311
312 def validate_python(self, value, state):
312 def validate_python(self, value, state):
313
313
314 repo_name = value.get('repo_name')
314 repo_name = value.get('repo_name')
315 repo_name_full = value.get('repo_name_full')
315 repo_name_full = value.get('repo_name_full')
316 group_path = value.get('group_path')
316 group_path = value.get('group_path')
317 group_name = value.get('group_name')
317 group_name = value.get('group_name')
318
318
319 if repo_name in [ADMIN_PREFIX, '']:
319 if repo_name in [ADMIN_PREFIX, '']:
320 msg = M(self, 'invalid_repo_name', state, repo=repo_name)
320 msg = M(self, 'invalid_repo_name', state, repo=repo_name)
321 raise formencode.Invalid(msg, value, state,
321 raise formencode.Invalid(msg, value, state,
322 error_dict=dict(repo_name=msg)
322 error_dict=dict(repo_name=msg)
323 )
323 )
324
324
325 rename = old_data.get('repo_name') != repo_name_full
325 rename = old_data.get('repo_name') != repo_name_full
326 create = not edit
326 create = not edit
327 if rename or create:
327 if rename or create:
328
328
329 if group_path != '':
329 if group_path != '':
330 if Repository.get_by_repo_name(repo_name_full):
330 if Repository.get_by_repo_name(repo_name_full):
331 msg = M(self, 'repository_in_group_exists', state,
331 msg = M(self, 'repository_in_group_exists', state,
332 repo=repo_name, group=group_name)
332 repo=repo_name, group=group_name)
333 raise formencode.Invalid(msg, value, state,
333 raise formencode.Invalid(msg, value, state,
334 error_dict=dict(repo_name=msg)
334 error_dict=dict(repo_name=msg)
335 )
335 )
336 elif RepoGroup.get_by_group_name(repo_name_full):
336 elif RepoGroup.get_by_group_name(repo_name_full):
337 msg = M(self, 'same_group_exists', state,
337 msg = M(self, 'same_group_exists', state,
338 repo=repo_name)
338 repo=repo_name)
339 raise formencode.Invalid(msg, value, state,
339 raise formencode.Invalid(msg, value, state,
340 error_dict=dict(repo_name=msg)
340 error_dict=dict(repo_name=msg)
341 )
341 )
342
342
343 elif Repository.get_by_repo_name(repo_name_full):
343 elif Repository.get_by_repo_name(repo_name_full):
344 msg = M(self, 'repository_exists', state,
344 msg = M(self, 'repository_exists', state,
345 repo=repo_name)
345 repo=repo_name)
346 raise formencode.Invalid(msg, value, state,
346 raise formencode.Invalid(msg, value, state,
347 error_dict=dict(repo_name=msg)
347 error_dict=dict(repo_name=msg)
348 )
348 )
349 return value
349 return value
350 return _validator
350 return _validator
351
351
352
352
353 def ValidForkName(*args, **kwargs):
353 def ValidForkName(*args, **kwargs):
354 return ValidRepoName(*args, **kwargs)
354 return ValidRepoName(*args, **kwargs)
355
355
356
356
357 def SlugifyName():
357 def SlugifyName():
358 class _validator(formencode.validators.FancyValidator):
358 class _validator(formencode.validators.FancyValidator):
359
359
360 def _to_python(self, value, state):
360 def _to_python(self, value, state):
361 return repo_name_slug(value)
361 return repo_name_slug(value)
362
362
363 def validate_python(self, value, state):
363 def validate_python(self, value, state):
364 pass
364 pass
365
365
366 return _validator
366 return _validator
367
367
368
368
369 def ValidCloneUri():
369 def ValidCloneUri():
370 from rhodecode.lib.utils import make_ui
370 from rhodecode.lib.utils import make_ui
371
371
372 def url_handler(repo_type, url, ui=None):
372 def url_handler(repo_type, url, ui=None):
373 if repo_type == 'hg':
373 if repo_type == 'hg':
374 from rhodecode.lib.vcs.backends.hg.repository import MercurialRepository
374 from rhodecode.lib.vcs.backends.hg.repository import MercurialRepository
375 from mercurial.httppeer import httppeer
375 from mercurial.httppeer import httppeer
376 if url.startswith('http'):
376 if url.startswith('http'):
377 ## initially check if it's at least the proper URL
377 ## initially check if it's at least the proper URL
378 ## or does it pass basic auth
378 ## or does it pass basic auth
379 MercurialRepository._check_url(url)
379 MercurialRepository._check_url(url)
380 httppeer(make_ui('db'), url)._capabilities()
380 httppeer(ui, url)._capabilities()
381 elif url.startswith('svn+http'):
381 elif url.startswith('svn+http'):
382 from hgsubversion.svnrepo import svnremoterepo
382 from hgsubversion.svnrepo import svnremoterepo
383 svnremoterepo(make_ui('db'), url).capabilities
383 svnremoterepo(ui, url).capabilities
384 elif url.startswith('git+http'):
384 elif url.startswith('git+http'):
385 raise NotImplementedError()
385 raise NotImplementedError()
386
386
387 elif repo_type == 'git':
387 elif repo_type == 'git':
388 from rhodecode.lib.vcs.backends.git.repository import GitRepository
388 from rhodecode.lib.vcs.backends.git.repository import GitRepository
389 if url.startswith('http'):
389 if url.startswith('http'):
390 ## initially check if it's at least the proper URL
390 ## initially check if it's at least the proper URL
391 ## or does it pass basic auth
391 ## or does it pass basic auth
392 GitRepository._check_url(url)
392 GitRepository._check_url(url)
393 elif url.startswith('svn+http'):
393 elif url.startswith('svn+http'):
394 raise NotImplementedError()
394 raise NotImplementedError()
395 elif url.startswith('hg+http'):
395 elif url.startswith('hg+http'):
396 raise NotImplementedError()
396 raise NotImplementedError()
397
397
398 class _validator(formencode.validators.FancyValidator):
398 class _validator(formencode.validators.FancyValidator):
399 messages = {
399 messages = {
400 'clone_uri': _(u'invalid clone url'),
400 'clone_uri': _(u'invalid clone url'),
401 'invalid_clone_uri': _(u'Invalid clone url, provide a '
401 'invalid_clone_uri': _(u'Invalid clone url, provide a '
402 'valid clone http(s)/svn+http(s) url')
402 'valid clone http(s)/svn+http(s) url')
403 }
403 }
404
404
405 def validate_python(self, value, state):
405 def validate_python(self, value, state):
406 repo_type = value.get('repo_type')
406 repo_type = value.get('repo_type')
407 url = value.get('clone_uri')
407 url = value.get('clone_uri')
408
408
409 if not url:
409 if not url:
410 pass
410 pass
411 else:
411 else:
412 try:
412 try:
413 url_handler(repo_type, url, make_ui('db'))
413 url_handler(repo_type, url, make_ui('db', clear_session=False))
414 except Exception:
414 except Exception:
415 log.exception('Url validation failed')
415 log.exception('Url validation failed')
416 msg = M(self, 'clone_uri')
416 msg = M(self, 'clone_uri')
417 raise formencode.Invalid(msg, value, state,
417 raise formencode.Invalid(msg, value, state,
418 error_dict=dict(clone_uri=msg)
418 error_dict=dict(clone_uri=msg)
419 )
419 )
420 return _validator
420 return _validator
421
421
422
422
423 def ValidForkType(old_data={}):
423 def ValidForkType(old_data={}):
424 class _validator(formencode.validators.FancyValidator):
424 class _validator(formencode.validators.FancyValidator):
425 messages = {
425 messages = {
426 'invalid_fork_type': _(u'Fork have to be the same type as parent')
426 'invalid_fork_type': _(u'Fork have to be the same type as parent')
427 }
427 }
428
428
429 def validate_python(self, value, state):
429 def validate_python(self, value, state):
430 if old_data['repo_type'] != value:
430 if old_data['repo_type'] != value:
431 msg = M(self, 'invalid_fork_type', state)
431 msg = M(self, 'invalid_fork_type', state)
432 raise formencode.Invalid(msg, value, state,
432 raise formencode.Invalid(msg, value, state,
433 error_dict=dict(repo_type=msg)
433 error_dict=dict(repo_type=msg)
434 )
434 )
435 return _validator
435 return _validator
436
436
437
437
438 def ValidPerms(type_='repo'):
438 def ValidPerms(type_='repo'):
439 if type_ == 'group':
439 if type_ == 'group':
440 EMPTY_PERM = 'group.none'
440 EMPTY_PERM = 'group.none'
441 elif type_ == 'repo':
441 elif type_ == 'repo':
442 EMPTY_PERM = 'repository.none'
442 EMPTY_PERM = 'repository.none'
443
443
444 class _validator(formencode.validators.FancyValidator):
444 class _validator(formencode.validators.FancyValidator):
445 messages = {
445 messages = {
446 'perm_new_member_name':
446 'perm_new_member_name':
447 _(u'This username or users group name is not valid')
447 _(u'This username or users group name is not valid')
448 }
448 }
449
449
450 def to_python(self, value, state):
450 def to_python(self, value, state):
451 perms_update = []
451 perms_update = []
452 perms_new = []
452 perms_new = []
453 # build a list of permission to update and new permission to create
453 # build a list of permission to update and new permission to create
454 for k, v in value.items():
454 for k, v in value.items():
455 # means new added member to permissions
455 # means new added member to permissions
456 if k.startswith('perm_new_member'):
456 if k.startswith('perm_new_member'):
457 new_perm = value.get('perm_new_member', False)
457 new_perm = value.get('perm_new_member', False)
458 new_member = value.get('perm_new_member_name', False)
458 new_member = value.get('perm_new_member_name', False)
459 new_type = value.get('perm_new_member_type')
459 new_type = value.get('perm_new_member_type')
460
460
461 if new_member and new_perm:
461 if new_member and new_perm:
462 if (new_member, new_perm, new_type) not in perms_new:
462 if (new_member, new_perm, new_type) not in perms_new:
463 perms_new.append((new_member, new_perm, new_type))
463 perms_new.append((new_member, new_perm, new_type))
464 elif k.startswith('u_perm_') or k.startswith('g_perm_'):
464 elif k.startswith('u_perm_') or k.startswith('g_perm_'):
465 member = k[7:]
465 member = k[7:]
466 t = {'u': 'user',
466 t = {'u': 'user',
467 'g': 'users_group'
467 'g': 'users_group'
468 }[k[0]]
468 }[k[0]]
469 if member == 'default':
469 if member == 'default':
470 if value.get('private'):
470 if value.get('private'):
471 # set none for default when updating to
471 # set none for default when updating to
472 # private repo
472 # private repo
473 v = EMPTY_PERM
473 v = EMPTY_PERM
474 perms_update.append((member, v, t))
474 perms_update.append((member, v, t))
475
475
476 value['perms_updates'] = perms_update
476 value['perms_updates'] = perms_update
477 value['perms_new'] = perms_new
477 value['perms_new'] = perms_new
478
478
479 # update permissions
479 # update permissions
480 for k, v, t in perms_new:
480 for k, v, t in perms_new:
481 try:
481 try:
482 if t is 'user':
482 if t is 'user':
483 self.user_db = User.query()\
483 self.user_db = User.query()\
484 .filter(User.active == True)\
484 .filter(User.active == True)\
485 .filter(User.username == k).one()
485 .filter(User.username == k).one()
486 if t is 'users_group':
486 if t is 'users_group':
487 self.user_db = UsersGroup.query()\
487 self.user_db = UsersGroup.query()\
488 .filter(UsersGroup.users_group_active == True)\
488 .filter(UsersGroup.users_group_active == True)\
489 .filter(UsersGroup.users_group_name == k).one()
489 .filter(UsersGroup.users_group_name == k).one()
490
490
491 except Exception:
491 except Exception:
492 log.exception('Updated permission failed')
492 log.exception('Updated permission failed')
493 msg = M(self, 'perm_new_member_type', state)
493 msg = M(self, 'perm_new_member_type', state)
494 raise formencode.Invalid(msg, value, state,
494 raise formencode.Invalid(msg, value, state,
495 error_dict=dict(perm_new_member_name=msg)
495 error_dict=dict(perm_new_member_name=msg)
496 )
496 )
497 return value
497 return value
498 return _validator
498 return _validator
499
499
500
500
501 def ValidSettings():
501 def ValidSettings():
502 class _validator(formencode.validators.FancyValidator):
502 class _validator(formencode.validators.FancyValidator):
503 def _to_python(self, value, state):
503 def _to_python(self, value, state):
504 # settings form can't edit user
504 # settings form can't edit user
505 if 'user' in value:
505 if 'user' in value:
506 del value['user']
506 del value['user']
507 return value
507 return value
508
508
509 def validate_python(self, value, state):
509 def validate_python(self, value, state):
510 pass
510 pass
511 return _validator
511 return _validator
512
512
513
513
514 def ValidPath():
514 def ValidPath():
515 class _validator(formencode.validators.FancyValidator):
515 class _validator(formencode.validators.FancyValidator):
516 messages = {
516 messages = {
517 'invalid_path': _(u'This is not a valid path')
517 'invalid_path': _(u'This is not a valid path')
518 }
518 }
519
519
520 def validate_python(self, value, state):
520 def validate_python(self, value, state):
521 if not os.path.isdir(value):
521 if not os.path.isdir(value):
522 msg = M(self, 'invalid_path', state)
522 msg = M(self, 'invalid_path', state)
523 raise formencode.Invalid(msg, value, state,
523 raise formencode.Invalid(msg, value, state,
524 error_dict=dict(paths_root_path=msg)
524 error_dict=dict(paths_root_path=msg)
525 )
525 )
526 return _validator
526 return _validator
527
527
528
528
529 def UniqSystemEmail(old_data={}):
529 def UniqSystemEmail(old_data={}):
530 class _validator(formencode.validators.FancyValidator):
530 class _validator(formencode.validators.FancyValidator):
531 messages = {
531 messages = {
532 'email_taken': _(u'This e-mail address is already taken')
532 'email_taken': _(u'This e-mail address is already taken')
533 }
533 }
534
534
535 def _to_python(self, value, state):
535 def _to_python(self, value, state):
536 return value.lower()
536 return value.lower()
537
537
538 def validate_python(self, value, state):
538 def validate_python(self, value, state):
539 if (old_data.get('email') or '').lower() != value:
539 if (old_data.get('email') or '').lower() != value:
540 user = User.get_by_email(value, case_insensitive=True)
540 user = User.get_by_email(value, case_insensitive=True)
541 if user:
541 if user:
542 msg = M(self, 'email_taken', state)
542 msg = M(self, 'email_taken', state)
543 raise formencode.Invalid(msg, value, state,
543 raise formencode.Invalid(msg, value, state,
544 error_dict=dict(email=msg)
544 error_dict=dict(email=msg)
545 )
545 )
546 return _validator
546 return _validator
547
547
548
548
549 def ValidSystemEmail():
549 def ValidSystemEmail():
550 class _validator(formencode.validators.FancyValidator):
550 class _validator(formencode.validators.FancyValidator):
551 messages = {
551 messages = {
552 'non_existing_email': _(u'e-mail "%(email)s" does not exist.')
552 'non_existing_email': _(u'e-mail "%(email)s" does not exist.')
553 }
553 }
554
554
555 def _to_python(self, value, state):
555 def _to_python(self, value, state):
556 return value.lower()
556 return value.lower()
557
557
558 def validate_python(self, value, state):
558 def validate_python(self, value, state):
559 user = User.get_by_email(value, case_insensitive=True)
559 user = User.get_by_email(value, case_insensitive=True)
560 if user is None:
560 if user is None:
561 msg = M(self, 'non_existing_email', state, email=value)
561 msg = M(self, 'non_existing_email', state, email=value)
562 raise formencode.Invalid(msg, value, state,
562 raise formencode.Invalid(msg, value, state,
563 error_dict=dict(email=msg)
563 error_dict=dict(email=msg)
564 )
564 )
565
565
566 return _validator
566 return _validator
567
567
568
568
569 def LdapLibValidator():
569 def LdapLibValidator():
570 class _validator(formencode.validators.FancyValidator):
570 class _validator(formencode.validators.FancyValidator):
571 messages = {
571 messages = {
572
572
573 }
573 }
574
574
575 def validate_python(self, value, state):
575 def validate_python(self, value, state):
576 try:
576 try:
577 import ldap
577 import ldap
578 ldap # pyflakes silence !
578 ldap # pyflakes silence !
579 except ImportError:
579 except ImportError:
580 raise LdapImportError()
580 raise LdapImportError()
581
581
582 return _validator
582 return _validator
583
583
584
584
585 def AttrLoginValidator():
585 def AttrLoginValidator():
586 class _validator(formencode.validators.FancyValidator):
586 class _validator(formencode.validators.FancyValidator):
587 messages = {
587 messages = {
588 'invalid_cn':
588 'invalid_cn':
589 _(u'The LDAP Login attribute of the CN must be specified - '
589 _(u'The LDAP Login attribute of the CN must be specified - '
590 'this is the name of the attribute that is equivalent '
590 'this is the name of the attribute that is equivalent '
591 'to "username"')
591 'to "username"')
592 }
592 }
593
593
594 def validate_python(self, value, state):
594 def validate_python(self, value, state):
595 if not value or not isinstance(value, (str, unicode)):
595 if not value or not isinstance(value, (str, unicode)):
596 msg = M(self, 'invalid_cn', state)
596 msg = M(self, 'invalid_cn', state)
597 raise formencode.Invalid(msg, value, state,
597 raise formencode.Invalid(msg, value, state,
598 error_dict=dict(ldap_attr_login=msg)
598 error_dict=dict(ldap_attr_login=msg)
599 )
599 )
600
600
601 return _validator
601 return _validator
General Comments 0
You need to be logged in to leave comments. Login now