Show More
@@ -1,1029 +1,1029 b'' | |||||
1 | # -*- coding: utf-8 -*- |
|
1 | # -*- coding: utf-8 -*- | |
2 | """ |
|
2 | """ | |
3 | rhodecode.lib.auth |
|
3 | rhodecode.lib.auth | |
4 | ~~~~~~~~~~~~~~~~~~ |
|
4 | ~~~~~~~~~~~~~~~~~~ | |
5 |
|
5 | |||
6 | authentication and permission libraries |
|
6 | authentication and permission libraries | |
7 |
|
7 | |||
8 | :created_on: Apr 4, 2010 |
|
8 | :created_on: Apr 4, 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 random |
|
26 | import random | |
27 | import logging |
|
27 | import logging | |
28 | import traceback |
|
28 | import traceback | |
29 | import hashlib |
|
29 | import hashlib | |
30 |
|
30 | |||
31 | from tempfile import _RandomNameSequence |
|
31 | from tempfile import _RandomNameSequence | |
32 | from decorator import decorator |
|
32 | from decorator import decorator | |
33 |
|
33 | |||
34 | from pylons import config, url, request |
|
34 | from pylons import config, url, request | |
35 | from pylons.controllers.util import abort, redirect |
|
35 | from pylons.controllers.util import abort, redirect | |
36 | from pylons.i18n.translation import _ |
|
36 | from pylons.i18n.translation import _ | |
37 | from sqlalchemy.orm.exc import ObjectDeletedError |
|
37 | from sqlalchemy.orm.exc import ObjectDeletedError | |
38 |
|
38 | |||
39 | from rhodecode import __platform__, is_windows, is_unix |
|
39 | from rhodecode import __platform__, is_windows, is_unix | |
40 | from rhodecode.model.meta import Session |
|
40 | from rhodecode.model.meta import Session | |
41 |
|
41 | |||
42 | from rhodecode.lib.utils2 import str2bool, safe_unicode |
|
42 | from rhodecode.lib.utils2 import str2bool, safe_unicode | |
43 | from rhodecode.lib.exceptions import LdapPasswordError, LdapUsernameError |
|
43 | from rhodecode.lib.exceptions import LdapPasswordError, LdapUsernameError | |
44 | from rhodecode.lib.utils import get_repo_slug, get_repos_group_slug |
|
44 | from rhodecode.lib.utils import get_repo_slug, get_repos_group_slug | |
45 | from rhodecode.lib.auth_ldap import AuthLdap |
|
45 | from rhodecode.lib.auth_ldap import AuthLdap | |
46 |
|
46 | |||
47 | from rhodecode.model import meta |
|
47 | from rhodecode.model import meta | |
48 | from rhodecode.model.user import UserModel |
|
48 | from rhodecode.model.user import UserModel | |
49 | from rhodecode.model.db import Permission, RhodeCodeSetting, User, UserIpMap |
|
49 | from rhodecode.model.db import Permission, RhodeCodeSetting, User, UserIpMap | |
50 | from rhodecode.lib.caching_query import FromCache |
|
50 | from rhodecode.lib.caching_query import FromCache | |
51 |
|
51 | |||
52 | log = logging.getLogger(__name__) |
|
52 | log = logging.getLogger(__name__) | |
53 |
|
53 | |||
54 |
|
54 | |||
55 | class PasswordGenerator(object): |
|
55 | class PasswordGenerator(object): | |
56 | """ |
|
56 | """ | |
57 | This is a simple class for generating password from different sets of |
|
57 | This is a simple class for generating password from different sets of | |
58 | characters |
|
58 | characters | |
59 | usage:: |
|
59 | usage:: | |
60 |
|
60 | |||
61 | passwd_gen = PasswordGenerator() |
|
61 | passwd_gen = PasswordGenerator() | |
62 | #print 8-letter password containing only big and small letters |
|
62 | #print 8-letter password containing only big and small letters | |
63 | of alphabet |
|
63 | of alphabet | |
64 | passwd_gen.gen_password(8, passwd_gen.ALPHABETS_BIG_SMALL) |
|
64 | passwd_gen.gen_password(8, passwd_gen.ALPHABETS_BIG_SMALL) | |
65 | """ |
|
65 | """ | |
66 | ALPHABETS_NUM = r'''1234567890''' |
|
66 | ALPHABETS_NUM = r'''1234567890''' | |
67 | ALPHABETS_SMALL = r'''qwertyuiopasdfghjklzxcvbnm''' |
|
67 | ALPHABETS_SMALL = r'''qwertyuiopasdfghjklzxcvbnm''' | |
68 | ALPHABETS_BIG = r'''QWERTYUIOPASDFGHJKLZXCVBNM''' |
|
68 | ALPHABETS_BIG = r'''QWERTYUIOPASDFGHJKLZXCVBNM''' | |
69 | ALPHABETS_SPECIAL = r'''`-=[]\;',./~!@#$%^&*()_+{}|:"<>?''' |
|
69 | ALPHABETS_SPECIAL = r'''`-=[]\;',./~!@#$%^&*()_+{}|:"<>?''' | |
70 | ALPHABETS_FULL = ALPHABETS_BIG + ALPHABETS_SMALL \ |
|
70 | ALPHABETS_FULL = ALPHABETS_BIG + ALPHABETS_SMALL \ | |
71 | + ALPHABETS_NUM + ALPHABETS_SPECIAL |
|
71 | + ALPHABETS_NUM + ALPHABETS_SPECIAL | |
72 | ALPHABETS_ALPHANUM = ALPHABETS_BIG + ALPHABETS_SMALL + ALPHABETS_NUM |
|
72 | ALPHABETS_ALPHANUM = ALPHABETS_BIG + ALPHABETS_SMALL + ALPHABETS_NUM | |
73 | ALPHABETS_BIG_SMALL = ALPHABETS_BIG + ALPHABETS_SMALL |
|
73 | ALPHABETS_BIG_SMALL = ALPHABETS_BIG + ALPHABETS_SMALL | |
74 | ALPHABETS_ALPHANUM_BIG = ALPHABETS_BIG + ALPHABETS_NUM |
|
74 | ALPHABETS_ALPHANUM_BIG = ALPHABETS_BIG + ALPHABETS_NUM | |
75 | ALPHABETS_ALPHANUM_SMALL = ALPHABETS_SMALL + ALPHABETS_NUM |
|
75 | ALPHABETS_ALPHANUM_SMALL = ALPHABETS_SMALL + ALPHABETS_NUM | |
76 |
|
76 | |||
77 | def __init__(self, passwd=''): |
|
77 | def __init__(self, passwd=''): | |
78 | self.passwd = passwd |
|
78 | self.passwd = passwd | |
79 |
|
79 | |||
80 | def gen_password(self, length, type_=None): |
|
80 | def gen_password(self, length, type_=None): | |
81 | if type_ is None: |
|
81 | if type_ is None: | |
82 | type_ = self.ALPHABETS_FULL |
|
82 | type_ = self.ALPHABETS_FULL | |
83 | self.passwd = ''.join([random.choice(type_) for _ in xrange(length)]) |
|
83 | self.passwd = ''.join([random.choice(type_) for _ in xrange(length)]) | |
84 | return self.passwd |
|
84 | return self.passwd | |
85 |
|
85 | |||
86 |
|
86 | |||
87 | class RhodeCodeCrypto(object): |
|
87 | class RhodeCodeCrypto(object): | |
88 |
|
88 | |||
89 | @classmethod |
|
89 | @classmethod | |
90 | def hash_string(cls, str_): |
|
90 | def hash_string(cls, str_): | |
91 | """ |
|
91 | """ | |
92 | Cryptographic function used for password hashing based on pybcrypt |
|
92 | Cryptographic function used for password hashing based on pybcrypt | |
93 | or pycrypto in windows |
|
93 | or pycrypto in windows | |
94 |
|
94 | |||
95 | :param password: password to hash |
|
95 | :param password: password to hash | |
96 | """ |
|
96 | """ | |
97 | if is_windows: |
|
97 | if is_windows: | |
98 | from hashlib import sha256 |
|
98 | from hashlib import sha256 | |
99 | return sha256(str_).hexdigest() |
|
99 | return sha256(str_).hexdigest() | |
100 | elif is_unix: |
|
100 | elif is_unix: | |
101 | import bcrypt |
|
101 | import bcrypt | |
102 | return bcrypt.hashpw(str_, bcrypt.gensalt(10)) |
|
102 | return bcrypt.hashpw(str_, bcrypt.gensalt(10)) | |
103 | else: |
|
103 | else: | |
104 | raise Exception('Unknown or unsupported platform %s' \ |
|
104 | raise Exception('Unknown or unsupported platform %s' \ | |
105 | % __platform__) |
|
105 | % __platform__) | |
106 |
|
106 | |||
107 | @classmethod |
|
107 | @classmethod | |
108 | def hash_check(cls, password, hashed): |
|
108 | def hash_check(cls, password, hashed): | |
109 | """ |
|
109 | """ | |
110 | Checks matching password with it's hashed value, runs different |
|
110 | Checks matching password with it's hashed value, runs different | |
111 | implementation based on platform it runs on |
|
111 | implementation based on platform it runs on | |
112 |
|
112 | |||
113 | :param password: password |
|
113 | :param password: password | |
114 | :param hashed: password in hashed form |
|
114 | :param hashed: password in hashed form | |
115 | """ |
|
115 | """ | |
116 |
|
116 | |||
117 | if is_windows: |
|
117 | if is_windows: | |
118 | from hashlib import sha256 |
|
118 | from hashlib import sha256 | |
119 | return sha256(password).hexdigest() == hashed |
|
119 | return sha256(password).hexdigest() == hashed | |
120 | elif is_unix: |
|
120 | elif is_unix: | |
121 | import bcrypt |
|
121 | import bcrypt | |
122 | return bcrypt.hashpw(password, hashed) == hashed |
|
122 | return bcrypt.hashpw(password, hashed) == hashed | |
123 | else: |
|
123 | else: | |
124 | raise Exception('Unknown or unsupported platform %s' \ |
|
124 | raise Exception('Unknown or unsupported platform %s' \ | |
125 | % __platform__) |
|
125 | % __platform__) | |
126 |
|
126 | |||
127 |
|
127 | |||
128 | def get_crypt_password(password): |
|
128 | def get_crypt_password(password): | |
129 | return RhodeCodeCrypto.hash_string(password) |
|
129 | return RhodeCodeCrypto.hash_string(password) | |
130 |
|
130 | |||
131 |
|
131 | |||
132 | def check_password(password, hashed): |
|
132 | def check_password(password, hashed): | |
133 | return RhodeCodeCrypto.hash_check(password, hashed) |
|
133 | return RhodeCodeCrypto.hash_check(password, hashed) | |
134 |
|
134 | |||
135 |
|
135 | |||
136 | def generate_api_key(str_, salt=None): |
|
136 | def generate_api_key(str_, salt=None): | |
137 | """ |
|
137 | """ | |
138 | Generates API KEY from given string |
|
138 | Generates API KEY from given string | |
139 |
|
139 | |||
140 | :param str_: |
|
140 | :param str_: | |
141 | :param salt: |
|
141 | :param salt: | |
142 | """ |
|
142 | """ | |
143 |
|
143 | |||
144 | if salt is None: |
|
144 | if salt is None: | |
145 | salt = _RandomNameSequence().next() |
|
145 | salt = _RandomNameSequence().next() | |
146 |
|
146 | |||
147 | return hashlib.sha1(str_ + salt).hexdigest() |
|
147 | return hashlib.sha1(str_ + salt).hexdigest() | |
148 |
|
148 | |||
149 |
|
149 | |||
150 | def authfunc(environ, username, password): |
|
150 | def authfunc(environ, username, password): | |
151 | """ |
|
151 | """ | |
152 | Dummy authentication wrapper function used in Mercurial and Git for |
|
152 | Dummy authentication wrapper function used in Mercurial and Git for | |
153 | access control. |
|
153 | access control. | |
154 |
|
154 | |||
155 | :param environ: needed only for using in Basic auth |
|
155 | :param environ: needed only for using in Basic auth | |
156 | """ |
|
156 | """ | |
157 | return authenticate(username, password) |
|
157 | return authenticate(username, password) | |
158 |
|
158 | |||
159 |
|
159 | |||
160 | def authenticate(username, password): |
|
160 | def authenticate(username, password): | |
161 | """ |
|
161 | """ | |
162 | Authentication function used for access control, |
|
162 | Authentication function used for access control, | |
163 | firstly checks for db authentication then if ldap is enabled for ldap |
|
163 | firstly checks for db authentication then if ldap is enabled for ldap | |
164 | authentication, also creates ldap user if not in database |
|
164 | authentication, also creates ldap user if not in database | |
165 |
|
165 | |||
166 | :param username: username |
|
166 | :param username: username | |
167 | :param password: password |
|
167 | :param password: password | |
168 | """ |
|
168 | """ | |
169 |
|
169 | |||
170 | user_model = UserModel() |
|
170 | user_model = UserModel() | |
171 | user = User.get_by_username(username) |
|
171 | user = User.get_by_username(username) | |
172 |
|
172 | |||
173 | log.debug('Authenticating user using RhodeCode account') |
|
173 | log.debug('Authenticating user using RhodeCode account') | |
174 | if user is not None and not user.ldap_dn: |
|
174 | if user is not None and not user.ldap_dn: | |
175 | if user.active: |
|
175 | if user.active: | |
176 | if user.username == 'default' and user.active: |
|
176 | if user.username == 'default' and user.active: | |
177 | log.info('user %s authenticated correctly as anonymous user' % |
|
177 | log.info('user %s authenticated correctly as anonymous user' % | |
178 | username) |
|
178 | username) | |
179 | return True |
|
179 | return True | |
180 |
|
180 | |||
181 | elif user.username == username and check_password(password, |
|
181 | elif user.username == username and check_password(password, | |
182 | user.password): |
|
182 | user.password): | |
183 | log.info('user %s authenticated correctly' % username) |
|
183 | log.info('user %s authenticated correctly' % username) | |
184 | return True |
|
184 | return True | |
185 | else: |
|
185 | else: | |
186 | log.warning('user %s tried auth but is disabled' % username) |
|
186 | log.warning('user %s tried auth but is disabled' % username) | |
187 |
|
187 | |||
188 | else: |
|
188 | else: | |
189 | log.debug('Regular authentication failed') |
|
189 | log.debug('Regular authentication failed') | |
190 | user_obj = User.get_by_username(username, case_insensitive=True) |
|
190 | user_obj = User.get_by_username(username, case_insensitive=True) | |
191 |
|
191 | |||
192 | if user_obj is not None and not user_obj.ldap_dn: |
|
192 | if user_obj is not None and not user_obj.ldap_dn: | |
193 | log.debug('this user already exists as non ldap') |
|
193 | log.debug('this user already exists as non ldap') | |
194 | return False |
|
194 | return False | |
195 |
|
195 | |||
196 | ldap_settings = RhodeCodeSetting.get_ldap_settings() |
|
196 | ldap_settings = RhodeCodeSetting.get_ldap_settings() | |
197 | #====================================================================== |
|
197 | #====================================================================== | |
198 | # FALLBACK TO LDAP AUTH IF ENABLE |
|
198 | # FALLBACK TO LDAP AUTH IF ENABLE | |
199 | #====================================================================== |
|
199 | #====================================================================== | |
200 | if str2bool(ldap_settings.get('ldap_active')): |
|
200 | if str2bool(ldap_settings.get('ldap_active')): | |
201 | log.debug("Authenticating user using ldap") |
|
201 | log.debug("Authenticating user using ldap") | |
202 | kwargs = { |
|
202 | kwargs = { | |
203 | 'server': ldap_settings.get('ldap_host', ''), |
|
203 | 'server': ldap_settings.get('ldap_host', ''), | |
204 | 'base_dn': ldap_settings.get('ldap_base_dn', ''), |
|
204 | 'base_dn': ldap_settings.get('ldap_base_dn', ''), | |
205 | 'port': ldap_settings.get('ldap_port'), |
|
205 | 'port': ldap_settings.get('ldap_port'), | |
206 | 'bind_dn': ldap_settings.get('ldap_dn_user'), |
|
206 | 'bind_dn': ldap_settings.get('ldap_dn_user'), | |
207 | 'bind_pass': ldap_settings.get('ldap_dn_pass'), |
|
207 | 'bind_pass': ldap_settings.get('ldap_dn_pass'), | |
208 | 'tls_kind': ldap_settings.get('ldap_tls_kind'), |
|
208 | 'tls_kind': ldap_settings.get('ldap_tls_kind'), | |
209 | 'tls_reqcert': ldap_settings.get('ldap_tls_reqcert'), |
|
209 | 'tls_reqcert': ldap_settings.get('ldap_tls_reqcert'), | |
210 | 'ldap_filter': ldap_settings.get('ldap_filter'), |
|
210 | 'ldap_filter': ldap_settings.get('ldap_filter'), | |
211 | 'search_scope': ldap_settings.get('ldap_search_scope'), |
|
211 | 'search_scope': ldap_settings.get('ldap_search_scope'), | |
212 | 'attr_login': ldap_settings.get('ldap_attr_login'), |
|
212 | 'attr_login': ldap_settings.get('ldap_attr_login'), | |
213 | 'ldap_version': 3, |
|
213 | 'ldap_version': 3, | |
214 | } |
|
214 | } | |
215 | log.debug('Checking for ldap authentication') |
|
215 | log.debug('Checking for ldap authentication') | |
216 | try: |
|
216 | try: | |
217 | aldap = AuthLdap(**kwargs) |
|
217 | aldap = AuthLdap(**kwargs) | |
218 | (user_dn, ldap_attrs) = aldap.authenticate_ldap(username, |
|
218 | (user_dn, ldap_attrs) = aldap.authenticate_ldap(username, | |
219 | password) |
|
219 | password) | |
220 | log.debug('Got ldap DN response %s' % user_dn) |
|
220 | log.debug('Got ldap DN response %s' % user_dn) | |
221 |
|
221 | |||
222 | get_ldap_attr = lambda k: ldap_attrs.get(ldap_settings\ |
|
222 | get_ldap_attr = lambda k: ldap_attrs.get(ldap_settings\ | |
223 | .get(k), [''])[0] |
|
223 | .get(k), [''])[0] | |
224 |
|
224 | |||
225 | user_attrs = { |
|
225 | user_attrs = { | |
226 | 'name': safe_unicode(get_ldap_attr('ldap_attr_firstname')), |
|
226 | 'name': safe_unicode(get_ldap_attr('ldap_attr_firstname')), | |
227 | 'lastname': safe_unicode(get_ldap_attr('ldap_attr_lastname')), |
|
227 | 'lastname': safe_unicode(get_ldap_attr('ldap_attr_lastname')), | |
228 | 'email': get_ldap_attr('ldap_attr_email'), |
|
228 | 'email': get_ldap_attr('ldap_attr_email'), | |
229 | 'active': 'hg.register.auto_activate' in User\ |
|
229 | 'active': 'hg.register.auto_activate' in User\ | |
230 | .get_by_username('default').AuthUser.permissions['global'] |
|
230 | .get_by_username('default').AuthUser.permissions['global'] | |
231 | } |
|
231 | } | |
232 |
|
232 | |||
233 | # don't store LDAP password since we don't need it. Override |
|
233 | # don't store LDAP password since we don't need it. Override | |
234 | # with some random generated password |
|
234 | # with some random generated password | |
235 | _password = PasswordGenerator().gen_password(length=8) |
|
235 | _password = PasswordGenerator().gen_password(length=8) | |
236 | # create this user on the fly if it doesn't exist in rhodecode |
|
236 | # create this user on the fly if it doesn't exist in rhodecode | |
237 | # database |
|
237 | # database | |
238 | if user_model.create_ldap(username, _password, user_dn, |
|
238 | if user_model.create_ldap(username, _password, user_dn, | |
239 | user_attrs): |
|
239 | user_attrs): | |
240 | log.info('created new ldap user %s' % username) |
|
240 | log.info('created new ldap user %s' % username) | |
241 |
|
241 | |||
242 | Session().commit() |
|
242 | Session().commit() | |
243 | return True |
|
243 | return True | |
244 | except (LdapUsernameError, LdapPasswordError,): |
|
244 | except (LdapUsernameError, LdapPasswordError,): | |
245 | pass |
|
245 | pass | |
246 | except (Exception,): |
|
246 | except (Exception,): | |
247 | log.error(traceback.format_exc()) |
|
247 | log.error(traceback.format_exc()) | |
248 | pass |
|
248 | pass | |
249 | return False |
|
249 | return False | |
250 |
|
250 | |||
251 |
|
251 | |||
252 | def login_container_auth(username): |
|
252 | def login_container_auth(username): | |
253 | user = User.get_by_username(username) |
|
253 | user = User.get_by_username(username) | |
254 | if user is None: |
|
254 | if user is None: | |
255 | user_attrs = { |
|
255 | user_attrs = { | |
256 | 'name': username, |
|
256 | 'name': username, | |
257 | 'lastname': None, |
|
257 | 'lastname': None, | |
258 | 'email': None, |
|
258 | 'email': None, | |
259 | 'active': 'hg.register.auto_activate' in User\ |
|
259 | 'active': 'hg.register.auto_activate' in User\ | |
260 | .get_by_username('default').AuthUser.permissions['global'] |
|
260 | .get_by_username('default').AuthUser.permissions['global'] | |
261 | } |
|
261 | } | |
262 | user = UserModel().create_for_container_auth(username, user_attrs) |
|
262 | user = UserModel().create_for_container_auth(username, user_attrs) | |
263 | if not user: |
|
263 | if not user: | |
264 | return None |
|
264 | return None | |
265 | log.info('User %s was created by container authentication' % username) |
|
265 | log.info('User %s was created by container authentication' % username) | |
266 |
|
266 | |||
267 | if not user.active: |
|
267 | if not user.active: | |
268 | return None |
|
268 | return None | |
269 |
|
269 | |||
270 | user.update_lastlogin() |
|
270 | user.update_lastlogin() | |
271 | Session().commit() |
|
271 | Session().commit() | |
272 |
|
272 | |||
273 | log.debug('User %s is now logged in by container authentication', |
|
273 | log.debug('User %s is now logged in by container authentication', | |
274 | user.username) |
|
274 | user.username) | |
275 | return user |
|
275 | return user | |
276 |
|
276 | |||
277 |
|
277 | |||
278 | def get_container_username(environ, config, clean_username=False): |
|
278 | def get_container_username(environ, config, clean_username=False): | |
279 | """ |
|
279 | """ | |
280 | Get's the container_auth username (or email). It tries to get username |
|
280 | Get's the container_auth username (or email). It tries to get username | |
281 | from REMOTE_USER if container_auth_enabled is enabled, if that fails |
|
281 | from REMOTE_USER if container_auth_enabled is enabled, if that fails | |
282 | it tries to get username from HTTP_X_FORWARDED_USER if proxypass_auth_enabled |
|
282 | it tries to get username from HTTP_X_FORWARDED_USER if proxypass_auth_enabled | |
283 | is enabled. clean_username extracts the username from this data if it's |
|
283 | is enabled. clean_username extracts the username from this data if it's | |
284 | having @ in it. |
|
284 | having @ in it. | |
285 |
|
285 | |||
286 | :param environ: |
|
286 | :param environ: | |
287 | :param config: |
|
287 | :param config: | |
288 | :param clean_username: |
|
288 | :param clean_username: | |
289 | """ |
|
289 | """ | |
290 | username = None |
|
290 | username = None | |
291 |
|
291 | |||
292 | if str2bool(config.get('container_auth_enabled', False)): |
|
292 | if str2bool(config.get('container_auth_enabled', False)): | |
293 | from paste.httpheaders import REMOTE_USER |
|
293 | from paste.httpheaders import REMOTE_USER | |
294 | username = REMOTE_USER(environ) |
|
294 | username = REMOTE_USER(environ) | |
295 | log.debug('extracted REMOTE_USER:%s' % (username)) |
|
295 | log.debug('extracted REMOTE_USER:%s' % (username)) | |
296 |
|
296 | |||
297 | if not username and str2bool(config.get('proxypass_auth_enabled', False)): |
|
297 | if not username and str2bool(config.get('proxypass_auth_enabled', False)): | |
298 | username = environ.get('HTTP_X_FORWARDED_USER') |
|
298 | username = environ.get('HTTP_X_FORWARDED_USER') | |
299 | log.debug('extracted HTTP_X_FORWARDED_USER:%s' % (username)) |
|
299 | log.debug('extracted HTTP_X_FORWARDED_USER:%s' % (username)) | |
300 |
|
300 | |||
301 | if username and clean_username: |
|
301 | if username and clean_username: | |
302 | # Removing realm and domain from username |
|
302 | # Removing realm and domain from username | |
303 | username = username.partition('@')[0] |
|
303 | username = username.partition('@')[0] | |
304 | username = username.rpartition('\\')[2] |
|
304 | username = username.rpartition('\\')[2] | |
305 | log.debug('Received username %s from container' % username) |
|
305 | log.debug('Received username %s from container' % username) | |
306 |
|
306 | |||
307 | return username |
|
307 | return username | |
308 |
|
308 | |||
309 |
|
309 | |||
310 | class CookieStoreWrapper(object): |
|
310 | class CookieStoreWrapper(object): | |
311 |
|
311 | |||
312 | def __init__(self, cookie_store): |
|
312 | def __init__(self, cookie_store): | |
313 | self.cookie_store = cookie_store |
|
313 | self.cookie_store = cookie_store | |
314 |
|
314 | |||
315 | def __repr__(self): |
|
315 | def __repr__(self): | |
316 | return 'CookieStore<%s>' % (self.cookie_store) |
|
316 | return 'CookieStore<%s>' % (self.cookie_store) | |
317 |
|
317 | |||
318 | def get(self, key, other=None): |
|
318 | def get(self, key, other=None): | |
319 | if isinstance(self.cookie_store, dict): |
|
319 | if isinstance(self.cookie_store, dict): | |
320 | return self.cookie_store.get(key, other) |
|
320 | return self.cookie_store.get(key, other) | |
321 | elif isinstance(self.cookie_store, AuthUser): |
|
321 | elif isinstance(self.cookie_store, AuthUser): | |
322 | return self.cookie_store.__dict__.get(key, other) |
|
322 | return self.cookie_store.__dict__.get(key, other) | |
323 |
|
323 | |||
324 |
|
324 | |||
325 | class AuthUser(object): |
|
325 | class AuthUser(object): | |
326 | """ |
|
326 | """ | |
327 | A simple object that handles all attributes of user in RhodeCode |
|
327 | A simple object that handles all attributes of user in RhodeCode | |
328 |
|
328 | |||
329 | It does lookup based on API key,given user, or user present in session |
|
329 | It does lookup based on API key,given user, or user present in session | |
330 | Then it fills all required information for such user. It also checks if |
|
330 | Then it fills all required information for such user. It also checks if | |
331 | anonymous access is enabled and if so, it returns default user as logged |
|
331 | anonymous access is enabled and if so, it returns default user as logged | |
332 | in |
|
332 | in | |
333 | """ |
|
333 | """ | |
334 |
|
334 | |||
335 | def __init__(self, user_id=None, api_key=None, username=None, ip_addr=None): |
|
335 | def __init__(self, user_id=None, api_key=None, username=None, ip_addr=None): | |
336 |
|
336 | |||
337 | self.user_id = user_id |
|
337 | self.user_id = user_id | |
338 | self.api_key = None |
|
338 | self.api_key = None | |
339 | self.username = username |
|
339 | self.username = username | |
340 | self.ip_addr = ip_addr |
|
340 | self.ip_addr = ip_addr | |
341 |
|
341 | |||
342 | self.name = '' |
|
342 | self.name = '' | |
343 | self.lastname = '' |
|
343 | self.lastname = '' | |
344 | self.email = '' |
|
344 | self.email = '' | |
345 | self.is_authenticated = False |
|
345 | self.is_authenticated = False | |
346 | self.admin = False |
|
346 | self.admin = False | |
347 | self.inherit_default_permissions = False |
|
347 | self.inherit_default_permissions = False | |
348 | self.permissions = {} |
|
348 | self.permissions = {} | |
349 | self._api_key = api_key |
|
349 | self._api_key = api_key | |
350 | self.propagate_data() |
|
350 | self.propagate_data() | |
351 | self._instance = None |
|
351 | self._instance = None | |
352 |
|
352 | |||
353 | def propagate_data(self): |
|
353 | def propagate_data(self): | |
354 | user_model = UserModel() |
|
354 | user_model = UserModel() | |
355 | self.anonymous_user = User.get_by_username('default', cache=True) |
|
355 | self.anonymous_user = User.get_by_username('default', cache=True) | |
356 | is_user_loaded = False |
|
356 | is_user_loaded = False | |
357 |
|
357 | |||
358 | # try go get user by api key |
|
358 | # try go get user by api key | |
359 | if self._api_key and self._api_key != self.anonymous_user.api_key: |
|
359 | if self._api_key and self._api_key != self.anonymous_user.api_key: | |
360 | log.debug('Auth User lookup by API KEY %s' % self._api_key) |
|
360 | log.debug('Auth User lookup by API KEY %s' % self._api_key) | |
361 | is_user_loaded = user_model.fill_data(self, api_key=self._api_key) |
|
361 | is_user_loaded = user_model.fill_data(self, api_key=self._api_key) | |
362 | # lookup by userid |
|
362 | # lookup by userid | |
363 | elif (self.user_id is not None and |
|
363 | elif (self.user_id is not None and | |
364 | self.user_id != self.anonymous_user.user_id): |
|
364 | self.user_id != self.anonymous_user.user_id): | |
365 | log.debug('Auth User lookup by USER ID %s' % self.user_id) |
|
365 | log.debug('Auth User lookup by USER ID %s' % self.user_id) | |
366 | is_user_loaded = user_model.fill_data(self, user_id=self.user_id) |
|
366 | is_user_loaded = user_model.fill_data(self, user_id=self.user_id) | |
367 | # lookup by username |
|
367 | # lookup by username | |
368 | elif self.username and \ |
|
368 | elif self.username and \ | |
369 | str2bool(config.get('container_auth_enabled', False)): |
|
369 | str2bool(config.get('container_auth_enabled', False)): | |
370 |
|
370 | |||
371 | log.debug('Auth User lookup by USER NAME %s' % self.username) |
|
371 | log.debug('Auth User lookup by USER NAME %s' % self.username) | |
372 | dbuser = login_container_auth(self.username) |
|
372 | dbuser = login_container_auth(self.username) | |
373 | if dbuser is not None: |
|
373 | if dbuser is not None: | |
374 | log.debug('filling all attributes to object') |
|
374 | log.debug('filling all attributes to object') | |
375 | for k, v in dbuser.get_dict().items(): |
|
375 | for k, v in dbuser.get_dict().items(): | |
376 | setattr(self, k, v) |
|
376 | setattr(self, k, v) | |
377 | self.set_authenticated() |
|
377 | self.set_authenticated() | |
378 | is_user_loaded = True |
|
378 | is_user_loaded = True | |
379 | else: |
|
379 | else: | |
380 | log.debug('No data in %s that could been used to log in' % self) |
|
380 | log.debug('No data in %s that could been used to log in' % self) | |
381 |
|
381 | |||
382 | if not is_user_loaded: |
|
382 | if not is_user_loaded: | |
383 | # if we cannot authenticate user try anonymous |
|
383 | # if we cannot authenticate user try anonymous | |
384 | if self.anonymous_user.active is True: |
|
384 | if self.anonymous_user.active is True: | |
385 | user_model.fill_data(self, user_id=self.anonymous_user.user_id) |
|
385 | user_model.fill_data(self, user_id=self.anonymous_user.user_id) | |
386 | # then we set this user is logged in |
|
386 | # then we set this user is logged in | |
387 | self.is_authenticated = True |
|
387 | self.is_authenticated = True | |
388 | else: |
|
388 | else: | |
389 | self.user_id = None |
|
389 | self.user_id = None | |
390 | self.username = None |
|
390 | self.username = None | |
391 | self.is_authenticated = False |
|
391 | self.is_authenticated = False | |
392 |
|
392 | |||
393 | if not self.username: |
|
393 | if not self.username: | |
394 | self.username = 'None' |
|
394 | self.username = 'None' | |
395 |
|
395 | |||
396 | log.debug('Auth User is now %s' % self) |
|
396 | log.debug('Auth User is now %s' % self) | |
397 | user_model.fill_perms(self) |
|
397 | user_model.fill_perms(self) | |
398 |
|
398 | |||
399 | @property |
|
399 | @property | |
400 | def is_admin(self): |
|
400 | def is_admin(self): | |
401 | return self.admin |
|
401 | return self.admin | |
402 |
|
402 | |||
403 | @property |
|
403 | @property | |
404 | def repos_admin(self): |
|
404 | def repos_admin(self): | |
405 | """ |
|
405 | """ | |
406 | Returns list of repositories you're an admin of |
|
406 | Returns list of repositories you're an admin of | |
407 | """ |
|
407 | """ | |
408 | return [x[0] for x in self.permissions['repositories'].iteritems() |
|
408 | return [x[0] for x in self.permissions['repositories'].iteritems() | |
409 | if x[1] == 'repository.admin'] |
|
409 | if x[1] == 'repository.admin'] | |
410 |
|
410 | |||
411 | @property |
|
411 | @property | |
412 | def groups_admin(self): |
|
412 | def groups_admin(self): | |
413 | """ |
|
413 | """ | |
414 |
Returns list of repositor |
|
414 | Returns list of repository groups you're an admin of | |
415 | """ |
|
415 | """ | |
416 | return [x[0] for x in self.permissions['repositories_groups'].iteritems() |
|
416 | return [x[0] for x in self.permissions['repositories_groups'].iteritems() | |
417 | if x[1] == 'group.admin'] |
|
417 | if x[1] == 'group.admin'] | |
418 |
|
418 | |||
419 | @property |
|
419 | @property | |
420 | def ip_allowed(self): |
|
420 | def ip_allowed(self): | |
421 | """ |
|
421 | """ | |
422 | Checks if ip_addr used in constructor is allowed from defined list of |
|
422 | Checks if ip_addr used in constructor is allowed from defined list of | |
423 | allowed ip_addresses for user |
|
423 | allowed ip_addresses for user | |
424 |
|
424 | |||
425 | :returns: boolean, True if ip is in allowed ip range |
|
425 | :returns: boolean, True if ip is in allowed ip range | |
426 | """ |
|
426 | """ | |
427 | #check IP |
|
427 | #check IP | |
428 | allowed_ips = AuthUser.get_allowed_ips(self.user_id, cache=True) |
|
428 | allowed_ips = AuthUser.get_allowed_ips(self.user_id, cache=True) | |
429 | if check_ip_access(source_ip=self.ip_addr, allowed_ips=allowed_ips): |
|
429 | if check_ip_access(source_ip=self.ip_addr, allowed_ips=allowed_ips): | |
430 | log.debug('IP:%s is in range of %s' % (self.ip_addr, allowed_ips)) |
|
430 | log.debug('IP:%s is in range of %s' % (self.ip_addr, allowed_ips)) | |
431 | return True |
|
431 | return True | |
432 | else: |
|
432 | else: | |
433 | log.info('Access for IP:%s forbidden, ' |
|
433 | log.info('Access for IP:%s forbidden, ' | |
434 | 'not in %s' % (self.ip_addr, allowed_ips)) |
|
434 | 'not in %s' % (self.ip_addr, allowed_ips)) | |
435 | return False |
|
435 | return False | |
436 |
|
436 | |||
437 | def __repr__(self): |
|
437 | def __repr__(self): | |
438 | return "<AuthUser('id:%s:%s|%s')>" % (self.user_id, self.username, |
|
438 | return "<AuthUser('id:%s:%s|%s')>" % (self.user_id, self.username, | |
439 | self.is_authenticated) |
|
439 | self.is_authenticated) | |
440 |
|
440 | |||
441 | def set_authenticated(self, authenticated=True): |
|
441 | def set_authenticated(self, authenticated=True): | |
442 | if self.user_id != self.anonymous_user.user_id: |
|
442 | if self.user_id != self.anonymous_user.user_id: | |
443 | self.is_authenticated = authenticated |
|
443 | self.is_authenticated = authenticated | |
444 |
|
444 | |||
445 | def get_cookie_store(self): |
|
445 | def get_cookie_store(self): | |
446 | return {'username': self.username, |
|
446 | return {'username': self.username, | |
447 | 'user_id': self.user_id, |
|
447 | 'user_id': self.user_id, | |
448 | 'is_authenticated': self.is_authenticated} |
|
448 | 'is_authenticated': self.is_authenticated} | |
449 |
|
449 | |||
450 | @classmethod |
|
450 | @classmethod | |
451 | def from_cookie_store(cls, cookie_store): |
|
451 | def from_cookie_store(cls, cookie_store): | |
452 | """ |
|
452 | """ | |
453 | Creates AuthUser from a cookie store |
|
453 | Creates AuthUser from a cookie store | |
454 |
|
454 | |||
455 | :param cls: |
|
455 | :param cls: | |
456 | :param cookie_store: |
|
456 | :param cookie_store: | |
457 | """ |
|
457 | """ | |
458 | user_id = cookie_store.get('user_id') |
|
458 | user_id = cookie_store.get('user_id') | |
459 | username = cookie_store.get('username') |
|
459 | username = cookie_store.get('username') | |
460 | api_key = cookie_store.get('api_key') |
|
460 | api_key = cookie_store.get('api_key') | |
461 | return AuthUser(user_id, api_key, username) |
|
461 | return AuthUser(user_id, api_key, username) | |
462 |
|
462 | |||
463 | @classmethod |
|
463 | @classmethod | |
464 | def get_allowed_ips(cls, user_id, cache=False): |
|
464 | def get_allowed_ips(cls, user_id, cache=False): | |
465 | _set = set() |
|
465 | _set = set() | |
466 | user_ips = UserIpMap.query().filter(UserIpMap.user_id == user_id) |
|
466 | user_ips = UserIpMap.query().filter(UserIpMap.user_id == user_id) | |
467 | if cache: |
|
467 | if cache: | |
468 | user_ips = user_ips.options(FromCache("sql_cache_short", |
|
468 | user_ips = user_ips.options(FromCache("sql_cache_short", | |
469 | "get_user_ips_%s" % user_id)) |
|
469 | "get_user_ips_%s" % user_id)) | |
470 | for ip in user_ips: |
|
470 | for ip in user_ips: | |
471 | try: |
|
471 | try: | |
472 | _set.add(ip.ip_addr) |
|
472 | _set.add(ip.ip_addr) | |
473 | except ObjectDeletedError: |
|
473 | except ObjectDeletedError: | |
474 | # since we use heavy caching sometimes it happens that we get |
|
474 | # since we use heavy caching sometimes it happens that we get | |
475 | # deleted objects here, we just skip them |
|
475 | # deleted objects here, we just skip them | |
476 | pass |
|
476 | pass | |
477 | return _set or set(['0.0.0.0/0', '::/0']) |
|
477 | return _set or set(['0.0.0.0/0', '::/0']) | |
478 |
|
478 | |||
479 |
|
479 | |||
480 | def set_available_permissions(config): |
|
480 | def set_available_permissions(config): | |
481 | """ |
|
481 | """ | |
482 | This function will propagate pylons globals with all available defined |
|
482 | This function will propagate pylons globals with all available defined | |
483 | permission given in db. We don't want to check each time from db for new |
|
483 | permission given in db. We don't want to check each time from db for new | |
484 | permissions since adding a new permission also requires application restart |
|
484 | permissions since adding a new permission also requires application restart | |
485 | ie. to decorate new views with the newly created permission |
|
485 | ie. to decorate new views with the newly created permission | |
486 |
|
486 | |||
487 | :param config: current pylons config instance |
|
487 | :param config: current pylons config instance | |
488 |
|
488 | |||
489 | """ |
|
489 | """ | |
490 | log.info('getting information about all available permissions') |
|
490 | log.info('getting information about all available permissions') | |
491 | try: |
|
491 | try: | |
492 | sa = meta.Session |
|
492 | sa = meta.Session | |
493 | all_perms = sa.query(Permission).all() |
|
493 | all_perms = sa.query(Permission).all() | |
494 | except Exception: |
|
494 | except Exception: | |
495 | pass |
|
495 | pass | |
496 | finally: |
|
496 | finally: | |
497 | meta.Session.remove() |
|
497 | meta.Session.remove() | |
498 |
|
498 | |||
499 | config['available_permissions'] = [x.permission_name for x in all_perms] |
|
499 | config['available_permissions'] = [x.permission_name for x in all_perms] | |
500 |
|
500 | |||
501 |
|
501 | |||
502 | #============================================================================== |
|
502 | #============================================================================== | |
503 | # CHECK DECORATORS |
|
503 | # CHECK DECORATORS | |
504 | #============================================================================== |
|
504 | #============================================================================== | |
505 | class LoginRequired(object): |
|
505 | class LoginRequired(object): | |
506 | """ |
|
506 | """ | |
507 | Must be logged in to execute this function else |
|
507 | Must be logged in to execute this function else | |
508 | redirect to login page |
|
508 | redirect to login page | |
509 |
|
509 | |||
510 | :param api_access: if enabled this checks only for valid auth token |
|
510 | :param api_access: if enabled this checks only for valid auth token | |
511 | and grants access based on valid token |
|
511 | and grants access based on valid token | |
512 | """ |
|
512 | """ | |
513 |
|
513 | |||
514 | def __init__(self, api_access=False): |
|
514 | def __init__(self, api_access=False): | |
515 | self.api_access = api_access |
|
515 | self.api_access = api_access | |
516 |
|
516 | |||
517 | def __call__(self, func): |
|
517 | def __call__(self, func): | |
518 | return decorator(self.__wrapper, func) |
|
518 | return decorator(self.__wrapper, func) | |
519 |
|
519 | |||
520 | def __wrapper(self, func, *fargs, **fkwargs): |
|
520 | def __wrapper(self, func, *fargs, **fkwargs): | |
521 | cls = fargs[0] |
|
521 | cls = fargs[0] | |
522 | user = cls.rhodecode_user |
|
522 | user = cls.rhodecode_user | |
523 | loc = "%s:%s" % (cls.__class__.__name__, func.__name__) |
|
523 | loc = "%s:%s" % (cls.__class__.__name__, func.__name__) | |
524 |
|
524 | |||
525 | #check IP |
|
525 | #check IP | |
526 | ip_access_ok = True |
|
526 | ip_access_ok = True | |
527 | if not user.ip_allowed: |
|
527 | if not user.ip_allowed: | |
528 | from rhodecode.lib import helpers as h |
|
528 | from rhodecode.lib import helpers as h | |
529 | h.flash(h.literal(_('IP %s not allowed' % (user.ip_addr))), |
|
529 | h.flash(h.literal(_('IP %s not allowed' % (user.ip_addr))), | |
530 | category='warning') |
|
530 | category='warning') | |
531 | ip_access_ok = False |
|
531 | ip_access_ok = False | |
532 |
|
532 | |||
533 | api_access_ok = False |
|
533 | api_access_ok = False | |
534 | if self.api_access: |
|
534 | if self.api_access: | |
535 | log.debug('Checking API KEY access for %s' % cls) |
|
535 | log.debug('Checking API KEY access for %s' % cls) | |
536 | if user.api_key == request.GET.get('api_key'): |
|
536 | if user.api_key == request.GET.get('api_key'): | |
537 | api_access_ok = True |
|
537 | api_access_ok = True | |
538 | else: |
|
538 | else: | |
539 | log.debug("API KEY token not valid") |
|
539 | log.debug("API KEY token not valid") | |
540 |
|
540 | |||
541 | log.debug('Checking if %s is authenticated @ %s' % (user.username, loc)) |
|
541 | log.debug('Checking if %s is authenticated @ %s' % (user.username, loc)) | |
542 | if (user.is_authenticated or api_access_ok) and ip_access_ok: |
|
542 | if (user.is_authenticated or api_access_ok) and ip_access_ok: | |
543 | reason = 'RegularAuth' if user.is_authenticated else 'APIAuth' |
|
543 | reason = 'RegularAuth' if user.is_authenticated else 'APIAuth' | |
544 | log.info('user %s is authenticated and granted access to %s ' |
|
544 | log.info('user %s is authenticated and granted access to %s ' | |
545 | 'using %s' % (user.username, loc, reason) |
|
545 | 'using %s' % (user.username, loc, reason) | |
546 | ) |
|
546 | ) | |
547 | return func(*fargs, **fkwargs) |
|
547 | return func(*fargs, **fkwargs) | |
548 | else: |
|
548 | else: | |
549 | log.warn('user %s NOT authenticated on func: %s' % ( |
|
549 | log.warn('user %s NOT authenticated on func: %s' % ( | |
550 | user, loc) |
|
550 | user, loc) | |
551 | ) |
|
551 | ) | |
552 | p = url.current() |
|
552 | p = url.current() | |
553 |
|
553 | |||
554 | log.debug('redirecting to login page with %s' % p) |
|
554 | log.debug('redirecting to login page with %s' % p) | |
555 | return redirect(url('login_home', came_from=p)) |
|
555 | return redirect(url('login_home', came_from=p)) | |
556 |
|
556 | |||
557 |
|
557 | |||
558 | class NotAnonymous(object): |
|
558 | class NotAnonymous(object): | |
559 | """ |
|
559 | """ | |
560 | Must be logged in to execute this function else |
|
560 | Must be logged in to execute this function else | |
561 | redirect to login page""" |
|
561 | redirect to login page""" | |
562 |
|
562 | |||
563 | def __call__(self, func): |
|
563 | def __call__(self, func): | |
564 | return decorator(self.__wrapper, func) |
|
564 | return decorator(self.__wrapper, func) | |
565 |
|
565 | |||
566 | def __wrapper(self, func, *fargs, **fkwargs): |
|
566 | def __wrapper(self, func, *fargs, **fkwargs): | |
567 | cls = fargs[0] |
|
567 | cls = fargs[0] | |
568 | self.user = cls.rhodecode_user |
|
568 | self.user = cls.rhodecode_user | |
569 |
|
569 | |||
570 | log.debug('Checking if user is not anonymous @%s' % cls) |
|
570 | log.debug('Checking if user is not anonymous @%s' % cls) | |
571 |
|
571 | |||
572 | anonymous = self.user.username == 'default' |
|
572 | anonymous = self.user.username == 'default' | |
573 |
|
573 | |||
574 | if anonymous: |
|
574 | if anonymous: | |
575 | p = url.current() |
|
575 | p = url.current() | |
576 |
|
576 | |||
577 | import rhodecode.lib.helpers as h |
|
577 | import rhodecode.lib.helpers as h | |
578 | h.flash(_('You need to be a registered user to ' |
|
578 | h.flash(_('You need to be a registered user to ' | |
579 | 'perform this action'), |
|
579 | 'perform this action'), | |
580 | category='warning') |
|
580 | category='warning') | |
581 | return redirect(url('login_home', came_from=p)) |
|
581 | return redirect(url('login_home', came_from=p)) | |
582 | else: |
|
582 | else: | |
583 | return func(*fargs, **fkwargs) |
|
583 | return func(*fargs, **fkwargs) | |
584 |
|
584 | |||
585 |
|
585 | |||
586 | class PermsDecorator(object): |
|
586 | class PermsDecorator(object): | |
587 | """Base class for controller decorators""" |
|
587 | """Base class for controller decorators""" | |
588 |
|
588 | |||
589 | def __init__(self, *required_perms): |
|
589 | def __init__(self, *required_perms): | |
590 | available_perms = config['available_permissions'] |
|
590 | available_perms = config['available_permissions'] | |
591 | for perm in required_perms: |
|
591 | for perm in required_perms: | |
592 | if perm not in available_perms: |
|
592 | if perm not in available_perms: | |
593 | raise Exception("'%s' permission is not defined" % perm) |
|
593 | raise Exception("'%s' permission is not defined" % perm) | |
594 | self.required_perms = set(required_perms) |
|
594 | self.required_perms = set(required_perms) | |
595 | self.user_perms = None |
|
595 | self.user_perms = None | |
596 |
|
596 | |||
597 | def __call__(self, func): |
|
597 | def __call__(self, func): | |
598 | return decorator(self.__wrapper, func) |
|
598 | return decorator(self.__wrapper, func) | |
599 |
|
599 | |||
600 | def __wrapper(self, func, *fargs, **fkwargs): |
|
600 | def __wrapper(self, func, *fargs, **fkwargs): | |
601 | cls = fargs[0] |
|
601 | cls = fargs[0] | |
602 | self.user = cls.rhodecode_user |
|
602 | self.user = cls.rhodecode_user | |
603 | self.user_perms = self.user.permissions |
|
603 | self.user_perms = self.user.permissions | |
604 | log.debug('checking %s permissions %s for %s %s', |
|
604 | log.debug('checking %s permissions %s for %s %s', | |
605 | self.__class__.__name__, self.required_perms, cls, self.user) |
|
605 | self.__class__.__name__, self.required_perms, cls, self.user) | |
606 |
|
606 | |||
607 | if self.check_permissions(): |
|
607 | if self.check_permissions(): | |
608 | log.debug('Permission granted for %s %s' % (cls, self.user)) |
|
608 | log.debug('Permission granted for %s %s' % (cls, self.user)) | |
609 | return func(*fargs, **fkwargs) |
|
609 | return func(*fargs, **fkwargs) | |
610 |
|
610 | |||
611 | else: |
|
611 | else: | |
612 | log.debug('Permission denied for %s %s' % (cls, self.user)) |
|
612 | log.debug('Permission denied for %s %s' % (cls, self.user)) | |
613 | anonymous = self.user.username == 'default' |
|
613 | anonymous = self.user.username == 'default' | |
614 |
|
614 | |||
615 | if anonymous: |
|
615 | if anonymous: | |
616 | p = url.current() |
|
616 | p = url.current() | |
617 |
|
617 | |||
618 | import rhodecode.lib.helpers as h |
|
618 | import rhodecode.lib.helpers as h | |
619 | h.flash(_('You need to be a signed in to ' |
|
619 | h.flash(_('You need to be a signed in to ' | |
620 | 'view this page'), |
|
620 | 'view this page'), | |
621 | category='warning') |
|
621 | category='warning') | |
622 | return redirect(url('login_home', came_from=p)) |
|
622 | return redirect(url('login_home', came_from=p)) | |
623 |
|
623 | |||
624 | else: |
|
624 | else: | |
625 | # redirect with forbidden ret code |
|
625 | # redirect with forbidden ret code | |
626 | return abort(403) |
|
626 | return abort(403) | |
627 |
|
627 | |||
628 | def check_permissions(self): |
|
628 | def check_permissions(self): | |
629 | """Dummy function for overriding""" |
|
629 | """Dummy function for overriding""" | |
630 | raise Exception('You have to write this function in child class') |
|
630 | raise Exception('You have to write this function in child class') | |
631 |
|
631 | |||
632 |
|
632 | |||
633 | class HasPermissionAllDecorator(PermsDecorator): |
|
633 | class HasPermissionAllDecorator(PermsDecorator): | |
634 | """ |
|
634 | """ | |
635 | Checks for access permission for all given predicates. All of them |
|
635 | Checks for access permission for all given predicates. All of them | |
636 | have to be meet in order to fulfill the request |
|
636 | have to be meet in order to fulfill the request | |
637 | """ |
|
637 | """ | |
638 |
|
638 | |||
639 | def check_permissions(self): |
|
639 | def check_permissions(self): | |
640 | if self.required_perms.issubset(self.user_perms.get('global')): |
|
640 | if self.required_perms.issubset(self.user_perms.get('global')): | |
641 | return True |
|
641 | return True | |
642 | return False |
|
642 | return False | |
643 |
|
643 | |||
644 |
|
644 | |||
645 | class HasPermissionAnyDecorator(PermsDecorator): |
|
645 | class HasPermissionAnyDecorator(PermsDecorator): | |
646 | """ |
|
646 | """ | |
647 | Checks for access permission for any of given predicates. In order to |
|
647 | Checks for access permission for any of given predicates. In order to | |
648 | fulfill the request any of predicates must be meet |
|
648 | fulfill the request any of predicates must be meet | |
649 | """ |
|
649 | """ | |
650 |
|
650 | |||
651 | def check_permissions(self): |
|
651 | def check_permissions(self): | |
652 | if self.required_perms.intersection(self.user_perms.get('global')): |
|
652 | if self.required_perms.intersection(self.user_perms.get('global')): | |
653 | return True |
|
653 | return True | |
654 | return False |
|
654 | return False | |
655 |
|
655 | |||
656 |
|
656 | |||
657 | class HasRepoPermissionAllDecorator(PermsDecorator): |
|
657 | class HasRepoPermissionAllDecorator(PermsDecorator): | |
658 | """ |
|
658 | """ | |
659 | Checks for access permission for all given predicates for specific |
|
659 | Checks for access permission for all given predicates for specific | |
660 | repository. All of them have to be meet in order to fulfill the request |
|
660 | repository. All of them have to be meet in order to fulfill the request | |
661 | """ |
|
661 | """ | |
662 |
|
662 | |||
663 | def check_permissions(self): |
|
663 | def check_permissions(self): | |
664 | repo_name = get_repo_slug(request) |
|
664 | repo_name = get_repo_slug(request) | |
665 | try: |
|
665 | try: | |
666 | user_perms = set([self.user_perms['repositories'][repo_name]]) |
|
666 | user_perms = set([self.user_perms['repositories'][repo_name]]) | |
667 | except KeyError: |
|
667 | except KeyError: | |
668 | return False |
|
668 | return False | |
669 | if self.required_perms.issubset(user_perms): |
|
669 | if self.required_perms.issubset(user_perms): | |
670 | return True |
|
670 | return True | |
671 | return False |
|
671 | return False | |
672 |
|
672 | |||
673 |
|
673 | |||
674 | class HasRepoPermissionAnyDecorator(PermsDecorator): |
|
674 | class HasRepoPermissionAnyDecorator(PermsDecorator): | |
675 | """ |
|
675 | """ | |
676 | Checks for access permission for any of given predicates for specific |
|
676 | Checks for access permission for any of given predicates for specific | |
677 | repository. In order to fulfill the request any of predicates must be meet |
|
677 | repository. In order to fulfill the request any of predicates must be meet | |
678 | """ |
|
678 | """ | |
679 |
|
679 | |||
680 | def check_permissions(self): |
|
680 | def check_permissions(self): | |
681 | repo_name = get_repo_slug(request) |
|
681 | repo_name = get_repo_slug(request) | |
682 | try: |
|
682 | try: | |
683 | user_perms = set([self.user_perms['repositories'][repo_name]]) |
|
683 | user_perms = set([self.user_perms['repositories'][repo_name]]) | |
684 | except KeyError: |
|
684 | except KeyError: | |
685 | return False |
|
685 | return False | |
686 |
|
686 | |||
687 | if self.required_perms.intersection(user_perms): |
|
687 | if self.required_perms.intersection(user_perms): | |
688 | return True |
|
688 | return True | |
689 | return False |
|
689 | return False | |
690 |
|
690 | |||
691 |
|
691 | |||
692 | class HasReposGroupPermissionAllDecorator(PermsDecorator): |
|
692 | class HasReposGroupPermissionAllDecorator(PermsDecorator): | |
693 | """ |
|
693 | """ | |
694 | Checks for access permission for all given predicates for specific |
|
694 | Checks for access permission for all given predicates for specific | |
695 | repository. All of them have to be meet in order to fulfill the request |
|
695 | repository. All of them have to be meet in order to fulfill the request | |
696 | """ |
|
696 | """ | |
697 |
|
697 | |||
698 | def check_permissions(self): |
|
698 | def check_permissions(self): | |
699 | group_name = get_repos_group_slug(request) |
|
699 | group_name = get_repos_group_slug(request) | |
700 | try: |
|
700 | try: | |
701 | user_perms = set([self.user_perms['repositories_groups'][group_name]]) |
|
701 | user_perms = set([self.user_perms['repositories_groups'][group_name]]) | |
702 | except KeyError: |
|
702 | except KeyError: | |
703 | return False |
|
703 | return False | |
704 |
|
704 | |||
705 | if self.required_perms.issubset(user_perms): |
|
705 | if self.required_perms.issubset(user_perms): | |
706 | return True |
|
706 | return True | |
707 | return False |
|
707 | return False | |
708 |
|
708 | |||
709 |
|
709 | |||
710 | class HasReposGroupPermissionAnyDecorator(PermsDecorator): |
|
710 | class HasReposGroupPermissionAnyDecorator(PermsDecorator): | |
711 | """ |
|
711 | """ | |
712 | Checks for access permission for any of given predicates for specific |
|
712 | Checks for access permission for any of given predicates for specific | |
713 | repository. In order to fulfill the request any of predicates must be meet |
|
713 | repository. In order to fulfill the request any of predicates must be meet | |
714 | """ |
|
714 | """ | |
715 |
|
715 | |||
716 | def check_permissions(self): |
|
716 | def check_permissions(self): | |
717 | group_name = get_repos_group_slug(request) |
|
717 | group_name = get_repos_group_slug(request) | |
718 | try: |
|
718 | try: | |
719 | user_perms = set([self.user_perms['repositories_groups'][group_name]]) |
|
719 | user_perms = set([self.user_perms['repositories_groups'][group_name]]) | |
720 | except KeyError: |
|
720 | except KeyError: | |
721 | return False |
|
721 | return False | |
722 |
|
722 | |||
723 | if self.required_perms.intersection(user_perms): |
|
723 | if self.required_perms.intersection(user_perms): | |
724 | return True |
|
724 | return True | |
725 | return False |
|
725 | return False | |
726 |
|
726 | |||
727 |
|
727 | |||
728 | #============================================================================== |
|
728 | #============================================================================== | |
729 | # CHECK FUNCTIONS |
|
729 | # CHECK FUNCTIONS | |
730 | #============================================================================== |
|
730 | #============================================================================== | |
731 | class PermsFunction(object): |
|
731 | class PermsFunction(object): | |
732 | """Base function for other check functions""" |
|
732 | """Base function for other check functions""" | |
733 |
|
733 | |||
734 | def __init__(self, *perms): |
|
734 | def __init__(self, *perms): | |
735 | available_perms = config['available_permissions'] |
|
735 | available_perms = config['available_permissions'] | |
736 |
|
736 | |||
737 | for perm in perms: |
|
737 | for perm in perms: | |
738 | if perm not in available_perms: |
|
738 | if perm not in available_perms: | |
739 | raise Exception("'%s' permission is not defined" % perm) |
|
739 | raise Exception("'%s' permission is not defined" % perm) | |
740 | self.required_perms = set(perms) |
|
740 | self.required_perms = set(perms) | |
741 | self.user_perms = None |
|
741 | self.user_perms = None | |
742 | self.repo_name = None |
|
742 | self.repo_name = None | |
743 | self.group_name = None |
|
743 | self.group_name = None | |
744 |
|
744 | |||
745 | def __call__(self, check_location=''): |
|
745 | def __call__(self, check_location=''): | |
746 | #TODO: put user as attribute here |
|
746 | #TODO: put user as attribute here | |
747 | user = request.user |
|
747 | user = request.user | |
748 | cls_name = self.__class__.__name__ |
|
748 | cls_name = self.__class__.__name__ | |
749 | check_scope = { |
|
749 | check_scope = { | |
750 | 'HasPermissionAll': '', |
|
750 | 'HasPermissionAll': '', | |
751 | 'HasPermissionAny': '', |
|
751 | 'HasPermissionAny': '', | |
752 | 'HasRepoPermissionAll': 'repo:%s' % self.repo_name, |
|
752 | 'HasRepoPermissionAll': 'repo:%s' % self.repo_name, | |
753 | 'HasRepoPermissionAny': 'repo:%s' % self.repo_name, |
|
753 | 'HasRepoPermissionAny': 'repo:%s' % self.repo_name, | |
754 | 'HasReposGroupPermissionAll': 'group:%s' % self.group_name, |
|
754 | 'HasReposGroupPermissionAll': 'group:%s' % self.group_name, | |
755 | 'HasReposGroupPermissionAny': 'group:%s' % self.group_name, |
|
755 | 'HasReposGroupPermissionAny': 'group:%s' % self.group_name, | |
756 | }.get(cls_name, '?') |
|
756 | }.get(cls_name, '?') | |
757 | log.debug('checking cls:%s %s usr:%s %s @ %s', cls_name, |
|
757 | log.debug('checking cls:%s %s usr:%s %s @ %s', cls_name, | |
758 | self.required_perms, user, check_scope, |
|
758 | self.required_perms, user, check_scope, | |
759 | check_location or 'unspecified location') |
|
759 | check_location or 'unspecified location') | |
760 | if not user: |
|
760 | if not user: | |
761 | log.debug('Empty request user') |
|
761 | log.debug('Empty request user') | |
762 | return False |
|
762 | return False | |
763 | self.user_perms = user.permissions |
|
763 | self.user_perms = user.permissions | |
764 | if self.check_permissions(): |
|
764 | if self.check_permissions(): | |
765 | log.debug('Permission to %s granted for user: %s @ %s', self.repo_name, user, |
|
765 | log.debug('Permission to %s granted for user: %s @ %s', self.repo_name, user, | |
766 | check_location or 'unspecified location') |
|
766 | check_location or 'unspecified location') | |
767 | return True |
|
767 | return True | |
768 |
|
768 | |||
769 | else: |
|
769 | else: | |
770 | log.debug('Permission to %s denied for user: %s @ %s', self.repo_name, user, |
|
770 | log.debug('Permission to %s denied for user: %s @ %s', self.repo_name, user, | |
771 | check_location or 'unspecified location') |
|
771 | check_location or 'unspecified location') | |
772 | return False |
|
772 | return False | |
773 |
|
773 | |||
774 | def check_permissions(self): |
|
774 | def check_permissions(self): | |
775 | """Dummy function for overriding""" |
|
775 | """Dummy function for overriding""" | |
776 | raise Exception('You have to write this function in child class') |
|
776 | raise Exception('You have to write this function in child class') | |
777 |
|
777 | |||
778 |
|
778 | |||
779 | class HasPermissionAll(PermsFunction): |
|
779 | class HasPermissionAll(PermsFunction): | |
780 | def check_permissions(self): |
|
780 | def check_permissions(self): | |
781 | if self.required_perms.issubset(self.user_perms.get('global')): |
|
781 | if self.required_perms.issubset(self.user_perms.get('global')): | |
782 | return True |
|
782 | return True | |
783 | return False |
|
783 | return False | |
784 |
|
784 | |||
785 |
|
785 | |||
786 | class HasPermissionAny(PermsFunction): |
|
786 | class HasPermissionAny(PermsFunction): | |
787 | def check_permissions(self): |
|
787 | def check_permissions(self): | |
788 | if self.required_perms.intersection(self.user_perms.get('global')): |
|
788 | if self.required_perms.intersection(self.user_perms.get('global')): | |
789 | return True |
|
789 | return True | |
790 | return False |
|
790 | return False | |
791 |
|
791 | |||
792 |
|
792 | |||
793 | class HasRepoPermissionAll(PermsFunction): |
|
793 | class HasRepoPermissionAll(PermsFunction): | |
794 | def __call__(self, repo_name=None, check_location=''): |
|
794 | def __call__(self, repo_name=None, check_location=''): | |
795 | self.repo_name = repo_name |
|
795 | self.repo_name = repo_name | |
796 | return super(HasRepoPermissionAll, self).__call__(check_location) |
|
796 | return super(HasRepoPermissionAll, self).__call__(check_location) | |
797 |
|
797 | |||
798 | def check_permissions(self): |
|
798 | def check_permissions(self): | |
799 | if not self.repo_name: |
|
799 | if not self.repo_name: | |
800 | self.repo_name = get_repo_slug(request) |
|
800 | self.repo_name = get_repo_slug(request) | |
801 |
|
801 | |||
802 | try: |
|
802 | try: | |
803 | self._user_perms = set( |
|
803 | self._user_perms = set( | |
804 | [self.user_perms['repositories'][self.repo_name]] |
|
804 | [self.user_perms['repositories'][self.repo_name]] | |
805 | ) |
|
805 | ) | |
806 | except KeyError: |
|
806 | except KeyError: | |
807 | return False |
|
807 | return False | |
808 | if self.required_perms.issubset(self._user_perms): |
|
808 | if self.required_perms.issubset(self._user_perms): | |
809 | return True |
|
809 | return True | |
810 | return False |
|
810 | return False | |
811 |
|
811 | |||
812 |
|
812 | |||
813 | class HasRepoPermissionAny(PermsFunction): |
|
813 | class HasRepoPermissionAny(PermsFunction): | |
814 | def __call__(self, repo_name=None, check_location=''): |
|
814 | def __call__(self, repo_name=None, check_location=''): | |
815 | self.repo_name = repo_name |
|
815 | self.repo_name = repo_name | |
816 | return super(HasRepoPermissionAny, self).__call__(check_location) |
|
816 | return super(HasRepoPermissionAny, self).__call__(check_location) | |
817 |
|
817 | |||
818 | def check_permissions(self): |
|
818 | def check_permissions(self): | |
819 | if not self.repo_name: |
|
819 | if not self.repo_name: | |
820 | self.repo_name = get_repo_slug(request) |
|
820 | self.repo_name = get_repo_slug(request) | |
821 |
|
821 | |||
822 | try: |
|
822 | try: | |
823 | self._user_perms = set( |
|
823 | self._user_perms = set( | |
824 | [self.user_perms['repositories'][self.repo_name]] |
|
824 | [self.user_perms['repositories'][self.repo_name]] | |
825 | ) |
|
825 | ) | |
826 | except KeyError: |
|
826 | except KeyError: | |
827 | return False |
|
827 | return False | |
828 | if self.required_perms.intersection(self._user_perms): |
|
828 | if self.required_perms.intersection(self._user_perms): | |
829 | return True |
|
829 | return True | |
830 | return False |
|
830 | return False | |
831 |
|
831 | |||
832 |
|
832 | |||
833 | class HasReposGroupPermissionAny(PermsFunction): |
|
833 | class HasReposGroupPermissionAny(PermsFunction): | |
834 | def __call__(self, group_name=None, check_location=''): |
|
834 | def __call__(self, group_name=None, check_location=''): | |
835 | self.group_name = group_name |
|
835 | self.group_name = group_name | |
836 | return super(HasReposGroupPermissionAny, self).__call__(check_location) |
|
836 | return super(HasReposGroupPermissionAny, self).__call__(check_location) | |
837 |
|
837 | |||
838 | def check_permissions(self): |
|
838 | def check_permissions(self): | |
839 | try: |
|
839 | try: | |
840 | self._user_perms = set( |
|
840 | self._user_perms = set( | |
841 | [self.user_perms['repositories_groups'][self.group_name]] |
|
841 | [self.user_perms['repositories_groups'][self.group_name]] | |
842 | ) |
|
842 | ) | |
843 | except KeyError: |
|
843 | except KeyError: | |
844 | return False |
|
844 | return False | |
845 | if self.required_perms.intersection(self._user_perms): |
|
845 | if self.required_perms.intersection(self._user_perms): | |
846 | return True |
|
846 | return True | |
847 | return False |
|
847 | return False | |
848 |
|
848 | |||
849 |
|
849 | |||
850 | class HasReposGroupPermissionAll(PermsFunction): |
|
850 | class HasReposGroupPermissionAll(PermsFunction): | |
851 | def __call__(self, group_name=None, check_location=''): |
|
851 | def __call__(self, group_name=None, check_location=''): | |
852 | self.group_name = group_name |
|
852 | self.group_name = group_name | |
853 | return super(HasReposGroupPermissionAll, self).__call__(check_location) |
|
853 | return super(HasReposGroupPermissionAll, self).__call__(check_location) | |
854 |
|
854 | |||
855 | def check_permissions(self): |
|
855 | def check_permissions(self): | |
856 | try: |
|
856 | try: | |
857 | self._user_perms = set( |
|
857 | self._user_perms = set( | |
858 | [self.user_perms['repositories_groups'][self.group_name]] |
|
858 | [self.user_perms['repositories_groups'][self.group_name]] | |
859 | ) |
|
859 | ) | |
860 | except KeyError: |
|
860 | except KeyError: | |
861 | return False |
|
861 | return False | |
862 | if self.required_perms.issubset(self._user_perms): |
|
862 | if self.required_perms.issubset(self._user_perms): | |
863 | return True |
|
863 | return True | |
864 | return False |
|
864 | return False | |
865 |
|
865 | |||
866 |
|
866 | |||
867 | #============================================================================== |
|
867 | #============================================================================== | |
868 | # SPECIAL VERSION TO HANDLE MIDDLEWARE AUTH |
|
868 | # SPECIAL VERSION TO HANDLE MIDDLEWARE AUTH | |
869 | #============================================================================== |
|
869 | #============================================================================== | |
870 | class HasPermissionAnyMiddleware(object): |
|
870 | class HasPermissionAnyMiddleware(object): | |
871 | def __init__(self, *perms): |
|
871 | def __init__(self, *perms): | |
872 | self.required_perms = set(perms) |
|
872 | self.required_perms = set(perms) | |
873 |
|
873 | |||
874 | def __call__(self, user, repo_name): |
|
874 | def __call__(self, user, repo_name): | |
875 | # repo_name MUST be unicode, since we handle keys in permission |
|
875 | # repo_name MUST be unicode, since we handle keys in permission | |
876 | # dict by unicode |
|
876 | # dict by unicode | |
877 | repo_name = safe_unicode(repo_name) |
|
877 | repo_name = safe_unicode(repo_name) | |
878 | usr = AuthUser(user.user_id) |
|
878 | usr = AuthUser(user.user_id) | |
879 | try: |
|
879 | try: | |
880 | self.user_perms = set([usr.permissions['repositories'][repo_name]]) |
|
880 | self.user_perms = set([usr.permissions['repositories'][repo_name]]) | |
881 | except Exception: |
|
881 | except Exception: | |
882 | log.error('Exception while accessing permissions %s' % |
|
882 | log.error('Exception while accessing permissions %s' % | |
883 | traceback.format_exc()) |
|
883 | traceback.format_exc()) | |
884 | self.user_perms = set() |
|
884 | self.user_perms = set() | |
885 | self.username = user.username |
|
885 | self.username = user.username | |
886 | self.repo_name = repo_name |
|
886 | self.repo_name = repo_name | |
887 | return self.check_permissions() |
|
887 | return self.check_permissions() | |
888 |
|
888 | |||
889 | def check_permissions(self): |
|
889 | def check_permissions(self): | |
890 | log.debug('checking VCS protocol ' |
|
890 | log.debug('checking VCS protocol ' | |
891 | 'permissions %s for user:%s repository:%s', self.user_perms, |
|
891 | 'permissions %s for user:%s repository:%s', self.user_perms, | |
892 | self.username, self.repo_name) |
|
892 | self.username, self.repo_name) | |
893 | if self.required_perms.intersection(self.user_perms): |
|
893 | if self.required_perms.intersection(self.user_perms): | |
894 | log.debug('permission granted for user:%s on repo:%s' % ( |
|
894 | log.debug('permission granted for user:%s on repo:%s' % ( | |
895 | self.username, self.repo_name |
|
895 | self.username, self.repo_name | |
896 | ) |
|
896 | ) | |
897 | ) |
|
897 | ) | |
898 | return True |
|
898 | return True | |
899 | log.debug('permission denied for user:%s on repo:%s' % ( |
|
899 | log.debug('permission denied for user:%s on repo:%s' % ( | |
900 | self.username, self.repo_name |
|
900 | self.username, self.repo_name | |
901 | ) |
|
901 | ) | |
902 | ) |
|
902 | ) | |
903 | return False |
|
903 | return False | |
904 |
|
904 | |||
905 |
|
905 | |||
906 | #============================================================================== |
|
906 | #============================================================================== | |
907 | # SPECIAL VERSION TO HANDLE API AUTH |
|
907 | # SPECIAL VERSION TO HANDLE API AUTH | |
908 | #============================================================================== |
|
908 | #============================================================================== | |
909 | class _BaseApiPerm(object): |
|
909 | class _BaseApiPerm(object): | |
910 | def __init__(self, *perms): |
|
910 | def __init__(self, *perms): | |
911 | self.required_perms = set(perms) |
|
911 | self.required_perms = set(perms) | |
912 |
|
912 | |||
913 | def __call__(self, check_location='unspecified', user=None, repo_name=None): |
|
913 | def __call__(self, check_location='unspecified', user=None, repo_name=None): | |
914 | cls_name = self.__class__.__name__ |
|
914 | cls_name = self.__class__.__name__ | |
915 | check_scope = 'user:%s, repo:%s' % (user, repo_name) |
|
915 | check_scope = 'user:%s, repo:%s' % (user, repo_name) | |
916 | log.debug('checking cls:%s %s %s @ %s', cls_name, |
|
916 | log.debug('checking cls:%s %s %s @ %s', cls_name, | |
917 | self.required_perms, check_scope, check_location) |
|
917 | self.required_perms, check_scope, check_location) | |
918 | if not user: |
|
918 | if not user: | |
919 | log.debug('Empty User passed into arguments') |
|
919 | log.debug('Empty User passed into arguments') | |
920 | return False |
|
920 | return False | |
921 |
|
921 | |||
922 | ## process user |
|
922 | ## process user | |
923 | if not isinstance(user, AuthUser): |
|
923 | if not isinstance(user, AuthUser): | |
924 | user = AuthUser(user.user_id) |
|
924 | user = AuthUser(user.user_id) | |
925 |
|
925 | |||
926 | if self.check_permissions(user.permissions, repo_name): |
|
926 | if self.check_permissions(user.permissions, repo_name): | |
927 | log.debug('Permission to %s granted for user: %s @ %s', repo_name, |
|
927 | log.debug('Permission to %s granted for user: %s @ %s', repo_name, | |
928 | user, check_location) |
|
928 | user, check_location) | |
929 | return True |
|
929 | return True | |
930 |
|
930 | |||
931 | else: |
|
931 | else: | |
932 | log.debug('Permission to %s denied for user: %s @ %s', repo_name, |
|
932 | log.debug('Permission to %s denied for user: %s @ %s', repo_name, | |
933 | user, check_location) |
|
933 | user, check_location) | |
934 | return False |
|
934 | return False | |
935 |
|
935 | |||
936 | def check_permissions(self, perm_defs, repo_name): |
|
936 | def check_permissions(self, perm_defs, repo_name): | |
937 | """ |
|
937 | """ | |
938 | implement in child class should return True if permissions are ok, |
|
938 | implement in child class should return True if permissions are ok, | |
939 | False otherwise |
|
939 | False otherwise | |
940 |
|
940 | |||
941 | :param perm_defs: dict with permission definitions |
|
941 | :param perm_defs: dict with permission definitions | |
942 | :param repo_name: repo name |
|
942 | :param repo_name: repo name | |
943 | """ |
|
943 | """ | |
944 | raise NotImplementedError() |
|
944 | raise NotImplementedError() | |
945 |
|
945 | |||
946 |
|
946 | |||
947 | class HasPermissionAllApi(_BaseApiPerm): |
|
947 | class HasPermissionAllApi(_BaseApiPerm): | |
948 | def __call__(self, user, check_location=''): |
|
948 | def __call__(self, user, check_location=''): | |
949 | return super(HasPermissionAllApi, self)\ |
|
949 | return super(HasPermissionAllApi, self)\ | |
950 | .__call__(check_location=check_location, user=user) |
|
950 | .__call__(check_location=check_location, user=user) | |
951 |
|
951 | |||
952 | def check_permissions(self, perm_defs, repo): |
|
952 | def check_permissions(self, perm_defs, repo): | |
953 | if self.required_perms.issubset(perm_defs.get('global')): |
|
953 | if self.required_perms.issubset(perm_defs.get('global')): | |
954 | return True |
|
954 | return True | |
955 | return False |
|
955 | return False | |
956 |
|
956 | |||
957 |
|
957 | |||
958 | class HasPermissionAnyApi(_BaseApiPerm): |
|
958 | class HasPermissionAnyApi(_BaseApiPerm): | |
959 | def __call__(self, user, check_location=''): |
|
959 | def __call__(self, user, check_location=''): | |
960 | return super(HasPermissionAnyApi, self)\ |
|
960 | return super(HasPermissionAnyApi, self)\ | |
961 | .__call__(check_location=check_location, user=user) |
|
961 | .__call__(check_location=check_location, user=user) | |
962 |
|
962 | |||
963 | def check_permissions(self, perm_defs, repo): |
|
963 | def check_permissions(self, perm_defs, repo): | |
964 | if self.required_perms.intersection(perm_defs.get('global')): |
|
964 | if self.required_perms.intersection(perm_defs.get('global')): | |
965 | return True |
|
965 | return True | |
966 | return False |
|
966 | return False | |
967 |
|
967 | |||
968 |
|
968 | |||
969 | class HasRepoPermissionAllApi(_BaseApiPerm): |
|
969 | class HasRepoPermissionAllApi(_BaseApiPerm): | |
970 | def __call__(self, user, repo_name, check_location=''): |
|
970 | def __call__(self, user, repo_name, check_location=''): | |
971 | return super(HasRepoPermissionAllApi, self)\ |
|
971 | return super(HasRepoPermissionAllApi, self)\ | |
972 | .__call__(check_location=check_location, user=user, |
|
972 | .__call__(check_location=check_location, user=user, | |
973 | repo_name=repo_name) |
|
973 | repo_name=repo_name) | |
974 |
|
974 | |||
975 | def check_permissions(self, perm_defs, repo_name): |
|
975 | def check_permissions(self, perm_defs, repo_name): | |
976 |
|
976 | |||
977 | try: |
|
977 | try: | |
978 | self._user_perms = set( |
|
978 | self._user_perms = set( | |
979 | [perm_defs['repositories'][repo_name]] |
|
979 | [perm_defs['repositories'][repo_name]] | |
980 | ) |
|
980 | ) | |
981 | except KeyError: |
|
981 | except KeyError: | |
982 | log.warning(traceback.format_exc()) |
|
982 | log.warning(traceback.format_exc()) | |
983 | return False |
|
983 | return False | |
984 | if self.required_perms.issubset(self._user_perms): |
|
984 | if self.required_perms.issubset(self._user_perms): | |
985 | return True |
|
985 | return True | |
986 | return False |
|
986 | return False | |
987 |
|
987 | |||
988 |
|
988 | |||
989 | class HasRepoPermissionAnyApi(_BaseApiPerm): |
|
989 | class HasRepoPermissionAnyApi(_BaseApiPerm): | |
990 | def __call__(self, user, repo_name, check_location=''): |
|
990 | def __call__(self, user, repo_name, check_location=''): | |
991 | return super(HasRepoPermissionAnyApi, self)\ |
|
991 | return super(HasRepoPermissionAnyApi, self)\ | |
992 | .__call__(check_location=check_location, user=user, |
|
992 | .__call__(check_location=check_location, user=user, | |
993 | repo_name=repo_name) |
|
993 | repo_name=repo_name) | |
994 |
|
994 | |||
995 | def check_permissions(self, perm_defs, repo_name): |
|
995 | def check_permissions(self, perm_defs, repo_name): | |
996 |
|
996 | |||
997 | try: |
|
997 | try: | |
998 | _user_perms = set( |
|
998 | _user_perms = set( | |
999 | [perm_defs['repositories'][repo_name]] |
|
999 | [perm_defs['repositories'][repo_name]] | |
1000 | ) |
|
1000 | ) | |
1001 | except KeyError: |
|
1001 | except KeyError: | |
1002 | log.warning(traceback.format_exc()) |
|
1002 | log.warning(traceback.format_exc()) | |
1003 | return False |
|
1003 | return False | |
1004 | if self.required_perms.intersection(_user_perms): |
|
1004 | if self.required_perms.intersection(_user_perms): | |
1005 | return True |
|
1005 | return True | |
1006 | return False |
|
1006 | return False | |
1007 |
|
1007 | |||
1008 |
|
1008 | |||
1009 | def check_ip_access(source_ip, allowed_ips=None): |
|
1009 | def check_ip_access(source_ip, allowed_ips=None): | |
1010 | """ |
|
1010 | """ | |
1011 | Checks if source_ip is a subnet of any of allowed_ips. |
|
1011 | Checks if source_ip is a subnet of any of allowed_ips. | |
1012 |
|
1012 | |||
1013 | :param source_ip: |
|
1013 | :param source_ip: | |
1014 | :param allowed_ips: list of allowed ips together with mask |
|
1014 | :param allowed_ips: list of allowed ips together with mask | |
1015 | """ |
|
1015 | """ | |
1016 | from rhodecode.lib import ipaddr |
|
1016 | from rhodecode.lib import ipaddr | |
1017 | log.debug('checking if ip:%s is subnet of %s' % (source_ip, allowed_ips)) |
|
1017 | log.debug('checking if ip:%s is subnet of %s' % (source_ip, allowed_ips)) | |
1018 | if isinstance(allowed_ips, (tuple, list, set)): |
|
1018 | if isinstance(allowed_ips, (tuple, list, set)): | |
1019 | for ip in allowed_ips: |
|
1019 | for ip in allowed_ips: | |
1020 | try: |
|
1020 | try: | |
1021 | if ipaddr.IPAddress(source_ip) in ipaddr.IPNetwork(ip): |
|
1021 | if ipaddr.IPAddress(source_ip) in ipaddr.IPNetwork(ip): | |
1022 | return True |
|
1022 | return True | |
1023 | # for any case we cannot determine the IP, don't crash just |
|
1023 | # for any case we cannot determine the IP, don't crash just | |
1024 | # skip it and log as error, we want to say forbidden still when |
|
1024 | # skip it and log as error, we want to say forbidden still when | |
1025 | # sending bad IP |
|
1025 | # sending bad IP | |
1026 | except Exception: |
|
1026 | except Exception: | |
1027 | log.error(traceback.format_exc()) |
|
1027 | log.error(traceback.format_exc()) | |
1028 | continue |
|
1028 | continue | |
1029 | return False |
|
1029 | return False |
@@ -1,1186 +1,1186 b'' | |||||
1 | """Helper functions |
|
1 | """Helper functions | |
2 |
|
2 | |||
3 | Consists of functions to typically be used within templates, but also |
|
3 | Consists of functions to typically be used within templates, but also | |
4 | available to Controllers. This module is available to both as 'h'. |
|
4 | available to Controllers. This module is available to both as 'h'. | |
5 | """ |
|
5 | """ | |
6 | import random |
|
6 | import random | |
7 | import hashlib |
|
7 | import hashlib | |
8 | import StringIO |
|
8 | import StringIO | |
9 | import urllib |
|
9 | import urllib | |
10 | import math |
|
10 | import math | |
11 | import logging |
|
11 | import logging | |
12 | import re |
|
12 | import re | |
13 | import urlparse |
|
13 | import urlparse | |
14 | import textwrap |
|
14 | import textwrap | |
15 |
|
15 | |||
16 | from datetime import datetime |
|
16 | from datetime import datetime | |
17 | from pygments.formatters.html import HtmlFormatter |
|
17 | from pygments.formatters.html import HtmlFormatter | |
18 | from pygments import highlight as code_highlight |
|
18 | from pygments import highlight as code_highlight | |
19 | from pylons import url, request, config |
|
19 | from pylons import url, request, config | |
20 | from pylons.i18n.translation import _, ungettext |
|
20 | from pylons.i18n.translation import _, ungettext | |
21 | from hashlib import md5 |
|
21 | from hashlib import md5 | |
22 |
|
22 | |||
23 | from webhelpers.html import literal, HTML, escape |
|
23 | from webhelpers.html import literal, HTML, escape | |
24 | from webhelpers.html.tools import * |
|
24 | from webhelpers.html.tools import * | |
25 | from webhelpers.html.builder import make_tag |
|
25 | from webhelpers.html.builder import make_tag | |
26 | from webhelpers.html.tags import auto_discovery_link, checkbox, css_classes, \ |
|
26 | from webhelpers.html.tags import auto_discovery_link, checkbox, css_classes, \ | |
27 | end_form, file, form, hidden, image, javascript_link, link_to, \ |
|
27 | end_form, file, form, hidden, image, javascript_link, link_to, \ | |
28 | link_to_if, link_to_unless, ol, required_legend, select, stylesheet_link, \ |
|
28 | link_to_if, link_to_unless, ol, required_legend, select, stylesheet_link, \ | |
29 | submit, text, password, textarea, title, ul, xml_declaration, radio |
|
29 | submit, text, password, textarea, title, ul, xml_declaration, radio | |
30 | from webhelpers.html.tools import auto_link, button_to, highlight, \ |
|
30 | from webhelpers.html.tools import auto_link, button_to, highlight, \ | |
31 | js_obfuscate, mail_to, strip_links, strip_tags, tag_re |
|
31 | js_obfuscate, mail_to, strip_links, strip_tags, tag_re | |
32 | from webhelpers.number import format_byte_size, format_bit_size |
|
32 | from webhelpers.number import format_byte_size, format_bit_size | |
33 | from webhelpers.pylonslib import Flash as _Flash |
|
33 | from webhelpers.pylonslib import Flash as _Flash | |
34 | from webhelpers.pylonslib.secure_form import secure_form |
|
34 | from webhelpers.pylonslib.secure_form import secure_form | |
35 | from webhelpers.text import chop_at, collapse, convert_accented_entities, \ |
|
35 | from webhelpers.text import chop_at, collapse, convert_accented_entities, \ | |
36 | convert_misc_entities, lchop, plural, rchop, remove_formatting, \ |
|
36 | convert_misc_entities, lchop, plural, rchop, remove_formatting, \ | |
37 | replace_whitespace, urlify, truncate, wrap_paragraphs |
|
37 | replace_whitespace, urlify, truncate, wrap_paragraphs | |
38 | from webhelpers.date import time_ago_in_words |
|
38 | from webhelpers.date import time_ago_in_words | |
39 | from webhelpers.paginate import Page |
|
39 | from webhelpers.paginate import Page | |
40 | from webhelpers.html.tags import _set_input_attrs, _set_id_attr, \ |
|
40 | from webhelpers.html.tags import _set_input_attrs, _set_id_attr, \ | |
41 | convert_boolean_attrs, NotGiven, _make_safe_id_component |
|
41 | convert_boolean_attrs, NotGiven, _make_safe_id_component | |
42 |
|
42 | |||
43 | from rhodecode.lib.annotate import annotate_highlight |
|
43 | from rhodecode.lib.annotate import annotate_highlight | |
44 | from rhodecode.lib.utils import repo_name_slug, get_custom_lexer |
|
44 | from rhodecode.lib.utils import repo_name_slug, get_custom_lexer | |
45 | from rhodecode.lib.utils2 import str2bool, safe_unicode, safe_str, \ |
|
45 | from rhodecode.lib.utils2 import str2bool, safe_unicode, safe_str, \ | |
46 | get_changeset_safe, datetime_to_time, time_to_datetime, AttributeDict |
|
46 | get_changeset_safe, datetime_to_time, time_to_datetime, AttributeDict | |
47 | from rhodecode.lib.markup_renderer import MarkupRenderer |
|
47 | from rhodecode.lib.markup_renderer import MarkupRenderer | |
48 | from rhodecode.lib.vcs.exceptions import ChangesetDoesNotExistError |
|
48 | from rhodecode.lib.vcs.exceptions import ChangesetDoesNotExistError | |
49 | from rhodecode.lib.vcs.backends.base import BaseChangeset, EmptyChangeset |
|
49 | from rhodecode.lib.vcs.backends.base import BaseChangeset, EmptyChangeset | |
50 | from rhodecode.config.conf import DATE_FORMAT, DATETIME_FORMAT |
|
50 | from rhodecode.config.conf import DATE_FORMAT, DATETIME_FORMAT | |
51 | from rhodecode.model.changeset_status import ChangesetStatusModel |
|
51 | from rhodecode.model.changeset_status import ChangesetStatusModel | |
52 | from rhodecode.model.db import URL_SEP, Permission |
|
52 | from rhodecode.model.db import URL_SEP, Permission | |
53 |
|
53 | |||
54 | log = logging.getLogger(__name__) |
|
54 | log = logging.getLogger(__name__) | |
55 |
|
55 | |||
56 |
|
56 | |||
57 | html_escape_table = { |
|
57 | html_escape_table = { | |
58 | "&": "&", |
|
58 | "&": "&", | |
59 | '"': """, |
|
59 | '"': """, | |
60 | "'": "'", |
|
60 | "'": "'", | |
61 | ">": ">", |
|
61 | ">": ">", | |
62 | "<": "<", |
|
62 | "<": "<", | |
63 | } |
|
63 | } | |
64 |
|
64 | |||
65 |
|
65 | |||
66 | def html_escape(text): |
|
66 | def html_escape(text): | |
67 | """Produce entities within text.""" |
|
67 | """Produce entities within text.""" | |
68 | return "".join(html_escape_table.get(c, c) for c in text) |
|
68 | return "".join(html_escape_table.get(c, c) for c in text) | |
69 |
|
69 | |||
70 |
|
70 | |||
71 | def shorter(text, size=20): |
|
71 | def shorter(text, size=20): | |
72 | postfix = '...' |
|
72 | postfix = '...' | |
73 | if len(text) > size: |
|
73 | if len(text) > size: | |
74 | return text[:size - len(postfix)] + postfix |
|
74 | return text[:size - len(postfix)] + postfix | |
75 | return text |
|
75 | return text | |
76 |
|
76 | |||
77 |
|
77 | |||
78 | def _reset(name, value=None, id=NotGiven, type="reset", **attrs): |
|
78 | def _reset(name, value=None, id=NotGiven, type="reset", **attrs): | |
79 | """ |
|
79 | """ | |
80 | Reset button |
|
80 | Reset button | |
81 | """ |
|
81 | """ | |
82 | _set_input_attrs(attrs, type, name, value) |
|
82 | _set_input_attrs(attrs, type, name, value) | |
83 | _set_id_attr(attrs, id, name) |
|
83 | _set_id_attr(attrs, id, name) | |
84 | convert_boolean_attrs(attrs, ["disabled"]) |
|
84 | convert_boolean_attrs(attrs, ["disabled"]) | |
85 | return HTML.input(**attrs) |
|
85 | return HTML.input(**attrs) | |
86 |
|
86 | |||
87 | reset = _reset |
|
87 | reset = _reset | |
88 | safeid = _make_safe_id_component |
|
88 | safeid = _make_safe_id_component | |
89 |
|
89 | |||
90 |
|
90 | |||
91 | def FID(raw_id, path): |
|
91 | def FID(raw_id, path): | |
92 | """ |
|
92 | """ | |
93 | Creates a uniqe ID for filenode based on it's hash of path and revision |
|
93 | Creates a uniqe ID for filenode based on it's hash of path and revision | |
94 | it's safe to use in urls |
|
94 | it's safe to use in urls | |
95 |
|
95 | |||
96 | :param raw_id: |
|
96 | :param raw_id: | |
97 | :param path: |
|
97 | :param path: | |
98 | """ |
|
98 | """ | |
99 |
|
99 | |||
100 | return 'C-%s-%s' % (short_id(raw_id), md5(safe_str(path)).hexdigest()[:12]) |
|
100 | return 'C-%s-%s' % (short_id(raw_id), md5(safe_str(path)).hexdigest()[:12]) | |
101 |
|
101 | |||
102 |
|
102 | |||
103 | def get_token(): |
|
103 | def get_token(): | |
104 | """Return the current authentication token, creating one if one doesn't |
|
104 | """Return the current authentication token, creating one if one doesn't | |
105 | already exist. |
|
105 | already exist. | |
106 | """ |
|
106 | """ | |
107 | token_key = "_authentication_token" |
|
107 | token_key = "_authentication_token" | |
108 | from pylons import session |
|
108 | from pylons import session | |
109 | if not token_key in session: |
|
109 | if not token_key in session: | |
110 | try: |
|
110 | try: | |
111 | token = hashlib.sha1(str(random.getrandbits(128))).hexdigest() |
|
111 | token = hashlib.sha1(str(random.getrandbits(128))).hexdigest() | |
112 | except AttributeError: # Python < 2.4 |
|
112 | except AttributeError: # Python < 2.4 | |
113 | token = hashlib.sha1(str(random.randrange(2 ** 128))).hexdigest() |
|
113 | token = hashlib.sha1(str(random.randrange(2 ** 128))).hexdigest() | |
114 | session[token_key] = token |
|
114 | session[token_key] = token | |
115 | if hasattr(session, 'save'): |
|
115 | if hasattr(session, 'save'): | |
116 | session.save() |
|
116 | session.save() | |
117 | return session[token_key] |
|
117 | return session[token_key] | |
118 |
|
118 | |||
119 |
|
119 | |||
120 | class _GetError(object): |
|
120 | class _GetError(object): | |
121 | """Get error from form_errors, and represent it as span wrapped error |
|
121 | """Get error from form_errors, and represent it as span wrapped error | |
122 | message |
|
122 | message | |
123 |
|
123 | |||
124 | :param field_name: field to fetch errors for |
|
124 | :param field_name: field to fetch errors for | |
125 | :param form_errors: form errors dict |
|
125 | :param form_errors: form errors dict | |
126 | """ |
|
126 | """ | |
127 |
|
127 | |||
128 | def __call__(self, field_name, form_errors): |
|
128 | def __call__(self, field_name, form_errors): | |
129 | tmpl = """<span class="error_msg">%s</span>""" |
|
129 | tmpl = """<span class="error_msg">%s</span>""" | |
130 | if form_errors and field_name in form_errors: |
|
130 | if form_errors and field_name in form_errors: | |
131 | return literal(tmpl % form_errors.get(field_name)) |
|
131 | return literal(tmpl % form_errors.get(field_name)) | |
132 |
|
132 | |||
133 | get_error = _GetError() |
|
133 | get_error = _GetError() | |
134 |
|
134 | |||
135 |
|
135 | |||
136 | class _ToolTip(object): |
|
136 | class _ToolTip(object): | |
137 |
|
137 | |||
138 | def __call__(self, tooltip_title, trim_at=50): |
|
138 | def __call__(self, tooltip_title, trim_at=50): | |
139 | """ |
|
139 | """ | |
140 | Special function just to wrap our text into nice formatted |
|
140 | Special function just to wrap our text into nice formatted | |
141 | autowrapped text |
|
141 | autowrapped text | |
142 |
|
142 | |||
143 | :param tooltip_title: |
|
143 | :param tooltip_title: | |
144 | """ |
|
144 | """ | |
145 | tooltip_title = escape(tooltip_title) |
|
145 | tooltip_title = escape(tooltip_title) | |
146 | tooltip_title = tooltip_title.replace('<', '<').replace('>', '>') |
|
146 | tooltip_title = tooltip_title.replace('<', '<').replace('>', '>') | |
147 | return tooltip_title |
|
147 | return tooltip_title | |
148 | tooltip = _ToolTip() |
|
148 | tooltip = _ToolTip() | |
149 |
|
149 | |||
150 |
|
150 | |||
151 | class _FilesBreadCrumbs(object): |
|
151 | class _FilesBreadCrumbs(object): | |
152 |
|
152 | |||
153 | def __call__(self, repo_name, rev, paths): |
|
153 | def __call__(self, repo_name, rev, paths): | |
154 | if isinstance(paths, str): |
|
154 | if isinstance(paths, str): | |
155 | paths = safe_unicode(paths) |
|
155 | paths = safe_unicode(paths) | |
156 | url_l = [link_to(repo_name, url('files_home', |
|
156 | url_l = [link_to(repo_name, url('files_home', | |
157 | repo_name=repo_name, |
|
157 | repo_name=repo_name, | |
158 | revision=rev, f_path=''), |
|
158 | revision=rev, f_path=''), | |
159 | class_='ypjax-link')] |
|
159 | class_='ypjax-link')] | |
160 | paths_l = paths.split('/') |
|
160 | paths_l = paths.split('/') | |
161 | for cnt, p in enumerate(paths_l): |
|
161 | for cnt, p in enumerate(paths_l): | |
162 | if p != '': |
|
162 | if p != '': | |
163 | url_l.append(link_to(p, |
|
163 | url_l.append(link_to(p, | |
164 | url('files_home', |
|
164 | url('files_home', | |
165 | repo_name=repo_name, |
|
165 | repo_name=repo_name, | |
166 | revision=rev, |
|
166 | revision=rev, | |
167 | f_path='/'.join(paths_l[:cnt + 1]) |
|
167 | f_path='/'.join(paths_l[:cnt + 1]) | |
168 | ), |
|
168 | ), | |
169 | class_='ypjax-link' |
|
169 | class_='ypjax-link' | |
170 | ) |
|
170 | ) | |
171 | ) |
|
171 | ) | |
172 |
|
172 | |||
173 | return literal('/'.join(url_l)) |
|
173 | return literal('/'.join(url_l)) | |
174 |
|
174 | |||
175 | files_breadcrumbs = _FilesBreadCrumbs() |
|
175 | files_breadcrumbs = _FilesBreadCrumbs() | |
176 |
|
176 | |||
177 |
|
177 | |||
178 | class CodeHtmlFormatter(HtmlFormatter): |
|
178 | class CodeHtmlFormatter(HtmlFormatter): | |
179 | """ |
|
179 | """ | |
180 | My code Html Formatter for source codes |
|
180 | My code Html Formatter for source codes | |
181 | """ |
|
181 | """ | |
182 |
|
182 | |||
183 | def wrap(self, source, outfile): |
|
183 | def wrap(self, source, outfile): | |
184 | return self._wrap_div(self._wrap_pre(self._wrap_code(source))) |
|
184 | return self._wrap_div(self._wrap_pre(self._wrap_code(source))) | |
185 |
|
185 | |||
186 | def _wrap_code(self, source): |
|
186 | def _wrap_code(self, source): | |
187 | for cnt, it in enumerate(source): |
|
187 | for cnt, it in enumerate(source): | |
188 | i, t = it |
|
188 | i, t = it | |
189 | t = '<div id="L%s">%s</div>' % (cnt + 1, t) |
|
189 | t = '<div id="L%s">%s</div>' % (cnt + 1, t) | |
190 | yield i, t |
|
190 | yield i, t | |
191 |
|
191 | |||
192 | def _wrap_tablelinenos(self, inner): |
|
192 | def _wrap_tablelinenos(self, inner): | |
193 | dummyoutfile = StringIO.StringIO() |
|
193 | dummyoutfile = StringIO.StringIO() | |
194 | lncount = 0 |
|
194 | lncount = 0 | |
195 | for t, line in inner: |
|
195 | for t, line in inner: | |
196 | if t: |
|
196 | if t: | |
197 | lncount += 1 |
|
197 | lncount += 1 | |
198 | dummyoutfile.write(line) |
|
198 | dummyoutfile.write(line) | |
199 |
|
199 | |||
200 | fl = self.linenostart |
|
200 | fl = self.linenostart | |
201 | mw = len(str(lncount + fl - 1)) |
|
201 | mw = len(str(lncount + fl - 1)) | |
202 | sp = self.linenospecial |
|
202 | sp = self.linenospecial | |
203 | st = self.linenostep |
|
203 | st = self.linenostep | |
204 | la = self.lineanchors |
|
204 | la = self.lineanchors | |
205 | aln = self.anchorlinenos |
|
205 | aln = self.anchorlinenos | |
206 | nocls = self.noclasses |
|
206 | nocls = self.noclasses | |
207 | if sp: |
|
207 | if sp: | |
208 | lines = [] |
|
208 | lines = [] | |
209 |
|
209 | |||
210 | for i in range(fl, fl + lncount): |
|
210 | for i in range(fl, fl + lncount): | |
211 | if i % st == 0: |
|
211 | if i % st == 0: | |
212 | if i % sp == 0: |
|
212 | if i % sp == 0: | |
213 | if aln: |
|
213 | if aln: | |
214 | lines.append('<a href="#%s%d" class="special">%*d</a>' % |
|
214 | lines.append('<a href="#%s%d" class="special">%*d</a>' % | |
215 | (la, i, mw, i)) |
|
215 | (la, i, mw, i)) | |
216 | else: |
|
216 | else: | |
217 | lines.append('<span class="special">%*d</span>' % (mw, i)) |
|
217 | lines.append('<span class="special">%*d</span>' % (mw, i)) | |
218 | else: |
|
218 | else: | |
219 | if aln: |
|
219 | if aln: | |
220 | lines.append('<a href="#%s%d">%*d</a>' % (la, i, mw, i)) |
|
220 | lines.append('<a href="#%s%d">%*d</a>' % (la, i, mw, i)) | |
221 | else: |
|
221 | else: | |
222 | lines.append('%*d' % (mw, i)) |
|
222 | lines.append('%*d' % (mw, i)) | |
223 | else: |
|
223 | else: | |
224 | lines.append('') |
|
224 | lines.append('') | |
225 | ls = '\n'.join(lines) |
|
225 | ls = '\n'.join(lines) | |
226 | else: |
|
226 | else: | |
227 | lines = [] |
|
227 | lines = [] | |
228 | for i in range(fl, fl + lncount): |
|
228 | for i in range(fl, fl + lncount): | |
229 | if i % st == 0: |
|
229 | if i % st == 0: | |
230 | if aln: |
|
230 | if aln: | |
231 | lines.append('<a href="#%s%d">%*d</a>' % (la, i, mw, i)) |
|
231 | lines.append('<a href="#%s%d">%*d</a>' % (la, i, mw, i)) | |
232 | else: |
|
232 | else: | |
233 | lines.append('%*d' % (mw, i)) |
|
233 | lines.append('%*d' % (mw, i)) | |
234 | else: |
|
234 | else: | |
235 | lines.append('') |
|
235 | lines.append('') | |
236 | ls = '\n'.join(lines) |
|
236 | ls = '\n'.join(lines) | |
237 |
|
237 | |||
238 | # in case you wonder about the seemingly redundant <div> here: since the |
|
238 | # in case you wonder about the seemingly redundant <div> here: since the | |
239 | # content in the other cell also is wrapped in a div, some browsers in |
|
239 | # content in the other cell also is wrapped in a div, some browsers in | |
240 | # some configurations seem to mess up the formatting... |
|
240 | # some configurations seem to mess up the formatting... | |
241 | if nocls: |
|
241 | if nocls: | |
242 | yield 0, ('<table class="%stable">' % self.cssclass + |
|
242 | yield 0, ('<table class="%stable">' % self.cssclass + | |
243 | '<tr><td><div class="linenodiv" ' |
|
243 | '<tr><td><div class="linenodiv" ' | |
244 | 'style="background-color: #f0f0f0; padding-right: 10px">' |
|
244 | 'style="background-color: #f0f0f0; padding-right: 10px">' | |
245 | '<pre style="line-height: 125%">' + |
|
245 | '<pre style="line-height: 125%">' + | |
246 | ls + '</pre></div></td><td id="hlcode" class="code">') |
|
246 | ls + '</pre></div></td><td id="hlcode" class="code">') | |
247 | else: |
|
247 | else: | |
248 | yield 0, ('<table class="%stable">' % self.cssclass + |
|
248 | yield 0, ('<table class="%stable">' % self.cssclass + | |
249 | '<tr><td class="linenos"><div class="linenodiv"><pre>' + |
|
249 | '<tr><td class="linenos"><div class="linenodiv"><pre>' + | |
250 | ls + '</pre></div></td><td id="hlcode" class="code">') |
|
250 | ls + '</pre></div></td><td id="hlcode" class="code">') | |
251 | yield 0, dummyoutfile.getvalue() |
|
251 | yield 0, dummyoutfile.getvalue() | |
252 | yield 0, '</td></tr></table>' |
|
252 | yield 0, '</td></tr></table>' | |
253 |
|
253 | |||
254 |
|
254 | |||
255 | def pygmentize(filenode, **kwargs): |
|
255 | def pygmentize(filenode, **kwargs): | |
256 | """ |
|
256 | """ | |
257 | pygmentize function using pygments |
|
257 | pygmentize function using pygments | |
258 |
|
258 | |||
259 | :param filenode: |
|
259 | :param filenode: | |
260 | """ |
|
260 | """ | |
261 | lexer = get_custom_lexer(filenode.extension) or filenode.lexer |
|
261 | lexer = get_custom_lexer(filenode.extension) or filenode.lexer | |
262 | return literal(code_highlight(filenode.content, lexer, |
|
262 | return literal(code_highlight(filenode.content, lexer, | |
263 | CodeHtmlFormatter(**kwargs))) |
|
263 | CodeHtmlFormatter(**kwargs))) | |
264 |
|
264 | |||
265 |
|
265 | |||
266 | def pygmentize_annotation(repo_name, filenode, **kwargs): |
|
266 | def pygmentize_annotation(repo_name, filenode, **kwargs): | |
267 | """ |
|
267 | """ | |
268 | pygmentize function for annotation |
|
268 | pygmentize function for annotation | |
269 |
|
269 | |||
270 | :param filenode: |
|
270 | :param filenode: | |
271 | """ |
|
271 | """ | |
272 |
|
272 | |||
273 | color_dict = {} |
|
273 | color_dict = {} | |
274 |
|
274 | |||
275 | def gen_color(n=10000): |
|
275 | def gen_color(n=10000): | |
276 | """generator for getting n of evenly distributed colors using |
|
276 | """generator for getting n of evenly distributed colors using | |
277 | hsv color and golden ratio. It always return same order of colors |
|
277 | hsv color and golden ratio. It always return same order of colors | |
278 |
|
278 | |||
279 | :returns: RGB tuple |
|
279 | :returns: RGB tuple | |
280 | """ |
|
280 | """ | |
281 |
|
281 | |||
282 | def hsv_to_rgb(h, s, v): |
|
282 | def hsv_to_rgb(h, s, v): | |
283 | if s == 0.0: |
|
283 | if s == 0.0: | |
284 | return v, v, v |
|
284 | return v, v, v | |
285 | i = int(h * 6.0) # XXX assume int() truncates! |
|
285 | i = int(h * 6.0) # XXX assume int() truncates! | |
286 | f = (h * 6.0) - i |
|
286 | f = (h * 6.0) - i | |
287 | p = v * (1.0 - s) |
|
287 | p = v * (1.0 - s) | |
288 | q = v * (1.0 - s * f) |
|
288 | q = v * (1.0 - s * f) | |
289 | t = v * (1.0 - s * (1.0 - f)) |
|
289 | t = v * (1.0 - s * (1.0 - f)) | |
290 | i = i % 6 |
|
290 | i = i % 6 | |
291 | if i == 0: |
|
291 | if i == 0: | |
292 | return v, t, p |
|
292 | return v, t, p | |
293 | if i == 1: |
|
293 | if i == 1: | |
294 | return q, v, p |
|
294 | return q, v, p | |
295 | if i == 2: |
|
295 | if i == 2: | |
296 | return p, v, t |
|
296 | return p, v, t | |
297 | if i == 3: |
|
297 | if i == 3: | |
298 | return p, q, v |
|
298 | return p, q, v | |
299 | if i == 4: |
|
299 | if i == 4: | |
300 | return t, p, v |
|
300 | return t, p, v | |
301 | if i == 5: |
|
301 | if i == 5: | |
302 | return v, p, q |
|
302 | return v, p, q | |
303 |
|
303 | |||
304 | golden_ratio = 0.618033988749895 |
|
304 | golden_ratio = 0.618033988749895 | |
305 | h = 0.22717784590367374 |
|
305 | h = 0.22717784590367374 | |
306 |
|
306 | |||
307 | for _ in xrange(n): |
|
307 | for _ in xrange(n): | |
308 | h += golden_ratio |
|
308 | h += golden_ratio | |
309 | h %= 1 |
|
309 | h %= 1 | |
310 | HSV_tuple = [h, 0.95, 0.95] |
|
310 | HSV_tuple = [h, 0.95, 0.95] | |
311 | RGB_tuple = hsv_to_rgb(*HSV_tuple) |
|
311 | RGB_tuple = hsv_to_rgb(*HSV_tuple) | |
312 | yield map(lambda x: str(int(x * 256)), RGB_tuple) |
|
312 | yield map(lambda x: str(int(x * 256)), RGB_tuple) | |
313 |
|
313 | |||
314 | cgenerator = gen_color() |
|
314 | cgenerator = gen_color() | |
315 |
|
315 | |||
316 | def get_color_string(cs): |
|
316 | def get_color_string(cs): | |
317 | if cs in color_dict: |
|
317 | if cs in color_dict: | |
318 | col = color_dict[cs] |
|
318 | col = color_dict[cs] | |
319 | else: |
|
319 | else: | |
320 | col = color_dict[cs] = cgenerator.next() |
|
320 | col = color_dict[cs] = cgenerator.next() | |
321 | return "color: rgb(%s)! important;" % (', '.join(col)) |
|
321 | return "color: rgb(%s)! important;" % (', '.join(col)) | |
322 |
|
322 | |||
323 | def url_func(repo_name): |
|
323 | def url_func(repo_name): | |
324 |
|
324 | |||
325 | def _url_func(changeset): |
|
325 | def _url_func(changeset): | |
326 | author = changeset.author |
|
326 | author = changeset.author | |
327 | date = changeset.date |
|
327 | date = changeset.date | |
328 | message = tooltip(changeset.message) |
|
328 | message = tooltip(changeset.message) | |
329 |
|
329 | |||
330 | tooltip_html = ("<div style='font-size:0.8em'><b>Author:</b>" |
|
330 | tooltip_html = ("<div style='font-size:0.8em'><b>Author:</b>" | |
331 | " %s<br/><b>Date:</b> %s</b><br/><b>Message:" |
|
331 | " %s<br/><b>Date:</b> %s</b><br/><b>Message:" | |
332 | "</b> %s<br/></div>") |
|
332 | "</b> %s<br/></div>") | |
333 |
|
333 | |||
334 | tooltip_html = tooltip_html % (author, date, message) |
|
334 | tooltip_html = tooltip_html % (author, date, message) | |
335 | lnk_format = '%5s:%s' % ('r%s' % changeset.revision, |
|
335 | lnk_format = '%5s:%s' % ('r%s' % changeset.revision, | |
336 | short_id(changeset.raw_id)) |
|
336 | short_id(changeset.raw_id)) | |
337 | uri = link_to( |
|
337 | uri = link_to( | |
338 | lnk_format, |
|
338 | lnk_format, | |
339 | url('changeset_home', repo_name=repo_name, |
|
339 | url('changeset_home', repo_name=repo_name, | |
340 | revision=changeset.raw_id), |
|
340 | revision=changeset.raw_id), | |
341 | style=get_color_string(changeset.raw_id), |
|
341 | style=get_color_string(changeset.raw_id), | |
342 | class_='tooltip', |
|
342 | class_='tooltip', | |
343 | title=tooltip_html |
|
343 | title=tooltip_html | |
344 | ) |
|
344 | ) | |
345 |
|
345 | |||
346 | uri += '\n' |
|
346 | uri += '\n' | |
347 | return uri |
|
347 | return uri | |
348 | return _url_func |
|
348 | return _url_func | |
349 |
|
349 | |||
350 | return literal(annotate_highlight(filenode, url_func(repo_name), **kwargs)) |
|
350 | return literal(annotate_highlight(filenode, url_func(repo_name), **kwargs)) | |
351 |
|
351 | |||
352 |
|
352 | |||
353 | def is_following_repo(repo_name, user_id): |
|
353 | def is_following_repo(repo_name, user_id): | |
354 | from rhodecode.model.scm import ScmModel |
|
354 | from rhodecode.model.scm import ScmModel | |
355 | return ScmModel().is_following_repo(repo_name, user_id) |
|
355 | return ScmModel().is_following_repo(repo_name, user_id) | |
356 |
|
356 | |||
357 | flash = _Flash() |
|
357 | flash = _Flash() | |
358 |
|
358 | |||
359 | #============================================================================== |
|
359 | #============================================================================== | |
360 | # SCM FILTERS available via h. |
|
360 | # SCM FILTERS available via h. | |
361 | #============================================================================== |
|
361 | #============================================================================== | |
362 | from rhodecode.lib.vcs.utils import author_name, author_email |
|
362 | from rhodecode.lib.vcs.utils import author_name, author_email | |
363 | from rhodecode.lib.utils2 import credentials_filter, age as _age |
|
363 | from rhodecode.lib.utils2 import credentials_filter, age as _age | |
364 | from rhodecode.model.db import User, ChangesetStatus |
|
364 | from rhodecode.model.db import User, ChangesetStatus | |
365 |
|
365 | |||
366 | age = lambda x: _age(x) |
|
366 | age = lambda x: _age(x) | |
367 | capitalize = lambda x: x.capitalize() |
|
367 | capitalize = lambda x: x.capitalize() | |
368 | email = author_email |
|
368 | email = author_email | |
369 | short_id = lambda x: x[:12] |
|
369 | short_id = lambda x: x[:12] | |
370 | hide_credentials = lambda x: ''.join(credentials_filter(x)) |
|
370 | hide_credentials = lambda x: ''.join(credentials_filter(x)) | |
371 |
|
371 | |||
372 |
|
372 | |||
373 | def fmt_date(date): |
|
373 | def fmt_date(date): | |
374 | if date: |
|
374 | if date: | |
375 | _fmt = _(u"%a, %d %b %Y %H:%M:%S").encode('utf8') |
|
375 | _fmt = _(u"%a, %d %b %Y %H:%M:%S").encode('utf8') | |
376 | return date.strftime(_fmt).decode('utf8') |
|
376 | return date.strftime(_fmt).decode('utf8') | |
377 |
|
377 | |||
378 | return "" |
|
378 | return "" | |
379 |
|
379 | |||
380 |
|
380 | |||
381 | def is_git(repository): |
|
381 | def is_git(repository): | |
382 | if hasattr(repository, 'alias'): |
|
382 | if hasattr(repository, 'alias'): | |
383 | _type = repository.alias |
|
383 | _type = repository.alias | |
384 | elif hasattr(repository, 'repo_type'): |
|
384 | elif hasattr(repository, 'repo_type'): | |
385 | _type = repository.repo_type |
|
385 | _type = repository.repo_type | |
386 | else: |
|
386 | else: | |
387 | _type = repository |
|
387 | _type = repository | |
388 | return _type == 'git' |
|
388 | return _type == 'git' | |
389 |
|
389 | |||
390 |
|
390 | |||
391 | def is_hg(repository): |
|
391 | def is_hg(repository): | |
392 | if hasattr(repository, 'alias'): |
|
392 | if hasattr(repository, 'alias'): | |
393 | _type = repository.alias |
|
393 | _type = repository.alias | |
394 | elif hasattr(repository, 'repo_type'): |
|
394 | elif hasattr(repository, 'repo_type'): | |
395 | _type = repository.repo_type |
|
395 | _type = repository.repo_type | |
396 | else: |
|
396 | else: | |
397 | _type = repository |
|
397 | _type = repository | |
398 | return _type == 'hg' |
|
398 | return _type == 'hg' | |
399 |
|
399 | |||
400 |
|
400 | |||
401 | def email_or_none(author): |
|
401 | def email_or_none(author): | |
402 | # extract email from the commit string |
|
402 | # extract email from the commit string | |
403 | _email = email(author) |
|
403 | _email = email(author) | |
404 | if _email != '': |
|
404 | if _email != '': | |
405 | # check it against RhodeCode database, and use the MAIN email for this |
|
405 | # check it against RhodeCode database, and use the MAIN email for this | |
406 | # user |
|
406 | # user | |
407 | user = User.get_by_email(_email, case_insensitive=True, cache=True) |
|
407 | user = User.get_by_email(_email, case_insensitive=True, cache=True) | |
408 | if user is not None: |
|
408 | if user is not None: | |
409 | return user.email |
|
409 | return user.email | |
410 | return _email |
|
410 | return _email | |
411 |
|
411 | |||
412 | # See if it contains a username we can get an email from |
|
412 | # See if it contains a username we can get an email from | |
413 | user = User.get_by_username(author_name(author), case_insensitive=True, |
|
413 | user = User.get_by_username(author_name(author), case_insensitive=True, | |
414 | cache=True) |
|
414 | cache=True) | |
415 | if user is not None: |
|
415 | if user is not None: | |
416 | return user.email |
|
416 | return user.email | |
417 |
|
417 | |||
418 | # No valid email, not a valid user in the system, none! |
|
418 | # No valid email, not a valid user in the system, none! | |
419 | return None |
|
419 | return None | |
420 |
|
420 | |||
421 |
|
421 | |||
422 | def person(author, show_attr="username_and_name"): |
|
422 | def person(author, show_attr="username_and_name"): | |
423 | # attr to return from fetched user |
|
423 | # attr to return from fetched user | |
424 | person_getter = lambda usr: getattr(usr, show_attr) |
|
424 | person_getter = lambda usr: getattr(usr, show_attr) | |
425 |
|
425 | |||
426 | # Valid email in the attribute passed, see if they're in the system |
|
426 | # Valid email in the attribute passed, see if they're in the system | |
427 | _email = email(author) |
|
427 | _email = email(author) | |
428 | if _email != '': |
|
428 | if _email != '': | |
429 | user = User.get_by_email(_email, case_insensitive=True, cache=True) |
|
429 | user = User.get_by_email(_email, case_insensitive=True, cache=True) | |
430 | if user is not None: |
|
430 | if user is not None: | |
431 | return person_getter(user) |
|
431 | return person_getter(user) | |
432 | return _email |
|
432 | return _email | |
433 |
|
433 | |||
434 | # Maybe it's a username? |
|
434 | # Maybe it's a username? | |
435 | _author = author_name(author) |
|
435 | _author = author_name(author) | |
436 | user = User.get_by_username(_author, case_insensitive=True, |
|
436 | user = User.get_by_username(_author, case_insensitive=True, | |
437 | cache=True) |
|
437 | cache=True) | |
438 | if user is not None: |
|
438 | if user is not None: | |
439 | return person_getter(user) |
|
439 | return person_getter(user) | |
440 |
|
440 | |||
441 | # Still nothing? Just pass back the author name then |
|
441 | # Still nothing? Just pass back the author name then | |
442 | return _author |
|
442 | return _author | |
443 |
|
443 | |||
444 |
|
444 | |||
445 | def person_by_id(id_, show_attr="username_and_name"): |
|
445 | def person_by_id(id_, show_attr="username_and_name"): | |
446 | # attr to return from fetched user |
|
446 | # attr to return from fetched user | |
447 | person_getter = lambda usr: getattr(usr, show_attr) |
|
447 | person_getter = lambda usr: getattr(usr, show_attr) | |
448 |
|
448 | |||
449 | #maybe it's an ID ? |
|
449 | #maybe it's an ID ? | |
450 | if str(id_).isdigit() or isinstance(id_, int): |
|
450 | if str(id_).isdigit() or isinstance(id_, int): | |
451 | id_ = int(id_) |
|
451 | id_ = int(id_) | |
452 | user = User.get(id_) |
|
452 | user = User.get(id_) | |
453 | if user is not None: |
|
453 | if user is not None: | |
454 | return person_getter(user) |
|
454 | return person_getter(user) | |
455 | return id_ |
|
455 | return id_ | |
456 |
|
456 | |||
457 |
|
457 | |||
458 | def desc_stylize(value): |
|
458 | def desc_stylize(value): | |
459 | """ |
|
459 | """ | |
460 | converts tags from value into html equivalent |
|
460 | converts tags from value into html equivalent | |
461 |
|
461 | |||
462 | :param value: |
|
462 | :param value: | |
463 | """ |
|
463 | """ | |
464 | value = re.sub(r'\[see\ \=\>\ *([a-zA-Z0-9\/\=\?\&\ \:\/\.\-]*)\]', |
|
464 | value = re.sub(r'\[see\ \=\>\ *([a-zA-Z0-9\/\=\?\&\ \:\/\.\-]*)\]', | |
465 | '<div class="metatag" tag="see">see => \\1 </div>', value) |
|
465 | '<div class="metatag" tag="see">see => \\1 </div>', value) | |
466 | value = re.sub(r'\[license\ \=\>\ *([a-zA-Z0-9\/\=\?\&\ \:\/\.\-]*)\]', |
|
466 | value = re.sub(r'\[license\ \=\>\ *([a-zA-Z0-9\/\=\?\&\ \:\/\.\-]*)\]', | |
467 | '<div class="metatag" tag="license"><a href="http:\/\/www.opensource.org/licenses/\\1">\\1</a></div>', value) |
|
467 | '<div class="metatag" tag="license"><a href="http:\/\/www.opensource.org/licenses/\\1">\\1</a></div>', value) | |
468 | value = re.sub(r'\[(requires|recommends|conflicts|base)\ \=\>\ *([a-zA-Z0-9\-\/]*)\]', |
|
468 | value = re.sub(r'\[(requires|recommends|conflicts|base)\ \=\>\ *([a-zA-Z0-9\-\/]*)\]', | |
469 | '<div class="metatag" tag="\\1">\\1 => <a href="/\\2">\\2</a></div>', value) |
|
469 | '<div class="metatag" tag="\\1">\\1 => <a href="/\\2">\\2</a></div>', value) | |
470 | value = re.sub(r'\[(lang|language)\ \=\>\ *([a-zA-Z\-\/\#\+]*)\]', |
|
470 | value = re.sub(r'\[(lang|language)\ \=\>\ *([a-zA-Z\-\/\#\+]*)\]', | |
471 | '<div class="metatag" tag="lang">\\2</div>', value) |
|
471 | '<div class="metatag" tag="lang">\\2</div>', value) | |
472 | value = re.sub(r'\[([a-z]+)\]', |
|
472 | value = re.sub(r'\[([a-z]+)\]', | |
473 | '<div class="metatag" tag="\\1">\\1</div>', value) |
|
473 | '<div class="metatag" tag="\\1">\\1</div>', value) | |
474 |
|
474 | |||
475 | return value |
|
475 | return value | |
476 |
|
476 | |||
477 |
|
477 | |||
478 | def bool2icon(value): |
|
478 | def bool2icon(value): | |
479 | """Returns True/False values represented as small html image of true/false |
|
479 | """Returns True/False values represented as small html image of true/false | |
480 | icons |
|
480 | icons | |
481 |
|
481 | |||
482 | :param value: bool value |
|
482 | :param value: bool value | |
483 | """ |
|
483 | """ | |
484 |
|
484 | |||
485 | if value is True: |
|
485 | if value is True: | |
486 | return HTML.tag('img', src=url("/images/icons/accept.png"), |
|
486 | return HTML.tag('img', src=url("/images/icons/accept.png"), | |
487 | alt=_('True')) |
|
487 | alt=_('True')) | |
488 |
|
488 | |||
489 | if value is False: |
|
489 | if value is False: | |
490 | return HTML.tag('img', src=url("/images/icons/cancel.png"), |
|
490 | return HTML.tag('img', src=url("/images/icons/cancel.png"), | |
491 | alt=_('False')) |
|
491 | alt=_('False')) | |
492 |
|
492 | |||
493 | return value |
|
493 | return value | |
494 |
|
494 | |||
495 |
|
495 | |||
496 | def action_parser(user_log, feed=False, parse_cs=False): |
|
496 | def action_parser(user_log, feed=False, parse_cs=False): | |
497 | """ |
|
497 | """ | |
498 | This helper will action_map the specified string action into translated |
|
498 | This helper will action_map the specified string action into translated | |
499 | fancy names with icons and links |
|
499 | fancy names with icons and links | |
500 |
|
500 | |||
501 | :param user_log: user log instance |
|
501 | :param user_log: user log instance | |
502 | :param feed: use output for feeds (no html and fancy icons) |
|
502 | :param feed: use output for feeds (no html and fancy icons) | |
503 | :param parse_cs: parse Changesets into VCS instances |
|
503 | :param parse_cs: parse Changesets into VCS instances | |
504 | """ |
|
504 | """ | |
505 |
|
505 | |||
506 | action = user_log.action |
|
506 | action = user_log.action | |
507 | action_params = ' ' |
|
507 | action_params = ' ' | |
508 |
|
508 | |||
509 | x = action.split(':') |
|
509 | x = action.split(':') | |
510 |
|
510 | |||
511 | if len(x) > 1: |
|
511 | if len(x) > 1: | |
512 | action, action_params = x |
|
512 | action, action_params = x | |
513 |
|
513 | |||
514 | def get_cs_links(): |
|
514 | def get_cs_links(): | |
515 | revs_limit = 3 # display this amount always |
|
515 | revs_limit = 3 # display this amount always | |
516 | revs_top_limit = 50 # show upto this amount of changesets hidden |
|
516 | revs_top_limit = 50 # show upto this amount of changesets hidden | |
517 | revs_ids = action_params.split(',') |
|
517 | revs_ids = action_params.split(',') | |
518 | deleted = user_log.repository is None |
|
518 | deleted = user_log.repository is None | |
519 | if deleted: |
|
519 | if deleted: | |
520 | return ','.join(revs_ids) |
|
520 | return ','.join(revs_ids) | |
521 |
|
521 | |||
522 | repo_name = user_log.repository.repo_name |
|
522 | repo_name = user_log.repository.repo_name | |
523 |
|
523 | |||
524 | def lnk(rev, repo_name): |
|
524 | def lnk(rev, repo_name): | |
525 | if isinstance(rev, BaseChangeset) or isinstance(rev, AttributeDict): |
|
525 | if isinstance(rev, BaseChangeset) or isinstance(rev, AttributeDict): | |
526 | lazy_cs = True |
|
526 | lazy_cs = True | |
527 | if getattr(rev, 'op', None) and getattr(rev, 'ref_name', None): |
|
527 | if getattr(rev, 'op', None) and getattr(rev, 'ref_name', None): | |
528 | lazy_cs = False |
|
528 | lazy_cs = False | |
529 | lbl = '?' |
|
529 | lbl = '?' | |
530 | if rev.op == 'delete_branch': |
|
530 | if rev.op == 'delete_branch': | |
531 | lbl = '%s' % _('Deleted branch: %s') % rev.ref_name |
|
531 | lbl = '%s' % _('Deleted branch: %s') % rev.ref_name | |
532 | title = '' |
|
532 | title = '' | |
533 | elif rev.op == 'tag': |
|
533 | elif rev.op == 'tag': | |
534 | lbl = '%s' % _('Created tag: %s') % rev.ref_name |
|
534 | lbl = '%s' % _('Created tag: %s') % rev.ref_name | |
535 | title = '' |
|
535 | title = '' | |
536 | _url = '#' |
|
536 | _url = '#' | |
537 |
|
537 | |||
538 | else: |
|
538 | else: | |
539 | lbl = '%s' % (rev.short_id[:8]) |
|
539 | lbl = '%s' % (rev.short_id[:8]) | |
540 | _url = url('changeset_home', repo_name=repo_name, |
|
540 | _url = url('changeset_home', repo_name=repo_name, | |
541 | revision=rev.raw_id) |
|
541 | revision=rev.raw_id) | |
542 | title = tooltip(rev.message) |
|
542 | title = tooltip(rev.message) | |
543 | else: |
|
543 | else: | |
544 | ## changeset cannot be found/striped/removed etc. |
|
544 | ## changeset cannot be found/striped/removed etc. | |
545 | lbl = ('%s' % rev)[:12] |
|
545 | lbl = ('%s' % rev)[:12] | |
546 | _url = '#' |
|
546 | _url = '#' | |
547 | title = _('Changeset not found') |
|
547 | title = _('Changeset not found') | |
548 | if parse_cs: |
|
548 | if parse_cs: | |
549 | return link_to(lbl, _url, title=title, class_='tooltip') |
|
549 | return link_to(lbl, _url, title=title, class_='tooltip') | |
550 | return link_to(lbl, _url, raw_id=rev.raw_id, repo_name=repo_name, |
|
550 | return link_to(lbl, _url, raw_id=rev.raw_id, repo_name=repo_name, | |
551 | class_='lazy-cs' if lazy_cs else '') |
|
551 | class_='lazy-cs' if lazy_cs else '') | |
552 |
|
552 | |||
553 | revs = [] |
|
553 | revs = [] | |
554 | if len(filter(lambda v: v != '', revs_ids)) > 0: |
|
554 | if len(filter(lambda v: v != '', revs_ids)) > 0: | |
555 | repo = None |
|
555 | repo = None | |
556 | for rev in revs_ids[:revs_top_limit]: |
|
556 | for rev in revs_ids[:revs_top_limit]: | |
557 | _op = _name = None |
|
557 | _op = _name = None | |
558 | if len(rev.split('=>')) == 2: |
|
558 | if len(rev.split('=>')) == 2: | |
559 | _op, _name = rev.split('=>') |
|
559 | _op, _name = rev.split('=>') | |
560 |
|
560 | |||
561 | # we want parsed changesets, or new log store format is bad |
|
561 | # we want parsed changesets, or new log store format is bad | |
562 | if parse_cs: |
|
562 | if parse_cs: | |
563 | try: |
|
563 | try: | |
564 | if repo is None: |
|
564 | if repo is None: | |
565 | repo = user_log.repository.scm_instance |
|
565 | repo = user_log.repository.scm_instance | |
566 | _rev = repo.get_changeset(rev) |
|
566 | _rev = repo.get_changeset(rev) | |
567 | revs.append(_rev) |
|
567 | revs.append(_rev) | |
568 | except ChangesetDoesNotExistError: |
|
568 | except ChangesetDoesNotExistError: | |
569 | log.error('cannot find revision %s in this repo' % rev) |
|
569 | log.error('cannot find revision %s in this repo' % rev) | |
570 | revs.append(rev) |
|
570 | revs.append(rev) | |
571 | continue |
|
571 | continue | |
572 | else: |
|
572 | else: | |
573 | _rev = AttributeDict({ |
|
573 | _rev = AttributeDict({ | |
574 | 'short_id': rev[:12], |
|
574 | 'short_id': rev[:12], | |
575 | 'raw_id': rev, |
|
575 | 'raw_id': rev, | |
576 | 'message': '', |
|
576 | 'message': '', | |
577 | 'op': _op, |
|
577 | 'op': _op, | |
578 | 'ref_name': _name |
|
578 | 'ref_name': _name | |
579 | }) |
|
579 | }) | |
580 | revs.append(_rev) |
|
580 | revs.append(_rev) | |
581 | cs_links = [] |
|
581 | cs_links = [] | |
582 | cs_links.append(" " + ', '.join( |
|
582 | cs_links.append(" " + ', '.join( | |
583 | [lnk(rev, repo_name) for rev in revs[:revs_limit]] |
|
583 | [lnk(rev, repo_name) for rev in revs[:revs_limit]] | |
584 | ) |
|
584 | ) | |
585 | ) |
|
585 | ) | |
586 |
|
586 | |||
587 | compare_view = ( |
|
587 | compare_view = ( | |
588 | ' <div class="compare_view tooltip" title="%s">' |
|
588 | ' <div class="compare_view tooltip" title="%s">' | |
589 | '<a href="%s">%s</a> </div>' % ( |
|
589 | '<a href="%s">%s</a> </div>' % ( | |
590 | _('Show all combined changesets %s->%s') % ( |
|
590 | _('Show all combined changesets %s->%s') % ( | |
591 | revs_ids[0][:12], revs_ids[-1][:12] |
|
591 | revs_ids[0][:12], revs_ids[-1][:12] | |
592 | ), |
|
592 | ), | |
593 | url('changeset_home', repo_name=repo_name, |
|
593 | url('changeset_home', repo_name=repo_name, | |
594 | revision='%s...%s' % (revs_ids[0], revs_ids[-1]) |
|
594 | revision='%s...%s' % (revs_ids[0], revs_ids[-1]) | |
595 | ), |
|
595 | ), | |
596 | _('compare view') |
|
596 | _('compare view') | |
597 | ) |
|
597 | ) | |
598 | ) |
|
598 | ) | |
599 |
|
599 | |||
600 | # if we have exactly one more than normally displayed |
|
600 | # if we have exactly one more than normally displayed | |
601 | # just display it, takes less space than displaying |
|
601 | # just display it, takes less space than displaying | |
602 | # "and 1 more revisions" |
|
602 | # "and 1 more revisions" | |
603 | if len(revs_ids) == revs_limit + 1: |
|
603 | if len(revs_ids) == revs_limit + 1: | |
604 | rev = revs[revs_limit] |
|
604 | rev = revs[revs_limit] | |
605 | cs_links.append(", " + lnk(rev, repo_name)) |
|
605 | cs_links.append(", " + lnk(rev, repo_name)) | |
606 |
|
606 | |||
607 | # hidden-by-default ones |
|
607 | # hidden-by-default ones | |
608 | if len(revs_ids) > revs_limit + 1: |
|
608 | if len(revs_ids) > revs_limit + 1: | |
609 | uniq_id = revs_ids[0] |
|
609 | uniq_id = revs_ids[0] | |
610 | html_tmpl = ( |
|
610 | html_tmpl = ( | |
611 | '<span> %s <a class="show_more" id="_%s" ' |
|
611 | '<span> %s <a class="show_more" id="_%s" ' | |
612 | 'href="#more">%s</a> %s</span>' |
|
612 | 'href="#more">%s</a> %s</span>' | |
613 | ) |
|
613 | ) | |
614 | if not feed: |
|
614 | if not feed: | |
615 | cs_links.append(html_tmpl % ( |
|
615 | cs_links.append(html_tmpl % ( | |
616 | _('and'), |
|
616 | _('and'), | |
617 | uniq_id, _('%s more') % (len(revs_ids) - revs_limit), |
|
617 | uniq_id, _('%s more') % (len(revs_ids) - revs_limit), | |
618 | _('revisions') |
|
618 | _('revisions') | |
619 | ) |
|
619 | ) | |
620 | ) |
|
620 | ) | |
621 |
|
621 | |||
622 | if not feed: |
|
622 | if not feed: | |
623 | html_tmpl = '<span id="%s" style="display:none">, %s </span>' |
|
623 | html_tmpl = '<span id="%s" style="display:none">, %s </span>' | |
624 | else: |
|
624 | else: | |
625 | html_tmpl = '<span id="%s"> %s </span>' |
|
625 | html_tmpl = '<span id="%s"> %s </span>' | |
626 |
|
626 | |||
627 | morelinks = ', '.join( |
|
627 | morelinks = ', '.join( | |
628 | [lnk(rev, repo_name) for rev in revs[revs_limit:]] |
|
628 | [lnk(rev, repo_name) for rev in revs[revs_limit:]] | |
629 | ) |
|
629 | ) | |
630 |
|
630 | |||
631 | if len(revs_ids) > revs_top_limit: |
|
631 | if len(revs_ids) > revs_top_limit: | |
632 | morelinks += ', ...' |
|
632 | morelinks += ', ...' | |
633 |
|
633 | |||
634 | cs_links.append(html_tmpl % (uniq_id, morelinks)) |
|
634 | cs_links.append(html_tmpl % (uniq_id, morelinks)) | |
635 | if len(revs) > 1: |
|
635 | if len(revs) > 1: | |
636 | cs_links.append(compare_view) |
|
636 | cs_links.append(compare_view) | |
637 | return ''.join(cs_links) |
|
637 | return ''.join(cs_links) | |
638 |
|
638 | |||
639 | def get_fork_name(): |
|
639 | def get_fork_name(): | |
640 | repo_name = action_params |
|
640 | repo_name = action_params | |
641 | _url = url('summary_home', repo_name=repo_name) |
|
641 | _url = url('summary_home', repo_name=repo_name) | |
642 | return _('fork name %s') % link_to(action_params, _url) |
|
642 | return _('fork name %s') % link_to(action_params, _url) | |
643 |
|
643 | |||
644 | def get_user_name(): |
|
644 | def get_user_name(): | |
645 | user_name = action_params |
|
645 | user_name = action_params | |
646 | return user_name |
|
646 | return user_name | |
647 |
|
647 | |||
648 | def get_users_group(): |
|
648 | def get_users_group(): | |
649 | group_name = action_params |
|
649 | group_name = action_params | |
650 | return group_name |
|
650 | return group_name | |
651 |
|
651 | |||
652 | def get_pull_request(): |
|
652 | def get_pull_request(): | |
653 | pull_request_id = action_params |
|
653 | pull_request_id = action_params | |
654 | deleted = user_log.repository is None |
|
654 | deleted = user_log.repository is None | |
655 | if deleted: |
|
655 | if deleted: | |
656 | repo_name = user_log.repository_name |
|
656 | repo_name = user_log.repository_name | |
657 | else: |
|
657 | else: | |
658 | repo_name = user_log.repository.repo_name |
|
658 | repo_name = user_log.repository.repo_name | |
659 | return link_to(_('Pull request #%s') % pull_request_id, |
|
659 | return link_to(_('Pull request #%s') % pull_request_id, | |
660 | url('pullrequest_show', repo_name=repo_name, |
|
660 | url('pullrequest_show', repo_name=repo_name, | |
661 | pull_request_id=pull_request_id)) |
|
661 | pull_request_id=pull_request_id)) | |
662 |
|
662 | |||
663 | # action : translated str, callback(extractor), icon |
|
663 | # action : translated str, callback(extractor), icon | |
664 | action_map = { |
|
664 | action_map = { | |
665 | 'user_deleted_repo': (_('[deleted] repository'), |
|
665 | 'user_deleted_repo': (_('[deleted] repository'), | |
666 | None, 'database_delete.png'), |
|
666 | None, 'database_delete.png'), | |
667 | 'user_created_repo': (_('[created] repository'), |
|
667 | 'user_created_repo': (_('[created] repository'), | |
668 | None, 'database_add.png'), |
|
668 | None, 'database_add.png'), | |
669 | 'user_created_fork': (_('[created] repository as fork'), |
|
669 | 'user_created_fork': (_('[created] repository as fork'), | |
670 | None, 'arrow_divide.png'), |
|
670 | None, 'arrow_divide.png'), | |
671 | 'user_forked_repo': (_('[forked] repository'), |
|
671 | 'user_forked_repo': (_('[forked] repository'), | |
672 | get_fork_name, 'arrow_divide.png'), |
|
672 | get_fork_name, 'arrow_divide.png'), | |
673 | 'user_updated_repo': (_('[updated] repository'), |
|
673 | 'user_updated_repo': (_('[updated] repository'), | |
674 | None, 'database_edit.png'), |
|
674 | None, 'database_edit.png'), | |
675 | 'admin_deleted_repo': (_('[delete] repository'), |
|
675 | 'admin_deleted_repo': (_('[delete] repository'), | |
676 | None, 'database_delete.png'), |
|
676 | None, 'database_delete.png'), | |
677 | 'admin_created_repo': (_('[created] repository'), |
|
677 | 'admin_created_repo': (_('[created] repository'), | |
678 | None, 'database_add.png'), |
|
678 | None, 'database_add.png'), | |
679 | 'admin_forked_repo': (_('[forked] repository'), |
|
679 | 'admin_forked_repo': (_('[forked] repository'), | |
680 | None, 'arrow_divide.png'), |
|
680 | None, 'arrow_divide.png'), | |
681 | 'admin_updated_repo': (_('[updated] repository'), |
|
681 | 'admin_updated_repo': (_('[updated] repository'), | |
682 | None, 'database_edit.png'), |
|
682 | None, 'database_edit.png'), | |
683 | 'admin_created_user': (_('[created] user'), |
|
683 | 'admin_created_user': (_('[created] user'), | |
684 | get_user_name, 'user_add.png'), |
|
684 | get_user_name, 'user_add.png'), | |
685 | 'admin_updated_user': (_('[updated] user'), |
|
685 | 'admin_updated_user': (_('[updated] user'), | |
686 | get_user_name, 'user_edit.png'), |
|
686 | get_user_name, 'user_edit.png'), | |
687 |
'admin_created_users_group': (_('[created] user |
|
687 | 'admin_created_users_group': (_('[created] user group'), | |
688 | get_users_group, 'group_add.png'), |
|
688 | get_users_group, 'group_add.png'), | |
689 |
'admin_updated_users_group': (_('[updated] user |
|
689 | 'admin_updated_users_group': (_('[updated] user group'), | |
690 | get_users_group, 'group_edit.png'), |
|
690 | get_users_group, 'group_edit.png'), | |
691 | 'user_commented_revision': (_('[commented] on revision in repository'), |
|
691 | 'user_commented_revision': (_('[commented] on revision in repository'), | |
692 | get_cs_links, 'comment_add.png'), |
|
692 | get_cs_links, 'comment_add.png'), | |
693 | 'user_commented_pull_request': (_('[commented] on pull request for'), |
|
693 | 'user_commented_pull_request': (_('[commented] on pull request for'), | |
694 | get_pull_request, 'comment_add.png'), |
|
694 | get_pull_request, 'comment_add.png'), | |
695 | 'user_closed_pull_request': (_('[closed] pull request for'), |
|
695 | 'user_closed_pull_request': (_('[closed] pull request for'), | |
696 | get_pull_request, 'tick.png'), |
|
696 | get_pull_request, 'tick.png'), | |
697 | 'push': (_('[pushed] into'), |
|
697 | 'push': (_('[pushed] into'), | |
698 | get_cs_links, 'script_add.png'), |
|
698 | get_cs_links, 'script_add.png'), | |
699 | 'push_local': (_('[committed via RhodeCode] into repository'), |
|
699 | 'push_local': (_('[committed via RhodeCode] into repository'), | |
700 | get_cs_links, 'script_edit.png'), |
|
700 | get_cs_links, 'script_edit.png'), | |
701 | 'push_remote': (_('[pulled from remote] into repository'), |
|
701 | 'push_remote': (_('[pulled from remote] into repository'), | |
702 | get_cs_links, 'connect.png'), |
|
702 | get_cs_links, 'connect.png'), | |
703 | 'pull': (_('[pulled] from'), |
|
703 | 'pull': (_('[pulled] from'), | |
704 | None, 'down_16.png'), |
|
704 | None, 'down_16.png'), | |
705 | 'started_following_repo': (_('[started following] repository'), |
|
705 | 'started_following_repo': (_('[started following] repository'), | |
706 | None, 'heart_add.png'), |
|
706 | None, 'heart_add.png'), | |
707 | 'stopped_following_repo': (_('[stopped following] repository'), |
|
707 | 'stopped_following_repo': (_('[stopped following] repository'), | |
708 | None, 'heart_delete.png'), |
|
708 | None, 'heart_delete.png'), | |
709 | } |
|
709 | } | |
710 |
|
710 | |||
711 | action_str = action_map.get(action, action) |
|
711 | action_str = action_map.get(action, action) | |
712 | if feed: |
|
712 | if feed: | |
713 | action = action_str[0].replace('[', '').replace(']', '') |
|
713 | action = action_str[0].replace('[', '').replace(']', '') | |
714 | else: |
|
714 | else: | |
715 | action = action_str[0]\ |
|
715 | action = action_str[0]\ | |
716 | .replace('[', '<span class="journal_highlight">')\ |
|
716 | .replace('[', '<span class="journal_highlight">')\ | |
717 | .replace(']', '</span>') |
|
717 | .replace(']', '</span>') | |
718 |
|
718 | |||
719 | action_params_func = lambda: "" |
|
719 | action_params_func = lambda: "" | |
720 |
|
720 | |||
721 | if callable(action_str[1]): |
|
721 | if callable(action_str[1]): | |
722 | action_params_func = action_str[1] |
|
722 | action_params_func = action_str[1] | |
723 |
|
723 | |||
724 | def action_parser_icon(): |
|
724 | def action_parser_icon(): | |
725 | action = user_log.action |
|
725 | action = user_log.action | |
726 | action_params = None |
|
726 | action_params = None | |
727 | x = action.split(':') |
|
727 | x = action.split(':') | |
728 |
|
728 | |||
729 | if len(x) > 1: |
|
729 | if len(x) > 1: | |
730 | action, action_params = x |
|
730 | action, action_params = x | |
731 |
|
731 | |||
732 | tmpl = """<img src="%s%s" alt="%s"/>""" |
|
732 | tmpl = """<img src="%s%s" alt="%s"/>""" | |
733 | ico = action_map.get(action, ['', '', ''])[2] |
|
733 | ico = action_map.get(action, ['', '', ''])[2] | |
734 | return literal(tmpl % ((url('/images/icons/')), ico, action)) |
|
734 | return literal(tmpl % ((url('/images/icons/')), ico, action)) | |
735 |
|
735 | |||
736 | # returned callbacks we need to call to get |
|
736 | # returned callbacks we need to call to get | |
737 | return [lambda: literal(action), action_params_func, action_parser_icon] |
|
737 | return [lambda: literal(action), action_params_func, action_parser_icon] | |
738 |
|
738 | |||
739 |
|
739 | |||
740 |
|
740 | |||
741 | #============================================================================== |
|
741 | #============================================================================== | |
742 | # PERMS |
|
742 | # PERMS | |
743 | #============================================================================== |
|
743 | #============================================================================== | |
744 | from rhodecode.lib.auth import HasPermissionAny, HasPermissionAll, \ |
|
744 | from rhodecode.lib.auth import HasPermissionAny, HasPermissionAll, \ | |
745 | HasRepoPermissionAny, HasRepoPermissionAll, HasReposGroupPermissionAll, \ |
|
745 | HasRepoPermissionAny, HasRepoPermissionAll, HasReposGroupPermissionAll, \ | |
746 | HasReposGroupPermissionAny |
|
746 | HasReposGroupPermissionAny | |
747 |
|
747 | |||
748 |
|
748 | |||
749 | #============================================================================== |
|
749 | #============================================================================== | |
750 | # GRAVATAR URL |
|
750 | # GRAVATAR URL | |
751 | #============================================================================== |
|
751 | #============================================================================== | |
752 |
|
752 | |||
753 | def gravatar_url(email_address, size=30): |
|
753 | def gravatar_url(email_address, size=30): | |
754 | from pylons import url # doh, we need to re-import url to mock it later |
|
754 | from pylons import url # doh, we need to re-import url to mock it later | |
755 | _def = 'anonymous@rhodecode.org' |
|
755 | _def = 'anonymous@rhodecode.org' | |
756 | use_gravatar = str2bool(config['app_conf'].get('use_gravatar')) |
|
756 | use_gravatar = str2bool(config['app_conf'].get('use_gravatar')) | |
757 | email_address = email_address or _def |
|
757 | email_address = email_address or _def | |
758 | if (not use_gravatar or not email_address or email_address == _def): |
|
758 | if (not use_gravatar or not email_address or email_address == _def): | |
759 | f = lambda a, l: min(l, key=lambda x: abs(x - a)) |
|
759 | f = lambda a, l: min(l, key=lambda x: abs(x - a)) | |
760 | return url("/images/user%s.png" % f(size, [14, 16, 20, 24, 30])) |
|
760 | return url("/images/user%s.png" % f(size, [14, 16, 20, 24, 30])) | |
761 |
|
761 | |||
762 | if use_gravatar and config['app_conf'].get('alternative_gravatar_url'): |
|
762 | if use_gravatar and config['app_conf'].get('alternative_gravatar_url'): | |
763 | tmpl = config['app_conf'].get('alternative_gravatar_url', '') |
|
763 | tmpl = config['app_conf'].get('alternative_gravatar_url', '') | |
764 | parsed_url = urlparse.urlparse(url.current(qualified=True)) |
|
764 | parsed_url = urlparse.urlparse(url.current(qualified=True)) | |
765 | tmpl = tmpl.replace('{email}', email_address)\ |
|
765 | tmpl = tmpl.replace('{email}', email_address)\ | |
766 | .replace('{md5email}', hashlib.md5(email_address.lower()).hexdigest()) \ |
|
766 | .replace('{md5email}', hashlib.md5(email_address.lower()).hexdigest()) \ | |
767 | .replace('{netloc}', parsed_url.netloc)\ |
|
767 | .replace('{netloc}', parsed_url.netloc)\ | |
768 | .replace('{scheme}', parsed_url.scheme)\ |
|
768 | .replace('{scheme}', parsed_url.scheme)\ | |
769 | .replace('{size}', str(size)) |
|
769 | .replace('{size}', str(size)) | |
770 | return tmpl |
|
770 | return tmpl | |
771 |
|
771 | |||
772 | ssl_enabled = 'https' == request.environ.get('wsgi.url_scheme') |
|
772 | ssl_enabled = 'https' == request.environ.get('wsgi.url_scheme') | |
773 | default = 'identicon' |
|
773 | default = 'identicon' | |
774 | baseurl_nossl = "http://www.gravatar.com/avatar/" |
|
774 | baseurl_nossl = "http://www.gravatar.com/avatar/" | |
775 | baseurl_ssl = "https://secure.gravatar.com/avatar/" |
|
775 | baseurl_ssl = "https://secure.gravatar.com/avatar/" | |
776 | baseurl = baseurl_ssl if ssl_enabled else baseurl_nossl |
|
776 | baseurl = baseurl_ssl if ssl_enabled else baseurl_nossl | |
777 |
|
777 | |||
778 | if isinstance(email_address, unicode): |
|
778 | if isinstance(email_address, unicode): | |
779 | #hashlib crashes on unicode items |
|
779 | #hashlib crashes on unicode items | |
780 | email_address = safe_str(email_address) |
|
780 | email_address = safe_str(email_address) | |
781 | # construct the url |
|
781 | # construct the url | |
782 | gravatar_url = baseurl + hashlib.md5(email_address.lower()).hexdigest() + "?" |
|
782 | gravatar_url = baseurl + hashlib.md5(email_address.lower()).hexdigest() + "?" | |
783 | gravatar_url += urllib.urlencode({'d': default, 's': str(size)}) |
|
783 | gravatar_url += urllib.urlencode({'d': default, 's': str(size)}) | |
784 |
|
784 | |||
785 | return gravatar_url |
|
785 | return gravatar_url | |
786 |
|
786 | |||
787 |
|
787 | |||
788 | #============================================================================== |
|
788 | #============================================================================== | |
789 | # REPO PAGER, PAGER FOR REPOSITORY |
|
789 | # REPO PAGER, PAGER FOR REPOSITORY | |
790 | #============================================================================== |
|
790 | #============================================================================== | |
791 | class RepoPage(Page): |
|
791 | class RepoPage(Page): | |
792 |
|
792 | |||
793 | def __init__(self, collection, page=1, items_per_page=20, |
|
793 | def __init__(self, collection, page=1, items_per_page=20, | |
794 | item_count=None, url=None, **kwargs): |
|
794 | item_count=None, url=None, **kwargs): | |
795 |
|
795 | |||
796 | """Create a "RepoPage" instance. special pager for paging |
|
796 | """Create a "RepoPage" instance. special pager for paging | |
797 | repository |
|
797 | repository | |
798 | """ |
|
798 | """ | |
799 | self._url_generator = url |
|
799 | self._url_generator = url | |
800 |
|
800 | |||
801 | # Safe the kwargs class-wide so they can be used in the pager() method |
|
801 | # Safe the kwargs class-wide so they can be used in the pager() method | |
802 | self.kwargs = kwargs |
|
802 | self.kwargs = kwargs | |
803 |
|
803 | |||
804 | # Save a reference to the collection |
|
804 | # Save a reference to the collection | |
805 | self.original_collection = collection |
|
805 | self.original_collection = collection | |
806 |
|
806 | |||
807 | self.collection = collection |
|
807 | self.collection = collection | |
808 |
|
808 | |||
809 | # The self.page is the number of the current page. |
|
809 | # The self.page is the number of the current page. | |
810 | # The first page has the number 1! |
|
810 | # The first page has the number 1! | |
811 | try: |
|
811 | try: | |
812 | self.page = int(page) # make it int() if we get it as a string |
|
812 | self.page = int(page) # make it int() if we get it as a string | |
813 | except (ValueError, TypeError): |
|
813 | except (ValueError, TypeError): | |
814 | self.page = 1 |
|
814 | self.page = 1 | |
815 |
|
815 | |||
816 | self.items_per_page = items_per_page |
|
816 | self.items_per_page = items_per_page | |
817 |
|
817 | |||
818 | # Unless the user tells us how many items the collections has |
|
818 | # Unless the user tells us how many items the collections has | |
819 | # we calculate that ourselves. |
|
819 | # we calculate that ourselves. | |
820 | if item_count is not None: |
|
820 | if item_count is not None: | |
821 | self.item_count = item_count |
|
821 | self.item_count = item_count | |
822 | else: |
|
822 | else: | |
823 | self.item_count = len(self.collection) |
|
823 | self.item_count = len(self.collection) | |
824 |
|
824 | |||
825 | # Compute the number of the first and last available page |
|
825 | # Compute the number of the first and last available page | |
826 | if self.item_count > 0: |
|
826 | if self.item_count > 0: | |
827 | self.first_page = 1 |
|
827 | self.first_page = 1 | |
828 | self.page_count = int(math.ceil(float(self.item_count) / |
|
828 | self.page_count = int(math.ceil(float(self.item_count) / | |
829 | self.items_per_page)) |
|
829 | self.items_per_page)) | |
830 | self.last_page = self.first_page + self.page_count - 1 |
|
830 | self.last_page = self.first_page + self.page_count - 1 | |
831 |
|
831 | |||
832 | # Make sure that the requested page number is the range of |
|
832 | # Make sure that the requested page number is the range of | |
833 | # valid pages |
|
833 | # valid pages | |
834 | if self.page > self.last_page: |
|
834 | if self.page > self.last_page: | |
835 | self.page = self.last_page |
|
835 | self.page = self.last_page | |
836 | elif self.page < self.first_page: |
|
836 | elif self.page < self.first_page: | |
837 | self.page = self.first_page |
|
837 | self.page = self.first_page | |
838 |
|
838 | |||
839 | # Note: the number of items on this page can be less than |
|
839 | # Note: the number of items on this page can be less than | |
840 | # items_per_page if the last page is not full |
|
840 | # items_per_page if the last page is not full | |
841 | self.first_item = max(0, (self.item_count) - (self.page * |
|
841 | self.first_item = max(0, (self.item_count) - (self.page * | |
842 | items_per_page)) |
|
842 | items_per_page)) | |
843 | self.last_item = ((self.item_count - 1) - items_per_page * |
|
843 | self.last_item = ((self.item_count - 1) - items_per_page * | |
844 | (self.page - 1)) |
|
844 | (self.page - 1)) | |
845 |
|
845 | |||
846 | self.items = list(self.collection[self.first_item:self.last_item + 1]) |
|
846 | self.items = list(self.collection[self.first_item:self.last_item + 1]) | |
847 |
|
847 | |||
848 | # Links to previous and next page |
|
848 | # Links to previous and next page | |
849 | if self.page > self.first_page: |
|
849 | if self.page > self.first_page: | |
850 | self.previous_page = self.page - 1 |
|
850 | self.previous_page = self.page - 1 | |
851 | else: |
|
851 | else: | |
852 | self.previous_page = None |
|
852 | self.previous_page = None | |
853 |
|
853 | |||
854 | if self.page < self.last_page: |
|
854 | if self.page < self.last_page: | |
855 | self.next_page = self.page + 1 |
|
855 | self.next_page = self.page + 1 | |
856 | else: |
|
856 | else: | |
857 | self.next_page = None |
|
857 | self.next_page = None | |
858 |
|
858 | |||
859 | # No items available |
|
859 | # No items available | |
860 | else: |
|
860 | else: | |
861 | self.first_page = None |
|
861 | self.first_page = None | |
862 | self.page_count = 0 |
|
862 | self.page_count = 0 | |
863 | self.last_page = None |
|
863 | self.last_page = None | |
864 | self.first_item = None |
|
864 | self.first_item = None | |
865 | self.last_item = None |
|
865 | self.last_item = None | |
866 | self.previous_page = None |
|
866 | self.previous_page = None | |
867 | self.next_page = None |
|
867 | self.next_page = None | |
868 | self.items = [] |
|
868 | self.items = [] | |
869 |
|
869 | |||
870 | # This is a subclass of the 'list' type. Initialise the list now. |
|
870 | # This is a subclass of the 'list' type. Initialise the list now. | |
871 | list.__init__(self, reversed(self.items)) |
|
871 | list.__init__(self, reversed(self.items)) | |
872 |
|
872 | |||
873 |
|
873 | |||
874 | def changed_tooltip(nodes): |
|
874 | def changed_tooltip(nodes): | |
875 | """ |
|
875 | """ | |
876 | Generates a html string for changed nodes in changeset page. |
|
876 | Generates a html string for changed nodes in changeset page. | |
877 | It limits the output to 30 entries |
|
877 | It limits the output to 30 entries | |
878 |
|
878 | |||
879 | :param nodes: LazyNodesGenerator |
|
879 | :param nodes: LazyNodesGenerator | |
880 | """ |
|
880 | """ | |
881 | if nodes: |
|
881 | if nodes: | |
882 | pref = ': <br/> ' |
|
882 | pref = ': <br/> ' | |
883 | suf = '' |
|
883 | suf = '' | |
884 | if len(nodes) > 30: |
|
884 | if len(nodes) > 30: | |
885 | suf = '<br/>' + _(' and %s more') % (len(nodes) - 30) |
|
885 | suf = '<br/>' + _(' and %s more') % (len(nodes) - 30) | |
886 | return literal(pref + '<br/> '.join([safe_unicode(x.path) |
|
886 | return literal(pref + '<br/> '.join([safe_unicode(x.path) | |
887 | for x in nodes[:30]]) + suf) |
|
887 | for x in nodes[:30]]) + suf) | |
888 | else: |
|
888 | else: | |
889 | return ': ' + _('No Files') |
|
889 | return ': ' + _('No Files') | |
890 |
|
890 | |||
891 |
|
891 | |||
892 | def repo_link(groups_and_repos, last_url=None): |
|
892 | def repo_link(groups_and_repos, last_url=None): | |
893 | """ |
|
893 | """ | |
894 | Makes a breadcrumbs link to repo within a group |
|
894 | Makes a breadcrumbs link to repo within a group | |
895 | joins » on each group to create a fancy link |
|
895 | joins » on each group to create a fancy link | |
896 |
|
896 | |||
897 | ex:: |
|
897 | ex:: | |
898 | group >> subgroup >> repo |
|
898 | group >> subgroup >> repo | |
899 |
|
899 | |||
900 | :param groups_and_repos: |
|
900 | :param groups_and_repos: | |
901 | :param last_url: |
|
901 | :param last_url: | |
902 | """ |
|
902 | """ | |
903 | groups, repo_name = groups_and_repos |
|
903 | groups, repo_name = groups_and_repos | |
904 | last_link = link_to(repo_name, last_url) if last_url else repo_name |
|
904 | last_link = link_to(repo_name, last_url) if last_url else repo_name | |
905 |
|
905 | |||
906 | if not groups: |
|
906 | if not groups: | |
907 | if last_url: |
|
907 | if last_url: | |
908 | return last_link |
|
908 | return last_link | |
909 | return repo_name |
|
909 | return repo_name | |
910 | else: |
|
910 | else: | |
911 | def make_link(group): |
|
911 | def make_link(group): | |
912 | return link_to(group.name, |
|
912 | return link_to(group.name, | |
913 | url('repos_group_home', group_name=group.group_name)) |
|
913 | url('repos_group_home', group_name=group.group_name)) | |
914 | return literal(' » '.join(map(make_link, groups) + [last_link])) |
|
914 | return literal(' » '.join(map(make_link, groups) + [last_link])) | |
915 |
|
915 | |||
916 |
|
916 | |||
917 | def fancy_file_stats(stats): |
|
917 | def fancy_file_stats(stats): | |
918 | """ |
|
918 | """ | |
919 | Displays a fancy two colored bar for number of added/deleted |
|
919 | Displays a fancy two colored bar for number of added/deleted | |
920 | lines of code on file |
|
920 | lines of code on file | |
921 |
|
921 | |||
922 | :param stats: two element list of added/deleted lines of code |
|
922 | :param stats: two element list of added/deleted lines of code | |
923 | """ |
|
923 | """ | |
924 | def cgen(l_type, a_v, d_v): |
|
924 | def cgen(l_type, a_v, d_v): | |
925 | mapping = {'tr': 'top-right-rounded-corner-mid', |
|
925 | mapping = {'tr': 'top-right-rounded-corner-mid', | |
926 | 'tl': 'top-left-rounded-corner-mid', |
|
926 | 'tl': 'top-left-rounded-corner-mid', | |
927 | 'br': 'bottom-right-rounded-corner-mid', |
|
927 | 'br': 'bottom-right-rounded-corner-mid', | |
928 | 'bl': 'bottom-left-rounded-corner-mid'} |
|
928 | 'bl': 'bottom-left-rounded-corner-mid'} | |
929 | map_getter = lambda x: mapping[x] |
|
929 | map_getter = lambda x: mapping[x] | |
930 |
|
930 | |||
931 | if l_type == 'a' and d_v: |
|
931 | if l_type == 'a' and d_v: | |
932 | #case when added and deleted are present |
|
932 | #case when added and deleted are present | |
933 | return ' '.join(map(map_getter, ['tl', 'bl'])) |
|
933 | return ' '.join(map(map_getter, ['tl', 'bl'])) | |
934 |
|
934 | |||
935 | if l_type == 'a' and not d_v: |
|
935 | if l_type == 'a' and not d_v: | |
936 | return ' '.join(map(map_getter, ['tr', 'br', 'tl', 'bl'])) |
|
936 | return ' '.join(map(map_getter, ['tr', 'br', 'tl', 'bl'])) | |
937 |
|
937 | |||
938 | if l_type == 'd' and a_v: |
|
938 | if l_type == 'd' and a_v: | |
939 | return ' '.join(map(map_getter, ['tr', 'br'])) |
|
939 | return ' '.join(map(map_getter, ['tr', 'br'])) | |
940 |
|
940 | |||
941 | if l_type == 'd' and not a_v: |
|
941 | if l_type == 'd' and not a_v: | |
942 | return ' '.join(map(map_getter, ['tr', 'br', 'tl', 'bl'])) |
|
942 | return ' '.join(map(map_getter, ['tr', 'br', 'tl', 'bl'])) | |
943 |
|
943 | |||
944 | a, d = stats[0], stats[1] |
|
944 | a, d = stats[0], stats[1] | |
945 | width = 100 |
|
945 | width = 100 | |
946 |
|
946 | |||
947 | if a == 'b': |
|
947 | if a == 'b': | |
948 | #binary mode |
|
948 | #binary mode | |
949 | b_d = '<div class="bin%s %s" style="width:100%%">%s</div>' % (d, cgen('a', a_v='', d_v=0), 'bin') |
|
949 | b_d = '<div class="bin%s %s" style="width:100%%">%s</div>' % (d, cgen('a', a_v='', d_v=0), 'bin') | |
950 | b_a = '<div class="bin1" style="width:0%%">%s</div>' % ('bin') |
|
950 | b_a = '<div class="bin1" style="width:0%%">%s</div>' % ('bin') | |
951 | return literal('<div style="width:%spx">%s%s</div>' % (width, b_a, b_d)) |
|
951 | return literal('<div style="width:%spx">%s%s</div>' % (width, b_a, b_d)) | |
952 |
|
952 | |||
953 | t = stats[0] + stats[1] |
|
953 | t = stats[0] + stats[1] | |
954 | unit = float(width) / (t or 1) |
|
954 | unit = float(width) / (t or 1) | |
955 |
|
955 | |||
956 | # needs > 9% of width to be visible or 0 to be hidden |
|
956 | # needs > 9% of width to be visible or 0 to be hidden | |
957 | a_p = max(9, unit * a) if a > 0 else 0 |
|
957 | a_p = max(9, unit * a) if a > 0 else 0 | |
958 | d_p = max(9, unit * d) if d > 0 else 0 |
|
958 | d_p = max(9, unit * d) if d > 0 else 0 | |
959 | p_sum = a_p + d_p |
|
959 | p_sum = a_p + d_p | |
960 |
|
960 | |||
961 | if p_sum > width: |
|
961 | if p_sum > width: | |
962 | #adjust the percentage to be == 100% since we adjusted to 9 |
|
962 | #adjust the percentage to be == 100% since we adjusted to 9 | |
963 | if a_p > d_p: |
|
963 | if a_p > d_p: | |
964 | a_p = a_p - (p_sum - width) |
|
964 | a_p = a_p - (p_sum - width) | |
965 | else: |
|
965 | else: | |
966 | d_p = d_p - (p_sum - width) |
|
966 | d_p = d_p - (p_sum - width) | |
967 |
|
967 | |||
968 | a_v = a if a > 0 else '' |
|
968 | a_v = a if a > 0 else '' | |
969 | d_v = d if d > 0 else '' |
|
969 | d_v = d if d > 0 else '' | |
970 |
|
970 | |||
971 | d_a = '<div class="added %s" style="width:%s%%">%s</div>' % ( |
|
971 | d_a = '<div class="added %s" style="width:%s%%">%s</div>' % ( | |
972 | cgen('a', a_v, d_v), a_p, a_v |
|
972 | cgen('a', a_v, d_v), a_p, a_v | |
973 | ) |
|
973 | ) | |
974 | d_d = '<div class="deleted %s" style="width:%s%%">%s</div>' % ( |
|
974 | d_d = '<div class="deleted %s" style="width:%s%%">%s</div>' % ( | |
975 | cgen('d', a_v, d_v), d_p, d_v |
|
975 | cgen('d', a_v, d_v), d_p, d_v | |
976 | ) |
|
976 | ) | |
977 | return literal('<div style="width:%spx">%s%s</div>' % (width, d_a, d_d)) |
|
977 | return literal('<div style="width:%spx">%s%s</div>' % (width, d_a, d_d)) | |
978 |
|
978 | |||
979 |
|
979 | |||
980 | def urlify_text(text_, safe=True): |
|
980 | def urlify_text(text_, safe=True): | |
981 | """ |
|
981 | """ | |
982 | Extrac urls from text and make html links out of them |
|
982 | Extrac urls from text and make html links out of them | |
983 |
|
983 | |||
984 | :param text_: |
|
984 | :param text_: | |
985 | """ |
|
985 | """ | |
986 |
|
986 | |||
987 | url_pat = re.compile(r'''(http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]''' |
|
987 | url_pat = re.compile(r'''(http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]''' | |
988 | '''|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+)''') |
|
988 | '''|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+)''') | |
989 |
|
989 | |||
990 | def url_func(match_obj): |
|
990 | def url_func(match_obj): | |
991 | url_full = match_obj.groups()[0] |
|
991 | url_full = match_obj.groups()[0] | |
992 | return '<a href="%(url)s">%(url)s</a>' % ({'url': url_full}) |
|
992 | return '<a href="%(url)s">%(url)s</a>' % ({'url': url_full}) | |
993 | _newtext = url_pat.sub(url_func, text_) |
|
993 | _newtext = url_pat.sub(url_func, text_) | |
994 | if safe: |
|
994 | if safe: | |
995 | return literal(_newtext) |
|
995 | return literal(_newtext) | |
996 | return _newtext |
|
996 | return _newtext | |
997 |
|
997 | |||
998 |
|
998 | |||
999 | def urlify_changesets(text_, repository): |
|
999 | def urlify_changesets(text_, repository): | |
1000 | """ |
|
1000 | """ | |
1001 | Extract revision ids from changeset and make link from them |
|
1001 | Extract revision ids from changeset and make link from them | |
1002 |
|
1002 | |||
1003 | :param text_: |
|
1003 | :param text_: | |
1004 | :param repository: repo name to build the URL with |
|
1004 | :param repository: repo name to build the URL with | |
1005 | """ |
|
1005 | """ | |
1006 | from pylons import url # doh, we need to re-import url to mock it later |
|
1006 | from pylons import url # doh, we need to re-import url to mock it later | |
1007 | URL_PAT = re.compile(r'(^|\s)([0-9a-fA-F]{12,40})($|\s)') |
|
1007 | URL_PAT = re.compile(r'(^|\s)([0-9a-fA-F]{12,40})($|\s)') | |
1008 |
|
1008 | |||
1009 | def url_func(match_obj): |
|
1009 | def url_func(match_obj): | |
1010 | rev = match_obj.groups()[1] |
|
1010 | rev = match_obj.groups()[1] | |
1011 | pref = match_obj.groups()[0] |
|
1011 | pref = match_obj.groups()[0] | |
1012 | suf = match_obj.groups()[2] |
|
1012 | suf = match_obj.groups()[2] | |
1013 |
|
1013 | |||
1014 | tmpl = ( |
|
1014 | tmpl = ( | |
1015 | '%(pref)s<a class="%(cls)s" href="%(url)s">' |
|
1015 | '%(pref)s<a class="%(cls)s" href="%(url)s">' | |
1016 | '%(rev)s</a>%(suf)s' |
|
1016 | '%(rev)s</a>%(suf)s' | |
1017 | ) |
|
1017 | ) | |
1018 | return tmpl % { |
|
1018 | return tmpl % { | |
1019 | 'pref': pref, |
|
1019 | 'pref': pref, | |
1020 | 'cls': 'revision-link', |
|
1020 | 'cls': 'revision-link', | |
1021 | 'url': url('changeset_home', repo_name=repository, revision=rev), |
|
1021 | 'url': url('changeset_home', repo_name=repository, revision=rev), | |
1022 | 'rev': rev, |
|
1022 | 'rev': rev, | |
1023 | 'suf': suf |
|
1023 | 'suf': suf | |
1024 | } |
|
1024 | } | |
1025 |
|
1025 | |||
1026 | newtext = URL_PAT.sub(url_func, text_) |
|
1026 | newtext = URL_PAT.sub(url_func, text_) | |
1027 |
|
1027 | |||
1028 | return newtext |
|
1028 | return newtext | |
1029 |
|
1029 | |||
1030 |
|
1030 | |||
1031 | def urlify_commit(text_, repository=None, link_=None): |
|
1031 | def urlify_commit(text_, repository=None, link_=None): | |
1032 | """ |
|
1032 | """ | |
1033 | Parses given text message and makes proper links. |
|
1033 | Parses given text message and makes proper links. | |
1034 | issues are linked to given issue-server, and rest is a changeset link |
|
1034 | issues are linked to given issue-server, and rest is a changeset link | |
1035 | if link_ is given, in other case it's a plain text |
|
1035 | if link_ is given, in other case it's a plain text | |
1036 |
|
1036 | |||
1037 | :param text_: |
|
1037 | :param text_: | |
1038 | :param repository: |
|
1038 | :param repository: | |
1039 | :param link_: changeset link |
|
1039 | :param link_: changeset link | |
1040 | """ |
|
1040 | """ | |
1041 | import traceback |
|
1041 | import traceback | |
1042 | from pylons import url # doh, we need to re-import url to mock it later |
|
1042 | from pylons import url # doh, we need to re-import url to mock it later | |
1043 |
|
1043 | |||
1044 | def escaper(string): |
|
1044 | def escaper(string): | |
1045 | return string.replace('<', '<').replace('>', '>') |
|
1045 | return string.replace('<', '<').replace('>', '>') | |
1046 |
|
1046 | |||
1047 | def linkify_others(t, l): |
|
1047 | def linkify_others(t, l): | |
1048 | urls = re.compile(r'(\<a.*?\<\/a\>)',) |
|
1048 | urls = re.compile(r'(\<a.*?\<\/a\>)',) | |
1049 | links = [] |
|
1049 | links = [] | |
1050 | for e in urls.split(t): |
|
1050 | for e in urls.split(t): | |
1051 | if not urls.match(e): |
|
1051 | if not urls.match(e): | |
1052 | links.append('<a class="message-link" href="%s">%s</a>' % (l, e)) |
|
1052 | links.append('<a class="message-link" href="%s">%s</a>' % (l, e)) | |
1053 | else: |
|
1053 | else: | |
1054 | links.append(e) |
|
1054 | links.append(e) | |
1055 |
|
1055 | |||
1056 | return ''.join(links) |
|
1056 | return ''.join(links) | |
1057 |
|
1057 | |||
1058 | # urlify changesets - extrac revisions and make link out of them |
|
1058 | # urlify changesets - extrac revisions and make link out of them | |
1059 | newtext = urlify_changesets(escaper(text_), repository) |
|
1059 | newtext = urlify_changesets(escaper(text_), repository) | |
1060 |
|
1060 | |||
1061 | # extract http/https links and make them real urls |
|
1061 | # extract http/https links and make them real urls | |
1062 | newtext = urlify_text(newtext, safe=False) |
|
1062 | newtext = urlify_text(newtext, safe=False) | |
1063 |
|
1063 | |||
1064 | try: |
|
1064 | try: | |
1065 | from rhodecode import CONFIG |
|
1065 | from rhodecode import CONFIG | |
1066 | conf = CONFIG |
|
1066 | conf = CONFIG | |
1067 |
|
1067 | |||
1068 | # allow multiple issue servers to be used |
|
1068 | # allow multiple issue servers to be used | |
1069 | valid_indices = [ |
|
1069 | valid_indices = [ | |
1070 | x.group(1) |
|
1070 | x.group(1) | |
1071 | for x in map(lambda x: re.match(r'issue_pat(.*)', x), conf.keys()) |
|
1071 | for x in map(lambda x: re.match(r'issue_pat(.*)', x), conf.keys()) | |
1072 | if x and 'issue_server_link%s' % x.group(1) in conf |
|
1072 | if x and 'issue_server_link%s' % x.group(1) in conf | |
1073 | and 'issue_prefix%s' % x.group(1) in conf |
|
1073 | and 'issue_prefix%s' % x.group(1) in conf | |
1074 | ] |
|
1074 | ] | |
1075 |
|
1075 | |||
1076 | log.debug('found issue server suffixes `%s` during valuation of: %s' |
|
1076 | log.debug('found issue server suffixes `%s` during valuation of: %s' | |
1077 | % (','.join(valid_indices), newtext)) |
|
1077 | % (','.join(valid_indices), newtext)) | |
1078 |
|
1078 | |||
1079 | for pattern_index in valid_indices: |
|
1079 | for pattern_index in valid_indices: | |
1080 | ISSUE_PATTERN = conf.get('issue_pat%s' % pattern_index) |
|
1080 | ISSUE_PATTERN = conf.get('issue_pat%s' % pattern_index) | |
1081 | ISSUE_SERVER_LNK = conf.get('issue_server_link%s' % pattern_index) |
|
1081 | ISSUE_SERVER_LNK = conf.get('issue_server_link%s' % pattern_index) | |
1082 | ISSUE_PREFIX = conf.get('issue_prefix%s' % pattern_index) |
|
1082 | ISSUE_PREFIX = conf.get('issue_prefix%s' % pattern_index) | |
1083 |
|
1083 | |||
1084 | log.debug('pattern suffix `%s` PAT:%s SERVER_LINK:%s PREFIX:%s' |
|
1084 | log.debug('pattern suffix `%s` PAT:%s SERVER_LINK:%s PREFIX:%s' | |
1085 | % (pattern_index, ISSUE_PATTERN, ISSUE_SERVER_LNK, |
|
1085 | % (pattern_index, ISSUE_PATTERN, ISSUE_SERVER_LNK, | |
1086 | ISSUE_PREFIX)) |
|
1086 | ISSUE_PREFIX)) | |
1087 |
|
1087 | |||
1088 | URL_PAT = re.compile(r'%s' % ISSUE_PATTERN) |
|
1088 | URL_PAT = re.compile(r'%s' % ISSUE_PATTERN) | |
1089 |
|
1089 | |||
1090 | def url_func(match_obj): |
|
1090 | def url_func(match_obj): | |
1091 | pref = '' |
|
1091 | pref = '' | |
1092 | if match_obj.group().startswith(' '): |
|
1092 | if match_obj.group().startswith(' '): | |
1093 | pref = ' ' |
|
1093 | pref = ' ' | |
1094 |
|
1094 | |||
1095 | issue_id = ''.join(match_obj.groups()) |
|
1095 | issue_id = ''.join(match_obj.groups()) | |
1096 | tmpl = ( |
|
1096 | tmpl = ( | |
1097 | '%(pref)s<a class="%(cls)s" href="%(url)s">' |
|
1097 | '%(pref)s<a class="%(cls)s" href="%(url)s">' | |
1098 | '%(issue-prefix)s%(id-repr)s' |
|
1098 | '%(issue-prefix)s%(id-repr)s' | |
1099 | '</a>' |
|
1099 | '</a>' | |
1100 | ) |
|
1100 | ) | |
1101 | url = ISSUE_SERVER_LNK.replace('{id}', issue_id) |
|
1101 | url = ISSUE_SERVER_LNK.replace('{id}', issue_id) | |
1102 | if repository: |
|
1102 | if repository: | |
1103 | url = url.replace('{repo}', repository) |
|
1103 | url = url.replace('{repo}', repository) | |
1104 | repo_name = repository.split(URL_SEP)[-1] |
|
1104 | repo_name = repository.split(URL_SEP)[-1] | |
1105 | url = url.replace('{repo_name}', repo_name) |
|
1105 | url = url.replace('{repo_name}', repo_name) | |
1106 |
|
1106 | |||
1107 | return tmpl % { |
|
1107 | return tmpl % { | |
1108 | 'pref': pref, |
|
1108 | 'pref': pref, | |
1109 | 'cls': 'issue-tracker-link', |
|
1109 | 'cls': 'issue-tracker-link', | |
1110 | 'url': url, |
|
1110 | 'url': url, | |
1111 | 'id-repr': issue_id, |
|
1111 | 'id-repr': issue_id, | |
1112 | 'issue-prefix': ISSUE_PREFIX, |
|
1112 | 'issue-prefix': ISSUE_PREFIX, | |
1113 | 'serv': ISSUE_SERVER_LNK, |
|
1113 | 'serv': ISSUE_SERVER_LNK, | |
1114 | } |
|
1114 | } | |
1115 | newtext = URL_PAT.sub(url_func, newtext) |
|
1115 | newtext = URL_PAT.sub(url_func, newtext) | |
1116 | log.debug('processed prefix:`%s` => %s' % (pattern_index, newtext)) |
|
1116 | log.debug('processed prefix:`%s` => %s' % (pattern_index, newtext)) | |
1117 |
|
1117 | |||
1118 | # if we actually did something above |
|
1118 | # if we actually did something above | |
1119 | if link_: |
|
1119 | if link_: | |
1120 | # wrap not links into final link => link_ |
|
1120 | # wrap not links into final link => link_ | |
1121 | newtext = linkify_others(newtext, link_) |
|
1121 | newtext = linkify_others(newtext, link_) | |
1122 | except: |
|
1122 | except: | |
1123 | log.error(traceback.format_exc()) |
|
1123 | log.error(traceback.format_exc()) | |
1124 | pass |
|
1124 | pass | |
1125 |
|
1125 | |||
1126 | return literal(newtext) |
|
1126 | return literal(newtext) | |
1127 |
|
1127 | |||
1128 |
|
1128 | |||
1129 | def rst(source): |
|
1129 | def rst(source): | |
1130 | return literal('<div class="rst-block">%s</div>' % |
|
1130 | return literal('<div class="rst-block">%s</div>' % | |
1131 | MarkupRenderer.rst(source)) |
|
1131 | MarkupRenderer.rst(source)) | |
1132 |
|
1132 | |||
1133 |
|
1133 | |||
1134 | def rst_w_mentions(source): |
|
1134 | def rst_w_mentions(source): | |
1135 | """ |
|
1135 | """ | |
1136 | Wrapped rst renderer with @mention highlighting |
|
1136 | Wrapped rst renderer with @mention highlighting | |
1137 |
|
1137 | |||
1138 | :param source: |
|
1138 | :param source: | |
1139 | """ |
|
1139 | """ | |
1140 | return literal('<div class="rst-block">%s</div>' % |
|
1140 | return literal('<div class="rst-block">%s</div>' % | |
1141 | MarkupRenderer.rst_with_mentions(source)) |
|
1141 | MarkupRenderer.rst_with_mentions(source)) | |
1142 |
|
1142 | |||
1143 |
|
1143 | |||
1144 | def changeset_status(repo, revision): |
|
1144 | def changeset_status(repo, revision): | |
1145 | return ChangesetStatusModel().get_status(repo, revision) |
|
1145 | return ChangesetStatusModel().get_status(repo, revision) | |
1146 |
|
1146 | |||
1147 |
|
1147 | |||
1148 | def changeset_status_lbl(changeset_status): |
|
1148 | def changeset_status_lbl(changeset_status): | |
1149 | return dict(ChangesetStatus.STATUSES).get(changeset_status) |
|
1149 | return dict(ChangesetStatus.STATUSES).get(changeset_status) | |
1150 |
|
1150 | |||
1151 |
|
1151 | |||
1152 | def get_permission_name(key): |
|
1152 | def get_permission_name(key): | |
1153 | return dict(Permission.PERMS).get(key) |
|
1153 | return dict(Permission.PERMS).get(key) | |
1154 |
|
1154 | |||
1155 |
|
1155 | |||
1156 | def journal_filter_help(): |
|
1156 | def journal_filter_help(): | |
1157 | return _(textwrap.dedent(''' |
|
1157 | return _(textwrap.dedent(''' | |
1158 | Example filter terms: |
|
1158 | Example filter terms: | |
1159 | repository:vcs |
|
1159 | repository:vcs | |
1160 | username:marcin |
|
1160 | username:marcin | |
1161 | action:*push* |
|
1161 | action:*push* | |
1162 | ip:127.0.0.1 |
|
1162 | ip:127.0.0.1 | |
1163 | date:20120101 |
|
1163 | date:20120101 | |
1164 | date:[20120101100000 TO 20120102] |
|
1164 | date:[20120101100000 TO 20120102] | |
1165 |
|
1165 | |||
1166 | Generate wildcards using '*' character: |
|
1166 | Generate wildcards using '*' character: | |
1167 | "repositroy:vcs*" - search everything starting with 'vcs' |
|
1167 | "repositroy:vcs*" - search everything starting with 'vcs' | |
1168 | "repository:*vcs*" - search for repository containing 'vcs' |
|
1168 | "repository:*vcs*" - search for repository containing 'vcs' | |
1169 |
|
1169 | |||
1170 | Optional AND / OR operators in queries |
|
1170 | Optional AND / OR operators in queries | |
1171 | "repository:vcs OR repository:test" |
|
1171 | "repository:vcs OR repository:test" | |
1172 | "username:test AND repository:test*" |
|
1172 | "username:test AND repository:test*" | |
1173 | ''')) |
|
1173 | ''')) | |
1174 |
|
1174 | |||
1175 |
|
1175 | |||
1176 | def not_mapped_error(repo_name): |
|
1176 | def not_mapped_error(repo_name): | |
1177 | flash(_('%s repository is not mapped to db perhaps' |
|
1177 | flash(_('%s repository is not mapped to db perhaps' | |
1178 | ' it was created or renamed from the filesystem' |
|
1178 | ' it was created or renamed from the filesystem' | |
1179 | ' please run the application again' |
|
1179 | ' please run the application again' | |
1180 | ' in order to rescan repositories') % repo_name, category='error') |
|
1180 | ' in order to rescan repositories') % repo_name, category='error') | |
1181 |
|
1181 | |||
1182 |
|
1182 | |||
1183 | def ip_range(ip_addr): |
|
1183 | def ip_range(ip_addr): | |
1184 | from rhodecode.model.db import UserIpMap |
|
1184 | from rhodecode.model.db import UserIpMap | |
1185 | s, e = UserIpMap._get_ip_range(ip_addr) |
|
1185 | s, e = UserIpMap._get_ip_range(ip_addr) | |
1186 | return '%s - %s' % (s, e) |
|
1186 | return '%s - %s' % (s, e) |
@@ -1,705 +1,705 b'' | |||||
1 | # -*- coding: utf-8 -*- |
|
1 | # -*- coding: utf-8 -*- | |
2 | """ |
|
2 | """ | |
3 | rhodecode.model.repo |
|
3 | rhodecode.model.repo | |
4 | ~~~~~~~~~~~~~~~~~~~~ |
|
4 | ~~~~~~~~~~~~~~~~~~~~ | |
5 |
|
5 | |||
6 | Repository model for rhodecode |
|
6 | Repository model for rhodecode | |
7 |
|
7 | |||
8 | :created_on: Jun 5, 2010 |
|
8 | :created_on: Jun 5, 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 | from __future__ import with_statement |
|
25 | from __future__ import with_statement | |
26 | import os |
|
26 | import os | |
27 | import shutil |
|
27 | import shutil | |
28 | import logging |
|
28 | import logging | |
29 | import traceback |
|
29 | import traceback | |
30 | from datetime import datetime |
|
30 | from datetime import datetime | |
31 |
|
31 | |||
32 | from rhodecode.lib.vcs.backends import get_backend |
|
32 | from rhodecode.lib.vcs.backends import get_backend | |
33 | from rhodecode.lib.compat import json |
|
33 | from rhodecode.lib.compat import json | |
34 | from rhodecode.lib.utils2 import LazyProperty, safe_str, safe_unicode,\ |
|
34 | from rhodecode.lib.utils2 import LazyProperty, safe_str, safe_unicode,\ | |
35 | remove_prefix |
|
35 | remove_prefix | |
36 | from rhodecode.lib.caching_query import FromCache |
|
36 | from rhodecode.lib.caching_query import FromCache | |
37 | from rhodecode.lib.hooks import log_create_repository, log_delete_repository |
|
37 | from rhodecode.lib.hooks import log_create_repository, log_delete_repository | |
38 |
|
38 | |||
39 | from rhodecode.model import BaseModel |
|
39 | from rhodecode.model import BaseModel | |
40 | from rhodecode.model.db import Repository, UserRepoToPerm, User, Permission, \ |
|
40 | from rhodecode.model.db import Repository, UserRepoToPerm, User, Permission, \ | |
41 | Statistics, UsersGroup, UsersGroupRepoToPerm, RhodeCodeUi, RepoGroup,\ |
|
41 | Statistics, UsersGroup, UsersGroupRepoToPerm, RhodeCodeUi, RepoGroup,\ | |
42 | RhodeCodeSetting, RepositoryField |
|
42 | RhodeCodeSetting, RepositoryField | |
43 | from rhodecode.lib import helpers as h |
|
43 | from rhodecode.lib import helpers as h | |
44 | from rhodecode.lib.auth import HasRepoPermissionAny |
|
44 | from rhodecode.lib.auth import HasRepoPermissionAny | |
45 | from rhodecode.lib.vcs.backends.base import EmptyChangeset |
|
45 | from rhodecode.lib.vcs.backends.base import EmptyChangeset | |
46 |
|
46 | |||
47 |
|
47 | |||
48 | log = logging.getLogger(__name__) |
|
48 | log = logging.getLogger(__name__) | |
49 |
|
49 | |||
50 |
|
50 | |||
51 | class RepoModel(BaseModel): |
|
51 | class RepoModel(BaseModel): | |
52 |
|
52 | |||
53 | cls = Repository |
|
53 | cls = Repository | |
54 | URL_SEPARATOR = Repository.url_sep() |
|
54 | URL_SEPARATOR = Repository.url_sep() | |
55 |
|
55 | |||
56 | def __get_users_group(self, users_group): |
|
56 | def __get_users_group(self, users_group): | |
57 | return self._get_instance(UsersGroup, users_group, |
|
57 | return self._get_instance(UsersGroup, users_group, | |
58 | callback=UsersGroup.get_by_group_name) |
|
58 | callback=UsersGroup.get_by_group_name) | |
59 |
|
59 | |||
60 | def _get_repos_group(self, repos_group): |
|
60 | def _get_repos_group(self, repos_group): | |
61 | return self._get_instance(RepoGroup, repos_group, |
|
61 | return self._get_instance(RepoGroup, repos_group, | |
62 | callback=RepoGroup.get_by_group_name) |
|
62 | callback=RepoGroup.get_by_group_name) | |
63 |
|
63 | |||
64 | @LazyProperty |
|
64 | @LazyProperty | |
65 | def repos_path(self): |
|
65 | def repos_path(self): | |
66 | """ |
|
66 | """ | |
67 | Get's the repositories root path from database |
|
67 | Get's the repositories root path from database | |
68 | """ |
|
68 | """ | |
69 |
|
69 | |||
70 | q = self.sa.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key == '/').one() |
|
70 | q = self.sa.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key == '/').one() | |
71 | return q.ui_value |
|
71 | return q.ui_value | |
72 |
|
72 | |||
73 | def get(self, repo_id, cache=False): |
|
73 | def get(self, repo_id, cache=False): | |
74 | repo = self.sa.query(Repository)\ |
|
74 | repo = self.sa.query(Repository)\ | |
75 | .filter(Repository.repo_id == repo_id) |
|
75 | .filter(Repository.repo_id == repo_id) | |
76 |
|
76 | |||
77 | if cache: |
|
77 | if cache: | |
78 | repo = repo.options(FromCache("sql_cache_short", |
|
78 | repo = repo.options(FromCache("sql_cache_short", | |
79 | "get_repo_%s" % repo_id)) |
|
79 | "get_repo_%s" % repo_id)) | |
80 | return repo.scalar() |
|
80 | return repo.scalar() | |
81 |
|
81 | |||
82 | def get_repo(self, repository): |
|
82 | def get_repo(self, repository): | |
83 | return self._get_repo(repository) |
|
83 | return self._get_repo(repository) | |
84 |
|
84 | |||
85 | def get_by_repo_name(self, repo_name, cache=False): |
|
85 | def get_by_repo_name(self, repo_name, cache=False): | |
86 | repo = self.sa.query(Repository)\ |
|
86 | repo = self.sa.query(Repository)\ | |
87 | .filter(Repository.repo_name == repo_name) |
|
87 | .filter(Repository.repo_name == repo_name) | |
88 |
|
88 | |||
89 | if cache: |
|
89 | if cache: | |
90 | repo = repo.options(FromCache("sql_cache_short", |
|
90 | repo = repo.options(FromCache("sql_cache_short", | |
91 | "get_repo_%s" % repo_name)) |
|
91 | "get_repo_%s" % repo_name)) | |
92 | return repo.scalar() |
|
92 | return repo.scalar() | |
93 |
|
93 | |||
94 | def get_all_user_repos(self, user): |
|
94 | def get_all_user_repos(self, user): | |
95 | """ |
|
95 | """ | |
96 | Get's all repositories that user have at least read access |
|
96 | Get's all repositories that user have at least read access | |
97 |
|
97 | |||
98 | :param user: |
|
98 | :param user: | |
99 | :type user: |
|
99 | :type user: | |
100 | """ |
|
100 | """ | |
101 | from rhodecode.lib.auth import AuthUser |
|
101 | from rhodecode.lib.auth import AuthUser | |
102 | user = self._get_user(user) |
|
102 | user = self._get_user(user) | |
103 | repos = AuthUser(user_id=user.user_id).permissions['repositories'] |
|
103 | repos = AuthUser(user_id=user.user_id).permissions['repositories'] | |
104 | access_check = lambda r: r[1] in ['repository.read', |
|
104 | access_check = lambda r: r[1] in ['repository.read', | |
105 | 'repository.write', |
|
105 | 'repository.write', | |
106 | 'repository.admin'] |
|
106 | 'repository.admin'] | |
107 | repos = [x[0] for x in filter(access_check, repos.items())] |
|
107 | repos = [x[0] for x in filter(access_check, repos.items())] | |
108 | return Repository.query().filter(Repository.repo_name.in_(repos)) |
|
108 | return Repository.query().filter(Repository.repo_name.in_(repos)) | |
109 |
|
109 | |||
110 | def get_users_js(self): |
|
110 | def get_users_js(self): | |
111 | users = self.sa.query(User).filter(User.active == True).all() |
|
111 | users = self.sa.query(User).filter(User.active == True).all() | |
112 | return json.dumps([ |
|
112 | return json.dumps([ | |
113 | { |
|
113 | { | |
114 | 'id': u.user_id, |
|
114 | 'id': u.user_id, | |
115 | 'fname': u.name, |
|
115 | 'fname': u.name, | |
116 | 'lname': u.lastname, |
|
116 | 'lname': u.lastname, | |
117 | 'nname': u.username, |
|
117 | 'nname': u.username, | |
118 | 'gravatar_lnk': h.gravatar_url(u.email, 14) |
|
118 | 'gravatar_lnk': h.gravatar_url(u.email, 14) | |
119 | } for u in users] |
|
119 | } for u in users] | |
120 | ) |
|
120 | ) | |
121 |
|
121 | |||
122 | def get_users_groups_js(self): |
|
122 | def get_users_groups_js(self): | |
123 | users_groups = self.sa.query(UsersGroup)\ |
|
123 | users_groups = self.sa.query(UsersGroup)\ | |
124 | .filter(UsersGroup.users_group_active == True).all() |
|
124 | .filter(UsersGroup.users_group_active == True).all() | |
125 |
|
125 | |||
126 | return json.dumps([ |
|
126 | return json.dumps([ | |
127 | { |
|
127 | { | |
128 | 'id': gr.users_group_id, |
|
128 | 'id': gr.users_group_id, | |
129 | 'grname': gr.users_group_name, |
|
129 | 'grname': gr.users_group_name, | |
130 | 'grmembers': len(gr.members), |
|
130 | 'grmembers': len(gr.members), | |
131 | } for gr in users_groups] |
|
131 | } for gr in users_groups] | |
132 | ) |
|
132 | ) | |
133 |
|
133 | |||
134 | @classmethod |
|
134 | @classmethod | |
135 | def _render_datatable(cls, tmpl, *args, **kwargs): |
|
135 | def _render_datatable(cls, tmpl, *args, **kwargs): | |
136 | import rhodecode |
|
136 | import rhodecode | |
137 | from pylons import tmpl_context as c |
|
137 | from pylons import tmpl_context as c | |
138 | from pylons.i18n.translation import _ |
|
138 | from pylons.i18n.translation import _ | |
139 |
|
139 | |||
140 | _tmpl_lookup = rhodecode.CONFIG['pylons.app_globals'].mako_lookup |
|
140 | _tmpl_lookup = rhodecode.CONFIG['pylons.app_globals'].mako_lookup | |
141 | template = _tmpl_lookup.get_template('data_table/_dt_elements.html') |
|
141 | template = _tmpl_lookup.get_template('data_table/_dt_elements.html') | |
142 |
|
142 | |||
143 | tmpl = template.get_def(tmpl) |
|
143 | tmpl = template.get_def(tmpl) | |
144 | kwargs.update(dict(_=_, h=h, c=c)) |
|
144 | kwargs.update(dict(_=_, h=h, c=c)) | |
145 | return tmpl.render(*args, **kwargs) |
|
145 | return tmpl.render(*args, **kwargs) | |
146 |
|
146 | |||
147 | @classmethod |
|
147 | @classmethod | |
148 | def update_repoinfo(cls, repositories=None): |
|
148 | def update_repoinfo(cls, repositories=None): | |
149 | if not repositories: |
|
149 | if not repositories: | |
150 | repositories = Repository.getAll() |
|
150 | repositories = Repository.getAll() | |
151 | for repo in repositories: |
|
151 | for repo in repositories: | |
152 | scm_repo = repo.scm_instance_no_cache |
|
152 | scm_repo = repo.scm_instance_no_cache | |
153 | last_cs = EmptyChangeset() |
|
153 | last_cs = EmptyChangeset() | |
154 | if scm_repo: |
|
154 | if scm_repo: | |
155 | last_cs = scm_repo.get_changeset() |
|
155 | last_cs = scm_repo.get_changeset() | |
156 | repo.update_changeset_cache(last_cs) |
|
156 | repo.update_changeset_cache(last_cs) | |
157 |
|
157 | |||
158 | def get_repos_as_dict(self, repos_list=None, admin=False, perm_check=True, |
|
158 | def get_repos_as_dict(self, repos_list=None, admin=False, perm_check=True, | |
159 | super_user_actions=False): |
|
159 | super_user_actions=False): | |
160 | _render = self._render_datatable |
|
160 | _render = self._render_datatable | |
161 |
|
161 | |||
162 | def quick_menu(repo_name): |
|
162 | def quick_menu(repo_name): | |
163 | return _render('quick_menu', repo_name) |
|
163 | return _render('quick_menu', repo_name) | |
164 |
|
164 | |||
165 | def repo_lnk(name, rtype, private, fork_of): |
|
165 | def repo_lnk(name, rtype, private, fork_of): | |
166 | return _render('repo_name', name, rtype, private, fork_of, |
|
166 | return _render('repo_name', name, rtype, private, fork_of, | |
167 | short_name=not admin, admin=False) |
|
167 | short_name=not admin, admin=False) | |
168 |
|
168 | |||
169 | def last_change(last_change): |
|
169 | def last_change(last_change): | |
170 | return _render("last_change", last_change) |
|
170 | return _render("last_change", last_change) | |
171 |
|
171 | |||
172 | def rss_lnk(repo_name): |
|
172 | def rss_lnk(repo_name): | |
173 | return _render("rss", repo_name) |
|
173 | return _render("rss", repo_name) | |
174 |
|
174 | |||
175 | def atom_lnk(repo_name): |
|
175 | def atom_lnk(repo_name): | |
176 | return _render("atom", repo_name) |
|
176 | return _render("atom", repo_name) | |
177 |
|
177 | |||
178 | def last_rev(repo_name, cs_cache): |
|
178 | def last_rev(repo_name, cs_cache): | |
179 | return _render('revision', repo_name, cs_cache.get('revision'), |
|
179 | return _render('revision', repo_name, cs_cache.get('revision'), | |
180 | cs_cache.get('raw_id'), cs_cache.get('author'), |
|
180 | cs_cache.get('raw_id'), cs_cache.get('author'), | |
181 | cs_cache.get('message')) |
|
181 | cs_cache.get('message')) | |
182 |
|
182 | |||
183 | def desc(desc): |
|
183 | def desc(desc): | |
184 | from pylons import tmpl_context as c |
|
184 | from pylons import tmpl_context as c | |
185 | if c.visual.stylify_metatags: |
|
185 | if c.visual.stylify_metatags: | |
186 | return h.urlify_text(h.desc_stylize(h.truncate(desc, 60))) |
|
186 | return h.urlify_text(h.desc_stylize(h.truncate(desc, 60))) | |
187 | else: |
|
187 | else: | |
188 | return h.urlify_text(h.truncate(desc, 60)) |
|
188 | return h.urlify_text(h.truncate(desc, 60)) | |
189 |
|
189 | |||
190 | def repo_actions(repo_name): |
|
190 | def repo_actions(repo_name): | |
191 | return _render('repo_actions', repo_name, super_user_actions) |
|
191 | return _render('repo_actions', repo_name, super_user_actions) | |
192 |
|
192 | |||
193 | def owner_actions(user_id, username): |
|
193 | def owner_actions(user_id, username): | |
194 | return _render('user_name', user_id, username) |
|
194 | return _render('user_name', user_id, username) | |
195 |
|
195 | |||
196 | repos_data = [] |
|
196 | repos_data = [] | |
197 | for repo in repos_list: |
|
197 | for repo in repos_list: | |
198 | if perm_check: |
|
198 | if perm_check: | |
199 | # check permission at this level |
|
199 | # check permission at this level | |
200 | if not HasRepoPermissionAny( |
|
200 | if not HasRepoPermissionAny( | |
201 | 'repository.read', 'repository.write', 'repository.admin' |
|
201 | 'repository.read', 'repository.write', 'repository.admin' | |
202 | )(repo.repo_name, 'get_repos_as_dict check'): |
|
202 | )(repo.repo_name, 'get_repos_as_dict check'): | |
203 | continue |
|
203 | continue | |
204 | cs_cache = repo.changeset_cache |
|
204 | cs_cache = repo.changeset_cache | |
205 | row = { |
|
205 | row = { | |
206 | "menu": quick_menu(repo.repo_name), |
|
206 | "menu": quick_menu(repo.repo_name), | |
207 | "raw_name": repo.repo_name.lower(), |
|
207 | "raw_name": repo.repo_name.lower(), | |
208 | "name": repo_lnk(repo.repo_name, repo.repo_type, |
|
208 | "name": repo_lnk(repo.repo_name, repo.repo_type, | |
209 | repo.private, repo.fork), |
|
209 | repo.private, repo.fork), | |
210 | "last_change": last_change(repo.last_db_change), |
|
210 | "last_change": last_change(repo.last_db_change), | |
211 | "last_changeset": last_rev(repo.repo_name, cs_cache), |
|
211 | "last_changeset": last_rev(repo.repo_name, cs_cache), | |
212 | "raw_tip": cs_cache.get('revision'), |
|
212 | "raw_tip": cs_cache.get('revision'), | |
213 | "desc": desc(repo.description), |
|
213 | "desc": desc(repo.description), | |
214 | "owner": h.person(repo.user.username), |
|
214 | "owner": h.person(repo.user.username), | |
215 | "rss": rss_lnk(repo.repo_name), |
|
215 | "rss": rss_lnk(repo.repo_name), | |
216 | "atom": atom_lnk(repo.repo_name), |
|
216 | "atom": atom_lnk(repo.repo_name), | |
217 |
|
217 | |||
218 | } |
|
218 | } | |
219 | if admin: |
|
219 | if admin: | |
220 | row.update({ |
|
220 | row.update({ | |
221 | "action": repo_actions(repo.repo_name), |
|
221 | "action": repo_actions(repo.repo_name), | |
222 | "owner": owner_actions(repo.user.user_id, |
|
222 | "owner": owner_actions(repo.user.user_id, | |
223 | h.person(repo.user.username)) |
|
223 | h.person(repo.user.username)) | |
224 | }) |
|
224 | }) | |
225 | repos_data.append(row) |
|
225 | repos_data.append(row) | |
226 |
|
226 | |||
227 | return { |
|
227 | return { | |
228 | "totalRecords": len(repos_list), |
|
228 | "totalRecords": len(repos_list), | |
229 | "startIndex": 0, |
|
229 | "startIndex": 0, | |
230 | "sort": "name", |
|
230 | "sort": "name", | |
231 | "dir": "asc", |
|
231 | "dir": "asc", | |
232 | "records": repos_data |
|
232 | "records": repos_data | |
233 | } |
|
233 | } | |
234 |
|
234 | |||
235 | def _get_defaults(self, repo_name): |
|
235 | def _get_defaults(self, repo_name): | |
236 | """ |
|
236 | """ | |
237 | Get's information about repository, and returns a dict for |
|
237 | Get's information about repository, and returns a dict for | |
238 | usage in forms |
|
238 | usage in forms | |
239 |
|
239 | |||
240 | :param repo_name: |
|
240 | :param repo_name: | |
241 | """ |
|
241 | """ | |
242 |
|
242 | |||
243 | repo_info = Repository.get_by_repo_name(repo_name) |
|
243 | repo_info = Repository.get_by_repo_name(repo_name) | |
244 |
|
244 | |||
245 | if repo_info is None: |
|
245 | if repo_info is None: | |
246 | return None |
|
246 | return None | |
247 |
|
247 | |||
248 | defaults = repo_info.get_dict() |
|
248 | defaults = repo_info.get_dict() | |
249 | group, repo_name = repo_info.groups_and_repo |
|
249 | group, repo_name = repo_info.groups_and_repo | |
250 | defaults['repo_name'] = repo_name |
|
250 | defaults['repo_name'] = repo_name | |
251 | defaults['repo_group'] = getattr(group[-1] if group else None, |
|
251 | defaults['repo_group'] = getattr(group[-1] if group else None, | |
252 | 'group_id', None) |
|
252 | 'group_id', None) | |
253 |
|
253 | |||
254 | for strip, k in [(0, 'repo_type'), (1, 'repo_enable_downloads'), |
|
254 | for strip, k in [(0, 'repo_type'), (1, 'repo_enable_downloads'), | |
255 | (1, 'repo_description'), (1, 'repo_enable_locking'), |
|
255 | (1, 'repo_description'), (1, 'repo_enable_locking'), | |
256 | (1, 'repo_landing_rev'), (0, 'clone_uri'), |
|
256 | (1, 'repo_landing_rev'), (0, 'clone_uri'), | |
257 | (1, 'repo_private'), (1, 'repo_enable_statistics')]: |
|
257 | (1, 'repo_private'), (1, 'repo_enable_statistics')]: | |
258 | attr = k |
|
258 | attr = k | |
259 | if strip: |
|
259 | if strip: | |
260 | attr = remove_prefix(k, 'repo_') |
|
260 | attr = remove_prefix(k, 'repo_') | |
261 |
|
261 | |||
262 | defaults[k] = defaults[attr] |
|
262 | defaults[k] = defaults[attr] | |
263 |
|
263 | |||
264 | # fill owner |
|
264 | # fill owner | |
265 | if repo_info.user: |
|
265 | if repo_info.user: | |
266 | defaults.update({'user': repo_info.user.username}) |
|
266 | defaults.update({'user': repo_info.user.username}) | |
267 | else: |
|
267 | else: | |
268 | replacement_user = User.query().filter(User.admin == |
|
268 | replacement_user = User.query().filter(User.admin == | |
269 | True).first().username |
|
269 | True).first().username | |
270 | defaults.update({'user': replacement_user}) |
|
270 | defaults.update({'user': replacement_user}) | |
271 |
|
271 | |||
272 | # fill repository users |
|
272 | # fill repository users | |
273 | for p in repo_info.repo_to_perm: |
|
273 | for p in repo_info.repo_to_perm: | |
274 | defaults.update({'u_perm_%s' % p.user.username: |
|
274 | defaults.update({'u_perm_%s' % p.user.username: | |
275 | p.permission.permission_name}) |
|
275 | p.permission.permission_name}) | |
276 |
|
276 | |||
277 | # fill repository groups |
|
277 | # fill repository groups | |
278 | for p in repo_info.users_group_to_perm: |
|
278 | for p in repo_info.users_group_to_perm: | |
279 | defaults.update({'g_perm_%s' % p.users_group.users_group_name: |
|
279 | defaults.update({'g_perm_%s' % p.users_group.users_group_name: | |
280 | p.permission.permission_name}) |
|
280 | p.permission.permission_name}) | |
281 |
|
281 | |||
282 | return defaults |
|
282 | return defaults | |
283 |
|
283 | |||
284 | def update(self, org_repo_name, **kwargs): |
|
284 | def update(self, org_repo_name, **kwargs): | |
285 | try: |
|
285 | try: | |
286 | cur_repo = self.get_by_repo_name(org_repo_name, cache=False) |
|
286 | cur_repo = self.get_by_repo_name(org_repo_name, cache=False) | |
287 |
|
287 | |||
288 | # update permissions |
|
288 | # update permissions | |
289 | for member, perm, member_type in kwargs['perms_updates']: |
|
289 | for member, perm, member_type in kwargs['perms_updates']: | |
290 | if member_type == 'user': |
|
290 | if member_type == 'user': | |
291 | # this updates existing one |
|
291 | # this updates existing one | |
292 | RepoModel().grant_user_permission( |
|
292 | RepoModel().grant_user_permission( | |
293 | repo=cur_repo, user=member, perm=perm |
|
293 | repo=cur_repo, user=member, perm=perm | |
294 | ) |
|
294 | ) | |
295 | else: |
|
295 | else: | |
296 | RepoModel().grant_users_group_permission( |
|
296 | RepoModel().grant_users_group_permission( | |
297 | repo=cur_repo, group_name=member, perm=perm |
|
297 | repo=cur_repo, group_name=member, perm=perm | |
298 | ) |
|
298 | ) | |
299 | # set new permissions |
|
299 | # set new permissions | |
300 | for member, perm, member_type in kwargs['perms_new']: |
|
300 | for member, perm, member_type in kwargs['perms_new']: | |
301 | if member_type == 'user': |
|
301 | if member_type == 'user': | |
302 | RepoModel().grant_user_permission( |
|
302 | RepoModel().grant_user_permission( | |
303 | repo=cur_repo, user=member, perm=perm |
|
303 | repo=cur_repo, user=member, perm=perm | |
304 | ) |
|
304 | ) | |
305 | else: |
|
305 | else: | |
306 | RepoModel().grant_users_group_permission( |
|
306 | RepoModel().grant_users_group_permission( | |
307 | repo=cur_repo, group_name=member, perm=perm |
|
307 | repo=cur_repo, group_name=member, perm=perm | |
308 | ) |
|
308 | ) | |
309 |
|
309 | |||
310 | if 'user' in kwargs: |
|
310 | if 'user' in kwargs: | |
311 | cur_repo.user = User.get_by_username(kwargs['user']) |
|
311 | cur_repo.user = User.get_by_username(kwargs['user']) | |
312 |
|
312 | |||
313 | if 'repo_group' in kwargs: |
|
313 | if 'repo_group' in kwargs: | |
314 | cur_repo.group = RepoGroup.get(kwargs['repo_group']) |
|
314 | cur_repo.group = RepoGroup.get(kwargs['repo_group']) | |
315 |
|
315 | |||
316 | for strip, k in [(0, 'repo_type'), (1, 'repo_enable_downloads'), |
|
316 | for strip, k in [(0, 'repo_type'), (1, 'repo_enable_downloads'), | |
317 | (1, 'repo_description'), (1, 'repo_enable_locking'), |
|
317 | (1, 'repo_description'), (1, 'repo_enable_locking'), | |
318 | (1, 'repo_landing_rev'), (0, 'clone_uri'), |
|
318 | (1, 'repo_landing_rev'), (0, 'clone_uri'), | |
319 | (1, 'repo_private'), (1, 'repo_enable_statistics')]: |
|
319 | (1, 'repo_private'), (1, 'repo_enable_statistics')]: | |
320 | if k in kwargs: |
|
320 | if k in kwargs: | |
321 | val = kwargs[k] |
|
321 | val = kwargs[k] | |
322 | if strip: |
|
322 | if strip: | |
323 | k = remove_prefix(k, 'repo_') |
|
323 | k = remove_prefix(k, 'repo_') | |
324 | setattr(cur_repo, k, val) |
|
324 | setattr(cur_repo, k, val) | |
325 |
|
325 | |||
326 | new_name = cur_repo.get_new_name(kwargs['repo_name']) |
|
326 | new_name = cur_repo.get_new_name(kwargs['repo_name']) | |
327 | cur_repo.repo_name = new_name |
|
327 | cur_repo.repo_name = new_name | |
328 |
|
328 | |||
329 | #handle extra fields |
|
329 | #handle extra fields | |
330 | for field in filter(lambda k: k.startswith(RepositoryField.PREFIX), kwargs): |
|
330 | for field in filter(lambda k: k.startswith(RepositoryField.PREFIX), kwargs): | |
331 | k = RepositoryField.un_prefix_key(field) |
|
331 | k = RepositoryField.un_prefix_key(field) | |
332 | ex_field = RepositoryField.get_by_key_name(key=k, repo=cur_repo) |
|
332 | ex_field = RepositoryField.get_by_key_name(key=k, repo=cur_repo) | |
333 | if ex_field: |
|
333 | if ex_field: | |
334 | ex_field.field_value = kwargs[field] |
|
334 | ex_field.field_value = kwargs[field] | |
335 | self.sa.add(ex_field) |
|
335 | self.sa.add(ex_field) | |
336 | self.sa.add(cur_repo) |
|
336 | self.sa.add(cur_repo) | |
337 |
|
337 | |||
338 | if org_repo_name != new_name: |
|
338 | if org_repo_name != new_name: | |
339 | # rename repository |
|
339 | # rename repository | |
340 | self.__rename_repo(old=org_repo_name, new=new_name) |
|
340 | self.__rename_repo(old=org_repo_name, new=new_name) | |
341 |
|
341 | |||
342 | return cur_repo |
|
342 | return cur_repo | |
343 | except: |
|
343 | except: | |
344 | log.error(traceback.format_exc()) |
|
344 | log.error(traceback.format_exc()) | |
345 | raise |
|
345 | raise | |
346 |
|
346 | |||
347 | def create_repo(self, repo_name, repo_type, description, owner, |
|
347 | def create_repo(self, repo_name, repo_type, description, owner, | |
348 | private=False, clone_uri=None, repos_group=None, |
|
348 | private=False, clone_uri=None, repos_group=None, | |
349 | landing_rev='tip', just_db=False, fork_of=None, |
|
349 | landing_rev='tip', just_db=False, fork_of=None, | |
350 | copy_fork_permissions=False, enable_statistics=False, |
|
350 | copy_fork_permissions=False, enable_statistics=False, | |
351 | enable_locking=False, enable_downloads=False): |
|
351 | enable_locking=False, enable_downloads=False): | |
352 | """ |
|
352 | """ | |
353 | Create repository |
|
353 | Create repository | |
354 |
|
354 | |||
355 | """ |
|
355 | """ | |
356 | from rhodecode.model.scm import ScmModel |
|
356 | from rhodecode.model.scm import ScmModel | |
357 |
|
357 | |||
358 | owner = self._get_user(owner) |
|
358 | owner = self._get_user(owner) | |
359 | fork_of = self._get_repo(fork_of) |
|
359 | fork_of = self._get_repo(fork_of) | |
360 | repos_group = self._get_repos_group(repos_group) |
|
360 | repos_group = self._get_repos_group(repos_group) | |
361 | try: |
|
361 | try: | |
362 |
|
362 | |||
363 | # repo name is just a name of repository |
|
363 | # repo name is just a name of repository | |
364 | # while repo_name_full is a full qualified name that is combined |
|
364 | # while repo_name_full is a full qualified name that is combined | |
365 | # with name and path of group |
|
365 | # with name and path of group | |
366 | repo_name_full = repo_name |
|
366 | repo_name_full = repo_name | |
367 | repo_name = repo_name.split(self.URL_SEPARATOR)[-1] |
|
367 | repo_name = repo_name.split(self.URL_SEPARATOR)[-1] | |
368 |
|
368 | |||
369 | new_repo = Repository() |
|
369 | new_repo = Repository() | |
370 | new_repo.enable_statistics = False |
|
370 | new_repo.enable_statistics = False | |
371 | new_repo.repo_name = repo_name_full |
|
371 | new_repo.repo_name = repo_name_full | |
372 | new_repo.repo_type = repo_type |
|
372 | new_repo.repo_type = repo_type | |
373 | new_repo.user = owner |
|
373 | new_repo.user = owner | |
374 | new_repo.group = repos_group |
|
374 | new_repo.group = repos_group | |
375 | new_repo.description = description or repo_name |
|
375 | new_repo.description = description or repo_name | |
376 | new_repo.private = private |
|
376 | new_repo.private = private | |
377 | new_repo.clone_uri = clone_uri |
|
377 | new_repo.clone_uri = clone_uri | |
378 | new_repo.landing_rev = landing_rev |
|
378 | new_repo.landing_rev = landing_rev | |
379 |
|
379 | |||
380 | new_repo.enable_statistics = enable_statistics |
|
380 | new_repo.enable_statistics = enable_statistics | |
381 | new_repo.enable_locking = enable_locking |
|
381 | new_repo.enable_locking = enable_locking | |
382 | new_repo.enable_downloads = enable_downloads |
|
382 | new_repo.enable_downloads = enable_downloads | |
383 |
|
383 | |||
384 | if repos_group: |
|
384 | if repos_group: | |
385 | new_repo.enable_locking = repos_group.enable_locking |
|
385 | new_repo.enable_locking = repos_group.enable_locking | |
386 |
|
386 | |||
387 | if fork_of: |
|
387 | if fork_of: | |
388 | parent_repo = fork_of |
|
388 | parent_repo = fork_of | |
389 | new_repo.fork = parent_repo |
|
389 | new_repo.fork = parent_repo | |
390 |
|
390 | |||
391 | self.sa.add(new_repo) |
|
391 | self.sa.add(new_repo) | |
392 |
|
392 | |||
393 | def _create_default_perms(): |
|
393 | def _create_default_perms(): | |
394 | # create default permission |
|
394 | # create default permission | |
395 | repo_to_perm = UserRepoToPerm() |
|
395 | repo_to_perm = UserRepoToPerm() | |
396 | default = 'repository.read' |
|
396 | default = 'repository.read' | |
397 | for p in User.get_by_username('default').user_perms: |
|
397 | for p in User.get_by_username('default').user_perms: | |
398 | if p.permission.permission_name.startswith('repository.'): |
|
398 | if p.permission.permission_name.startswith('repository.'): | |
399 | default = p.permission.permission_name |
|
399 | default = p.permission.permission_name | |
400 | break |
|
400 | break | |
401 |
|
401 | |||
402 | default_perm = 'repository.none' if private else default |
|
402 | default_perm = 'repository.none' if private else default | |
403 |
|
403 | |||
404 | repo_to_perm.permission_id = self.sa.query(Permission)\ |
|
404 | repo_to_perm.permission_id = self.sa.query(Permission)\ | |
405 | .filter(Permission.permission_name == default_perm)\ |
|
405 | .filter(Permission.permission_name == default_perm)\ | |
406 | .one().permission_id |
|
406 | .one().permission_id | |
407 |
|
407 | |||
408 | repo_to_perm.repository = new_repo |
|
408 | repo_to_perm.repository = new_repo | |
409 | repo_to_perm.user_id = User.get_by_username('default').user_id |
|
409 | repo_to_perm.user_id = User.get_by_username('default').user_id | |
410 |
|
410 | |||
411 | self.sa.add(repo_to_perm) |
|
411 | self.sa.add(repo_to_perm) | |
412 |
|
412 | |||
413 | if fork_of: |
|
413 | if fork_of: | |
414 | if copy_fork_permissions: |
|
414 | if copy_fork_permissions: | |
415 | repo = fork_of |
|
415 | repo = fork_of | |
416 | user_perms = UserRepoToPerm.query()\ |
|
416 | user_perms = UserRepoToPerm.query()\ | |
417 | .filter(UserRepoToPerm.repository == repo).all() |
|
417 | .filter(UserRepoToPerm.repository == repo).all() | |
418 | group_perms = UsersGroupRepoToPerm.query()\ |
|
418 | group_perms = UsersGroupRepoToPerm.query()\ | |
419 | .filter(UsersGroupRepoToPerm.repository == repo).all() |
|
419 | .filter(UsersGroupRepoToPerm.repository == repo).all() | |
420 |
|
420 | |||
421 | for perm in user_perms: |
|
421 | for perm in user_perms: | |
422 | UserRepoToPerm.create(perm.user, new_repo, |
|
422 | UserRepoToPerm.create(perm.user, new_repo, | |
423 | perm.permission) |
|
423 | perm.permission) | |
424 |
|
424 | |||
425 | for perm in group_perms: |
|
425 | for perm in group_perms: | |
426 | UsersGroupRepoToPerm.create(perm.users_group, new_repo, |
|
426 | UsersGroupRepoToPerm.create(perm.users_group, new_repo, | |
427 | perm.permission) |
|
427 | perm.permission) | |
428 | else: |
|
428 | else: | |
429 | _create_default_perms() |
|
429 | _create_default_perms() | |
430 | else: |
|
430 | else: | |
431 | _create_default_perms() |
|
431 | _create_default_perms() | |
432 |
|
432 | |||
433 | if not just_db: |
|
433 | if not just_db: | |
434 | self.__create_repo(repo_name, repo_type, |
|
434 | self.__create_repo(repo_name, repo_type, | |
435 | repos_group, |
|
435 | repos_group, | |
436 | clone_uri) |
|
436 | clone_uri) | |
437 | log_create_repository(new_repo.get_dict(), |
|
437 | log_create_repository(new_repo.get_dict(), | |
438 | created_by=owner.username) |
|
438 | created_by=owner.username) | |
439 |
|
439 | |||
440 | # now automatically start following this repository as owner |
|
440 | # now automatically start following this repository as owner | |
441 | ScmModel(self.sa).toggle_following_repo(new_repo.repo_id, |
|
441 | ScmModel(self.sa).toggle_following_repo(new_repo.repo_id, | |
442 | owner.user_id) |
|
442 | owner.user_id) | |
443 | return new_repo |
|
443 | return new_repo | |
444 | except: |
|
444 | except: | |
445 | log.error(traceback.format_exc()) |
|
445 | log.error(traceback.format_exc()) | |
446 | raise |
|
446 | raise | |
447 |
|
447 | |||
448 | def create(self, form_data, cur_user, just_db=False, fork=None): |
|
448 | def create(self, form_data, cur_user, just_db=False, fork=None): | |
449 | """ |
|
449 | """ | |
450 | Backward compatibility function, just a wrapper on top of create_repo |
|
450 | Backward compatibility function, just a wrapper on top of create_repo | |
451 |
|
451 | |||
452 | :param form_data: |
|
452 | :param form_data: | |
453 | :param cur_user: |
|
453 | :param cur_user: | |
454 | :param just_db: |
|
454 | :param just_db: | |
455 | :param fork: |
|
455 | :param fork: | |
456 | """ |
|
456 | """ | |
457 | owner = cur_user |
|
457 | owner = cur_user | |
458 | repo_name = form_data['repo_name_full'] |
|
458 | repo_name = form_data['repo_name_full'] | |
459 | repo_type = form_data['repo_type'] |
|
459 | repo_type = form_data['repo_type'] | |
460 | description = form_data['repo_description'] |
|
460 | description = form_data['repo_description'] | |
461 | private = form_data['repo_private'] |
|
461 | private = form_data['repo_private'] | |
462 | clone_uri = form_data.get('clone_uri') |
|
462 | clone_uri = form_data.get('clone_uri') | |
463 | repos_group = form_data['repo_group'] |
|
463 | repos_group = form_data['repo_group'] | |
464 | landing_rev = form_data['repo_landing_rev'] |
|
464 | landing_rev = form_data['repo_landing_rev'] | |
465 | copy_fork_permissions = form_data.get('copy_permissions') |
|
465 | copy_fork_permissions = form_data.get('copy_permissions') | |
466 | fork_of = form_data.get('fork_parent_id') |
|
466 | fork_of = form_data.get('fork_parent_id') | |
467 |
|
467 | |||
468 | ## repo creation defaults, private and repo_type are filled in form |
|
468 | ## repo creation defaults, private and repo_type are filled in form | |
469 | defs = RhodeCodeSetting.get_default_repo_settings(strip_prefix=True) |
|
469 | defs = RhodeCodeSetting.get_default_repo_settings(strip_prefix=True) | |
470 | enable_statistics = defs.get('repo_enable_statistics') |
|
470 | enable_statistics = defs.get('repo_enable_statistics') | |
471 | enable_locking = defs.get('repo_enable_locking') |
|
471 | enable_locking = defs.get('repo_enable_locking') | |
472 | enable_downloads = defs.get('repo_enable_downloads') |
|
472 | enable_downloads = defs.get('repo_enable_downloads') | |
473 |
|
473 | |||
474 | return self.create_repo( |
|
474 | return self.create_repo( | |
475 | repo_name, repo_type, description, owner, private, clone_uri, |
|
475 | repo_name, repo_type, description, owner, private, clone_uri, | |
476 | repos_group, landing_rev, just_db, fork_of, copy_fork_permissions, |
|
476 | repos_group, landing_rev, just_db, fork_of, copy_fork_permissions, | |
477 | enable_statistics, enable_locking, enable_downloads |
|
477 | enable_statistics, enable_locking, enable_downloads | |
478 | ) |
|
478 | ) | |
479 |
|
479 | |||
480 | def create_fork(self, form_data, cur_user): |
|
480 | def create_fork(self, form_data, cur_user): | |
481 | """ |
|
481 | """ | |
482 | Simple wrapper into executing celery task for fork creation |
|
482 | Simple wrapper into executing celery task for fork creation | |
483 |
|
483 | |||
484 | :param form_data: |
|
484 | :param form_data: | |
485 | :param cur_user: |
|
485 | :param cur_user: | |
486 | """ |
|
486 | """ | |
487 | from rhodecode.lib.celerylib import tasks, run_task |
|
487 | from rhodecode.lib.celerylib import tasks, run_task | |
488 | run_task(tasks.create_repo_fork, form_data, cur_user) |
|
488 | run_task(tasks.create_repo_fork, form_data, cur_user) | |
489 |
|
489 | |||
490 | def delete(self, repo): |
|
490 | def delete(self, repo): | |
491 | repo = self._get_repo(repo) |
|
491 | repo = self._get_repo(repo) | |
492 | if repo: |
|
492 | if repo: | |
493 | old_repo_dict = repo.get_dict() |
|
493 | old_repo_dict = repo.get_dict() | |
494 | owner = repo.user |
|
494 | owner = repo.user | |
495 | try: |
|
495 | try: | |
496 | self.sa.delete(repo) |
|
496 | self.sa.delete(repo) | |
497 | self.__delete_repo(repo) |
|
497 | self.__delete_repo(repo) | |
498 | log_delete_repository(old_repo_dict, |
|
498 | log_delete_repository(old_repo_dict, | |
499 | deleted_by=owner.username) |
|
499 | deleted_by=owner.username) | |
500 | except: |
|
500 | except: | |
501 | log.error(traceback.format_exc()) |
|
501 | log.error(traceback.format_exc()) | |
502 | raise |
|
502 | raise | |
503 |
|
503 | |||
504 | def grant_user_permission(self, repo, user, perm): |
|
504 | def grant_user_permission(self, repo, user, perm): | |
505 | """ |
|
505 | """ | |
506 | Grant permission for user on given repository, or update existing one |
|
506 | Grant permission for user on given repository, or update existing one | |
507 | if found |
|
507 | if found | |
508 |
|
508 | |||
509 | :param repo: Instance of Repository, repository_id, or repository name |
|
509 | :param repo: Instance of Repository, repository_id, or repository name | |
510 | :param user: Instance of User, user_id or username |
|
510 | :param user: Instance of User, user_id or username | |
511 | :param perm: Instance of Permission, or permission_name |
|
511 | :param perm: Instance of Permission, or permission_name | |
512 | """ |
|
512 | """ | |
513 | user = self._get_user(user) |
|
513 | user = self._get_user(user) | |
514 | repo = self._get_repo(repo) |
|
514 | repo = self._get_repo(repo) | |
515 | permission = self._get_perm(perm) |
|
515 | permission = self._get_perm(perm) | |
516 |
|
516 | |||
517 | # check if we have that permission already |
|
517 | # check if we have that permission already | |
518 | obj = self.sa.query(UserRepoToPerm)\ |
|
518 | obj = self.sa.query(UserRepoToPerm)\ | |
519 | .filter(UserRepoToPerm.user == user)\ |
|
519 | .filter(UserRepoToPerm.user == user)\ | |
520 | .filter(UserRepoToPerm.repository == repo)\ |
|
520 | .filter(UserRepoToPerm.repository == repo)\ | |
521 | .scalar() |
|
521 | .scalar() | |
522 | if obj is None: |
|
522 | if obj is None: | |
523 | # create new ! |
|
523 | # create new ! | |
524 | obj = UserRepoToPerm() |
|
524 | obj = UserRepoToPerm() | |
525 | obj.repository = repo |
|
525 | obj.repository = repo | |
526 | obj.user = user |
|
526 | obj.user = user | |
527 | obj.permission = permission |
|
527 | obj.permission = permission | |
528 | self.sa.add(obj) |
|
528 | self.sa.add(obj) | |
529 | log.debug('Granted perm %s to %s on %s' % (perm, user, repo)) |
|
529 | log.debug('Granted perm %s to %s on %s' % (perm, user, repo)) | |
530 |
|
530 | |||
531 | def revoke_user_permission(self, repo, user): |
|
531 | def revoke_user_permission(self, repo, user): | |
532 | """ |
|
532 | """ | |
533 | Revoke permission for user on given repository |
|
533 | Revoke permission for user on given repository | |
534 |
|
534 | |||
535 | :param repo: Instance of Repository, repository_id, or repository name |
|
535 | :param repo: Instance of Repository, repository_id, or repository name | |
536 | :param user: Instance of User, user_id or username |
|
536 | :param user: Instance of User, user_id or username | |
537 | """ |
|
537 | """ | |
538 |
|
538 | |||
539 | user = self._get_user(user) |
|
539 | user = self._get_user(user) | |
540 | repo = self._get_repo(repo) |
|
540 | repo = self._get_repo(repo) | |
541 |
|
541 | |||
542 | obj = self.sa.query(UserRepoToPerm)\ |
|
542 | obj = self.sa.query(UserRepoToPerm)\ | |
543 | .filter(UserRepoToPerm.repository == repo)\ |
|
543 | .filter(UserRepoToPerm.repository == repo)\ | |
544 | .filter(UserRepoToPerm.user == user)\ |
|
544 | .filter(UserRepoToPerm.user == user)\ | |
545 | .scalar() |
|
545 | .scalar() | |
546 | if obj: |
|
546 | if obj: | |
547 | self.sa.delete(obj) |
|
547 | self.sa.delete(obj) | |
548 | log.debug('Revoked perm on %s on %s' % (repo, user)) |
|
548 | log.debug('Revoked perm on %s on %s' % (repo, user)) | |
549 |
|
549 | |||
550 | def grant_users_group_permission(self, repo, group_name, perm): |
|
550 | def grant_users_group_permission(self, repo, group_name, perm): | |
551 | """ |
|
551 | """ | |
552 |
Grant permission for user |
|
552 | Grant permission for user group on given repository, or update | |
553 | existing one if found |
|
553 | existing one if found | |
554 |
|
554 | |||
555 | :param repo: Instance of Repository, repository_id, or repository name |
|
555 | :param repo: Instance of Repository, repository_id, or repository name | |
556 | :param group_name: Instance of UserGroup, users_group_id, |
|
556 | :param group_name: Instance of UserGroup, users_group_id, | |
557 |
or user |
|
557 | or user group name | |
558 | :param perm: Instance of Permission, or permission_name |
|
558 | :param perm: Instance of Permission, or permission_name | |
559 | """ |
|
559 | """ | |
560 | repo = self._get_repo(repo) |
|
560 | repo = self._get_repo(repo) | |
561 | group_name = self.__get_users_group(group_name) |
|
561 | group_name = self.__get_users_group(group_name) | |
562 | permission = self._get_perm(perm) |
|
562 | permission = self._get_perm(perm) | |
563 |
|
563 | |||
564 | # check if we have that permission already |
|
564 | # check if we have that permission already | |
565 | obj = self.sa.query(UsersGroupRepoToPerm)\ |
|
565 | obj = self.sa.query(UsersGroupRepoToPerm)\ | |
566 | .filter(UsersGroupRepoToPerm.users_group == group_name)\ |
|
566 | .filter(UsersGroupRepoToPerm.users_group == group_name)\ | |
567 | .filter(UsersGroupRepoToPerm.repository == repo)\ |
|
567 | .filter(UsersGroupRepoToPerm.repository == repo)\ | |
568 | .scalar() |
|
568 | .scalar() | |
569 |
|
569 | |||
570 | if obj is None: |
|
570 | if obj is None: | |
571 | # create new |
|
571 | # create new | |
572 | obj = UsersGroupRepoToPerm() |
|
572 | obj = UsersGroupRepoToPerm() | |
573 |
|
573 | |||
574 | obj.repository = repo |
|
574 | obj.repository = repo | |
575 | obj.users_group = group_name |
|
575 | obj.users_group = group_name | |
576 | obj.permission = permission |
|
576 | obj.permission = permission | |
577 | self.sa.add(obj) |
|
577 | self.sa.add(obj) | |
578 | log.debug('Granted perm %s to %s on %s' % (perm, group_name, repo)) |
|
578 | log.debug('Granted perm %s to %s on %s' % (perm, group_name, repo)) | |
579 |
|
579 | |||
580 | def revoke_users_group_permission(self, repo, group_name): |
|
580 | def revoke_users_group_permission(self, repo, group_name): | |
581 | """ |
|
581 | """ | |
582 |
Revoke permission for user |
|
582 | Revoke permission for user group on given repository | |
583 |
|
583 | |||
584 | :param repo: Instance of Repository, repository_id, or repository name |
|
584 | :param repo: Instance of Repository, repository_id, or repository name | |
585 | :param group_name: Instance of UserGroup, users_group_id, |
|
585 | :param group_name: Instance of UserGroup, users_group_id, | |
586 |
or user |
|
586 | or user group name | |
587 | """ |
|
587 | """ | |
588 | repo = self._get_repo(repo) |
|
588 | repo = self._get_repo(repo) | |
589 | group_name = self.__get_users_group(group_name) |
|
589 | group_name = self.__get_users_group(group_name) | |
590 |
|
590 | |||
591 | obj = self.sa.query(UsersGroupRepoToPerm)\ |
|
591 | obj = self.sa.query(UsersGroupRepoToPerm)\ | |
592 | .filter(UsersGroupRepoToPerm.repository == repo)\ |
|
592 | .filter(UsersGroupRepoToPerm.repository == repo)\ | |
593 | .filter(UsersGroupRepoToPerm.users_group == group_name)\ |
|
593 | .filter(UsersGroupRepoToPerm.users_group == group_name)\ | |
594 | .scalar() |
|
594 | .scalar() | |
595 | if obj: |
|
595 | if obj: | |
596 | self.sa.delete(obj) |
|
596 | self.sa.delete(obj) | |
597 | log.debug('Revoked perm to %s on %s' % (repo, group_name)) |
|
597 | log.debug('Revoked perm to %s on %s' % (repo, group_name)) | |
598 |
|
598 | |||
599 | def delete_stats(self, repo_name): |
|
599 | def delete_stats(self, repo_name): | |
600 | """ |
|
600 | """ | |
601 | removes stats for given repo |
|
601 | removes stats for given repo | |
602 |
|
602 | |||
603 | :param repo_name: |
|
603 | :param repo_name: | |
604 | """ |
|
604 | """ | |
605 | repo = self._get_repo(repo_name) |
|
605 | repo = self._get_repo(repo_name) | |
606 | try: |
|
606 | try: | |
607 | obj = self.sa.query(Statistics)\ |
|
607 | obj = self.sa.query(Statistics)\ | |
608 | .filter(Statistics.repository == repo).scalar() |
|
608 | .filter(Statistics.repository == repo).scalar() | |
609 | if obj: |
|
609 | if obj: | |
610 | self.sa.delete(obj) |
|
610 | self.sa.delete(obj) | |
611 | except: |
|
611 | except: | |
612 | log.error(traceback.format_exc()) |
|
612 | log.error(traceback.format_exc()) | |
613 | raise |
|
613 | raise | |
614 |
|
614 | |||
615 | def __create_repo(self, repo_name, alias, parent, clone_uri=False): |
|
615 | def __create_repo(self, repo_name, alias, parent, clone_uri=False): | |
616 | """ |
|
616 | """ | |
617 | makes repository on filesystem. It's group aware means it'll create |
|
617 | makes repository on filesystem. It's group aware means it'll create | |
618 | a repository within a group, and alter the paths accordingly of |
|
618 | a repository within a group, and alter the paths accordingly of | |
619 | group location |
|
619 | group location | |
620 |
|
620 | |||
621 | :param repo_name: |
|
621 | :param repo_name: | |
622 | :param alias: |
|
622 | :param alias: | |
623 | :param parent_id: |
|
623 | :param parent_id: | |
624 | :param clone_uri: |
|
624 | :param clone_uri: | |
625 | """ |
|
625 | """ | |
626 | from rhodecode.lib.utils import is_valid_repo, is_valid_repos_group |
|
626 | from rhodecode.lib.utils import is_valid_repo, is_valid_repos_group | |
627 | from rhodecode.model.scm import ScmModel |
|
627 | from rhodecode.model.scm import ScmModel | |
628 |
|
628 | |||
629 | if parent: |
|
629 | if parent: | |
630 | new_parent_path = os.sep.join(parent.full_path_splitted) |
|
630 | new_parent_path = os.sep.join(parent.full_path_splitted) | |
631 | else: |
|
631 | else: | |
632 | new_parent_path = '' |
|
632 | new_parent_path = '' | |
633 |
|
633 | |||
634 | # we need to make it str for mercurial |
|
634 | # we need to make it str for mercurial | |
635 | repo_path = os.path.join(*map(lambda x: safe_str(x), |
|
635 | repo_path = os.path.join(*map(lambda x: safe_str(x), | |
636 | [self.repos_path, new_parent_path, repo_name])) |
|
636 | [self.repos_path, new_parent_path, repo_name])) | |
637 |
|
637 | |||
638 | # check if this path is not a repository |
|
638 | # check if this path is not a repository | |
639 | if is_valid_repo(repo_path, self.repos_path): |
|
639 | if is_valid_repo(repo_path, self.repos_path): | |
640 | raise Exception('This path %s is a valid repository' % repo_path) |
|
640 | raise Exception('This path %s is a valid repository' % repo_path) | |
641 |
|
641 | |||
642 | # check if this path is a group |
|
642 | # check if this path is a group | |
643 | if is_valid_repos_group(repo_path, self.repos_path): |
|
643 | if is_valid_repos_group(repo_path, self.repos_path): | |
644 | raise Exception('This path %s is a valid group' % repo_path) |
|
644 | raise Exception('This path %s is a valid group' % repo_path) | |
645 |
|
645 | |||
646 | log.info('creating repo %s in %s @ %s' % ( |
|
646 | log.info('creating repo %s in %s @ %s' % ( | |
647 | repo_name, safe_unicode(repo_path), clone_uri |
|
647 | repo_name, safe_unicode(repo_path), clone_uri | |
648 | ) |
|
648 | ) | |
649 | ) |
|
649 | ) | |
650 | backend = get_backend(alias) |
|
650 | backend = get_backend(alias) | |
651 | if alias == 'hg': |
|
651 | if alias == 'hg': | |
652 | backend(repo_path, create=True, src_url=clone_uri) |
|
652 | backend(repo_path, create=True, src_url=clone_uri) | |
653 | elif alias == 'git': |
|
653 | elif alias == 'git': | |
654 | r = backend(repo_path, create=True, src_url=clone_uri, bare=True) |
|
654 | r = backend(repo_path, create=True, src_url=clone_uri, bare=True) | |
655 | # add rhodecode hook into this repo |
|
655 | # add rhodecode hook into this repo | |
656 | ScmModel().install_git_hook(repo=r) |
|
656 | ScmModel().install_git_hook(repo=r) | |
657 | else: |
|
657 | else: | |
658 | raise Exception('Undefined alias %s' % alias) |
|
658 | raise Exception('Undefined alias %s' % alias) | |
659 |
|
659 | |||
660 | def __rename_repo(self, old, new): |
|
660 | def __rename_repo(self, old, new): | |
661 | """ |
|
661 | """ | |
662 | renames repository on filesystem |
|
662 | renames repository on filesystem | |
663 |
|
663 | |||
664 | :param old: old name |
|
664 | :param old: old name | |
665 | :param new: new name |
|
665 | :param new: new name | |
666 | """ |
|
666 | """ | |
667 | log.info('renaming repo from %s to %s' % (old, new)) |
|
667 | log.info('renaming repo from %s to %s' % (old, new)) | |
668 |
|
668 | |||
669 | old_path = os.path.join(self.repos_path, old) |
|
669 | old_path = os.path.join(self.repos_path, old) | |
670 | new_path = os.path.join(self.repos_path, new) |
|
670 | new_path = os.path.join(self.repos_path, new) | |
671 | if os.path.isdir(new_path): |
|
671 | if os.path.isdir(new_path): | |
672 | raise Exception( |
|
672 | raise Exception( | |
673 | 'Was trying to rename to already existing dir %s' % new_path |
|
673 | 'Was trying to rename to already existing dir %s' % new_path | |
674 | ) |
|
674 | ) | |
675 | shutil.move(old_path, new_path) |
|
675 | shutil.move(old_path, new_path) | |
676 |
|
676 | |||
677 | def __delete_repo(self, repo): |
|
677 | def __delete_repo(self, repo): | |
678 | """ |
|
678 | """ | |
679 | removes repo from filesystem, the removal is acctually made by |
|
679 | removes repo from filesystem, the removal is acctually made by | |
680 | added rm__ prefix into dir, and rename internat .hg/.git dirs so this |
|
680 | added rm__ prefix into dir, and rename internat .hg/.git dirs so this | |
681 | repository is no longer valid for rhodecode, can be undeleted later on |
|
681 | repository is no longer valid for rhodecode, can be undeleted later on | |
682 | by reverting the renames on this repository |
|
682 | by reverting the renames on this repository | |
683 |
|
683 | |||
684 | :param repo: repo object |
|
684 | :param repo: repo object | |
685 | """ |
|
685 | """ | |
686 | rm_path = os.path.join(self.repos_path, repo.repo_name) |
|
686 | rm_path = os.path.join(self.repos_path, repo.repo_name) | |
687 | log.info("Removing %s" % (rm_path)) |
|
687 | log.info("Removing %s" % (rm_path)) | |
688 | # disable hg/git internal that it doesn't get detected as repo |
|
688 | # disable hg/git internal that it doesn't get detected as repo | |
689 | alias = repo.repo_type |
|
689 | alias = repo.repo_type | |
690 |
|
690 | |||
691 | bare = getattr(repo.scm_instance, 'bare', False) |
|
691 | bare = getattr(repo.scm_instance, 'bare', False) | |
692 |
|
692 | |||
693 | if not bare: |
|
693 | if not bare: | |
694 | # skip this for bare git repos |
|
694 | # skip this for bare git repos | |
695 | shutil.move(os.path.join(rm_path, '.%s' % alias), |
|
695 | shutil.move(os.path.join(rm_path, '.%s' % alias), | |
696 | os.path.join(rm_path, 'rm__.%s' % alias)) |
|
696 | os.path.join(rm_path, 'rm__.%s' % alias)) | |
697 | # disable repo |
|
697 | # disable repo | |
698 | _now = datetime.now() |
|
698 | _now = datetime.now() | |
699 | _ms = str(_now.microsecond).rjust(6, '0') |
|
699 | _ms = str(_now.microsecond).rjust(6, '0') | |
700 | _d = 'rm__%s__%s' % (_now.strftime('%Y%m%d_%H%M%S_' + _ms), |
|
700 | _d = 'rm__%s__%s' % (_now.strftime('%Y%m%d_%H%M%S_' + _ms), | |
701 | repo.just_name) |
|
701 | repo.just_name) | |
702 | if repo.group: |
|
702 | if repo.group: | |
703 | args = repo.group.full_path_splitted + [_d] |
|
703 | args = repo.group.full_path_splitted + [_d] | |
704 | _d = os.path.join(*args) |
|
704 | _d = os.path.join(*args) | |
705 | shutil.move(rm_path, os.path.join(self.repos_path, _d)) |
|
705 | shutil.move(rm_path, os.path.join(self.repos_path, _d)) |
@@ -1,763 +1,763 b'' | |||||
1 | # -*- coding: utf-8 -*- |
|
1 | # -*- coding: utf-8 -*- | |
2 | """ |
|
2 | """ | |
3 | rhodecode.model.user |
|
3 | rhodecode.model.user | |
4 | ~~~~~~~~~~~~~~~~~~~~ |
|
4 | ~~~~~~~~~~~~~~~~~~~~ | |
5 |
|
5 | |||
6 | users model for RhodeCode |
|
6 | users model for RhodeCode | |
7 |
|
7 | |||
8 | :created_on: Apr 9, 2010 |
|
8 | :created_on: Apr 9, 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 logging |
|
26 | import logging | |
27 | import traceback |
|
27 | import traceback | |
28 | import itertools |
|
28 | import itertools | |
29 | import collections |
|
29 | import collections | |
30 | from pylons import url |
|
30 | from pylons import url | |
31 | from pylons.i18n.translation import _ |
|
31 | from pylons.i18n.translation import _ | |
32 |
|
32 | |||
33 | from sqlalchemy.exc import DatabaseError |
|
33 | from sqlalchemy.exc import DatabaseError | |
34 | from sqlalchemy.orm import joinedload |
|
34 | from sqlalchemy.orm import joinedload | |
35 |
|
35 | |||
36 | from rhodecode.lib.utils2 import safe_unicode, generate_api_key |
|
36 | from rhodecode.lib.utils2 import safe_unicode, generate_api_key | |
37 | from rhodecode.lib.caching_query import FromCache |
|
37 | from rhodecode.lib.caching_query import FromCache | |
38 | from rhodecode.model import BaseModel |
|
38 | from rhodecode.model import BaseModel | |
39 | from rhodecode.model.db import User, UserRepoToPerm, Repository, Permission, \ |
|
39 | from rhodecode.model.db import User, UserRepoToPerm, Repository, Permission, \ | |
40 | UserToPerm, UsersGroupRepoToPerm, UsersGroupToPerm, UsersGroupMember, \ |
|
40 | UserToPerm, UsersGroupRepoToPerm, UsersGroupToPerm, UsersGroupMember, \ | |
41 | Notification, RepoGroup, UserRepoGroupToPerm, UsersGroupRepoGroupToPerm, \ |
|
41 | Notification, RepoGroup, UserRepoGroupToPerm, UsersGroupRepoGroupToPerm, \ | |
42 | UserEmailMap, UserIpMap |
|
42 | UserEmailMap, UserIpMap | |
43 | from rhodecode.lib.exceptions import DefaultUserException, \ |
|
43 | from rhodecode.lib.exceptions import DefaultUserException, \ | |
44 | UserOwnsReposException |
|
44 | UserOwnsReposException | |
45 | from rhodecode.model.meta import Session |
|
45 | from rhodecode.model.meta import Session | |
46 |
|
46 | |||
47 |
|
47 | |||
48 | log = logging.getLogger(__name__) |
|
48 | log = logging.getLogger(__name__) | |
49 |
|
49 | |||
50 | PERM_WEIGHTS = Permission.PERM_WEIGHTS |
|
50 | PERM_WEIGHTS = Permission.PERM_WEIGHTS | |
51 |
|
51 | |||
52 |
|
52 | |||
53 | class UserModel(BaseModel): |
|
53 | class UserModel(BaseModel): | |
54 | cls = User |
|
54 | cls = User | |
55 |
|
55 | |||
56 | def get(self, user_id, cache=False): |
|
56 | def get(self, user_id, cache=False): | |
57 | user = self.sa.query(User) |
|
57 | user = self.sa.query(User) | |
58 | if cache: |
|
58 | if cache: | |
59 | user = user.options(FromCache("sql_cache_short", |
|
59 | user = user.options(FromCache("sql_cache_short", | |
60 | "get_user_%s" % user_id)) |
|
60 | "get_user_%s" % user_id)) | |
61 | return user.get(user_id) |
|
61 | return user.get(user_id) | |
62 |
|
62 | |||
63 | def get_user(self, user): |
|
63 | def get_user(self, user): | |
64 | return self._get_user(user) |
|
64 | return self._get_user(user) | |
65 |
|
65 | |||
66 | def get_by_username(self, username, cache=False, case_insensitive=False): |
|
66 | def get_by_username(self, username, cache=False, case_insensitive=False): | |
67 |
|
67 | |||
68 | if case_insensitive: |
|
68 | if case_insensitive: | |
69 | user = self.sa.query(User).filter(User.username.ilike(username)) |
|
69 | user = self.sa.query(User).filter(User.username.ilike(username)) | |
70 | else: |
|
70 | else: | |
71 | user = self.sa.query(User)\ |
|
71 | user = self.sa.query(User)\ | |
72 | .filter(User.username == username) |
|
72 | .filter(User.username == username) | |
73 | if cache: |
|
73 | if cache: | |
74 | user = user.options(FromCache("sql_cache_short", |
|
74 | user = user.options(FromCache("sql_cache_short", | |
75 | "get_user_%s" % username)) |
|
75 | "get_user_%s" % username)) | |
76 | return user.scalar() |
|
76 | return user.scalar() | |
77 |
|
77 | |||
78 | def get_by_email(self, email, cache=False, case_insensitive=False): |
|
78 | def get_by_email(self, email, cache=False, case_insensitive=False): | |
79 | return User.get_by_email(email, case_insensitive, cache) |
|
79 | return User.get_by_email(email, case_insensitive, cache) | |
80 |
|
80 | |||
81 | def get_by_api_key(self, api_key, cache=False): |
|
81 | def get_by_api_key(self, api_key, cache=False): | |
82 | return User.get_by_api_key(api_key, cache) |
|
82 | return User.get_by_api_key(api_key, cache) | |
83 |
|
83 | |||
84 | def create(self, form_data): |
|
84 | def create(self, form_data): | |
85 | from rhodecode.lib.auth import get_crypt_password |
|
85 | from rhodecode.lib.auth import get_crypt_password | |
86 | try: |
|
86 | try: | |
87 | new_user = User() |
|
87 | new_user = User() | |
88 | for k, v in form_data.items(): |
|
88 | for k, v in form_data.items(): | |
89 | if k == 'password': |
|
89 | if k == 'password': | |
90 | v = get_crypt_password(v) |
|
90 | v = get_crypt_password(v) | |
91 | if k == 'firstname': |
|
91 | if k == 'firstname': | |
92 | k = 'name' |
|
92 | k = 'name' | |
93 | setattr(new_user, k, v) |
|
93 | setattr(new_user, k, v) | |
94 |
|
94 | |||
95 | new_user.api_key = generate_api_key(form_data['username']) |
|
95 | new_user.api_key = generate_api_key(form_data['username']) | |
96 | self.sa.add(new_user) |
|
96 | self.sa.add(new_user) | |
97 | return new_user |
|
97 | return new_user | |
98 | except: |
|
98 | except: | |
99 | log.error(traceback.format_exc()) |
|
99 | log.error(traceback.format_exc()) | |
100 | raise |
|
100 | raise | |
101 |
|
101 | |||
102 | def create_or_update(self, username, password, email, firstname='', |
|
102 | def create_or_update(self, username, password, email, firstname='', | |
103 | lastname='', active=True, admin=False, ldap_dn=None): |
|
103 | lastname='', active=True, admin=False, ldap_dn=None): | |
104 | """ |
|
104 | """ | |
105 | Creates a new instance if not found, or updates current one |
|
105 | Creates a new instance if not found, or updates current one | |
106 |
|
106 | |||
107 | :param username: |
|
107 | :param username: | |
108 | :param password: |
|
108 | :param password: | |
109 | :param email: |
|
109 | :param email: | |
110 | :param active: |
|
110 | :param active: | |
111 | :param firstname: |
|
111 | :param firstname: | |
112 | :param lastname: |
|
112 | :param lastname: | |
113 | :param active: |
|
113 | :param active: | |
114 | :param admin: |
|
114 | :param admin: | |
115 | :param ldap_dn: |
|
115 | :param ldap_dn: | |
116 | """ |
|
116 | """ | |
117 |
|
117 | |||
118 | from rhodecode.lib.auth import get_crypt_password |
|
118 | from rhodecode.lib.auth import get_crypt_password | |
119 |
|
119 | |||
120 | log.debug('Checking for %s account in RhodeCode database' % username) |
|
120 | log.debug('Checking for %s account in RhodeCode database' % username) | |
121 | user = User.get_by_username(username, case_insensitive=True) |
|
121 | user = User.get_by_username(username, case_insensitive=True) | |
122 | if user is None: |
|
122 | if user is None: | |
123 | log.debug('creating new user %s' % username) |
|
123 | log.debug('creating new user %s' % username) | |
124 | new_user = User() |
|
124 | new_user = User() | |
125 | edit = False |
|
125 | edit = False | |
126 | else: |
|
126 | else: | |
127 | log.debug('updating user %s' % username) |
|
127 | log.debug('updating user %s' % username) | |
128 | new_user = user |
|
128 | new_user = user | |
129 | edit = True |
|
129 | edit = True | |
130 |
|
130 | |||
131 | try: |
|
131 | try: | |
132 | new_user.username = username |
|
132 | new_user.username = username | |
133 | new_user.admin = admin |
|
133 | new_user.admin = admin | |
134 | # set password only if creating an user or password is changed |
|
134 | # set password only if creating an user or password is changed | |
135 | if edit is False or user.password != password: |
|
135 | if edit is False or user.password != password: | |
136 | new_user.password = get_crypt_password(password) |
|
136 | new_user.password = get_crypt_password(password) | |
137 | new_user.api_key = generate_api_key(username) |
|
137 | new_user.api_key = generate_api_key(username) | |
138 | new_user.email = email |
|
138 | new_user.email = email | |
139 | new_user.active = active |
|
139 | new_user.active = active | |
140 | new_user.ldap_dn = safe_unicode(ldap_dn) if ldap_dn else None |
|
140 | new_user.ldap_dn = safe_unicode(ldap_dn) if ldap_dn else None | |
141 | new_user.name = firstname |
|
141 | new_user.name = firstname | |
142 | new_user.lastname = lastname |
|
142 | new_user.lastname = lastname | |
143 | self.sa.add(new_user) |
|
143 | self.sa.add(new_user) | |
144 | return new_user |
|
144 | return new_user | |
145 | except (DatabaseError,): |
|
145 | except (DatabaseError,): | |
146 | log.error(traceback.format_exc()) |
|
146 | log.error(traceback.format_exc()) | |
147 | raise |
|
147 | raise | |
148 |
|
148 | |||
149 | def create_for_container_auth(self, username, attrs): |
|
149 | def create_for_container_auth(self, username, attrs): | |
150 | """ |
|
150 | """ | |
151 | Creates the given user if it's not already in the database |
|
151 | Creates the given user if it's not already in the database | |
152 |
|
152 | |||
153 | :param username: |
|
153 | :param username: | |
154 | :param attrs: |
|
154 | :param attrs: | |
155 | """ |
|
155 | """ | |
156 | if self.get_by_username(username, case_insensitive=True) is None: |
|
156 | if self.get_by_username(username, case_insensitive=True) is None: | |
157 |
|
157 | |||
158 | # autogenerate email for container account without one |
|
158 | # autogenerate email for container account without one | |
159 | generate_email = lambda usr: '%s@container_auth.account' % usr |
|
159 | generate_email = lambda usr: '%s@container_auth.account' % usr | |
160 |
|
160 | |||
161 | try: |
|
161 | try: | |
162 | new_user = User() |
|
162 | new_user = User() | |
163 | new_user.username = username |
|
163 | new_user.username = username | |
164 | new_user.password = None |
|
164 | new_user.password = None | |
165 | new_user.api_key = generate_api_key(username) |
|
165 | new_user.api_key = generate_api_key(username) | |
166 | new_user.email = attrs['email'] |
|
166 | new_user.email = attrs['email'] | |
167 | new_user.active = attrs.get('active', True) |
|
167 | new_user.active = attrs.get('active', True) | |
168 | new_user.name = attrs['name'] or generate_email(username) |
|
168 | new_user.name = attrs['name'] or generate_email(username) | |
169 | new_user.lastname = attrs['lastname'] |
|
169 | new_user.lastname = attrs['lastname'] | |
170 |
|
170 | |||
171 | self.sa.add(new_user) |
|
171 | self.sa.add(new_user) | |
172 | return new_user |
|
172 | return new_user | |
173 | except (DatabaseError,): |
|
173 | except (DatabaseError,): | |
174 | log.error(traceback.format_exc()) |
|
174 | log.error(traceback.format_exc()) | |
175 | self.sa.rollback() |
|
175 | self.sa.rollback() | |
176 | raise |
|
176 | raise | |
177 | log.debug('User %s already exists. Skipping creation of account' |
|
177 | log.debug('User %s already exists. Skipping creation of account' | |
178 | ' for container auth.', username) |
|
178 | ' for container auth.', username) | |
179 | return None |
|
179 | return None | |
180 |
|
180 | |||
181 | def create_ldap(self, username, password, user_dn, attrs): |
|
181 | def create_ldap(self, username, password, user_dn, attrs): | |
182 | """ |
|
182 | """ | |
183 | Checks if user is in database, if not creates this user marked |
|
183 | Checks if user is in database, if not creates this user marked | |
184 | as ldap user |
|
184 | as ldap user | |
185 |
|
185 | |||
186 | :param username: |
|
186 | :param username: | |
187 | :param password: |
|
187 | :param password: | |
188 | :param user_dn: |
|
188 | :param user_dn: | |
189 | :param attrs: |
|
189 | :param attrs: | |
190 | """ |
|
190 | """ | |
191 | from rhodecode.lib.auth import get_crypt_password |
|
191 | from rhodecode.lib.auth import get_crypt_password | |
192 | log.debug('Checking for such ldap account in RhodeCode database') |
|
192 | log.debug('Checking for such ldap account in RhodeCode database') | |
193 | if self.get_by_username(username, case_insensitive=True) is None: |
|
193 | if self.get_by_username(username, case_insensitive=True) is None: | |
194 |
|
194 | |||
195 | # autogenerate email for ldap account without one |
|
195 | # autogenerate email for ldap account without one | |
196 | generate_email = lambda usr: '%s@ldap.account' % usr |
|
196 | generate_email = lambda usr: '%s@ldap.account' % usr | |
197 |
|
197 | |||
198 | try: |
|
198 | try: | |
199 | new_user = User() |
|
199 | new_user = User() | |
200 | username = username.lower() |
|
200 | username = username.lower() | |
201 | # add ldap account always lowercase |
|
201 | # add ldap account always lowercase | |
202 | new_user.username = username |
|
202 | new_user.username = username | |
203 | new_user.password = get_crypt_password(password) |
|
203 | new_user.password = get_crypt_password(password) | |
204 | new_user.api_key = generate_api_key(username) |
|
204 | new_user.api_key = generate_api_key(username) | |
205 | new_user.email = attrs['email'] or generate_email(username) |
|
205 | new_user.email = attrs['email'] or generate_email(username) | |
206 | new_user.active = attrs.get('active', True) |
|
206 | new_user.active = attrs.get('active', True) | |
207 | new_user.ldap_dn = safe_unicode(user_dn) |
|
207 | new_user.ldap_dn = safe_unicode(user_dn) | |
208 | new_user.name = attrs['name'] |
|
208 | new_user.name = attrs['name'] | |
209 | new_user.lastname = attrs['lastname'] |
|
209 | new_user.lastname = attrs['lastname'] | |
210 |
|
210 | |||
211 | self.sa.add(new_user) |
|
211 | self.sa.add(new_user) | |
212 | return new_user |
|
212 | return new_user | |
213 | except (DatabaseError,): |
|
213 | except (DatabaseError,): | |
214 | log.error(traceback.format_exc()) |
|
214 | log.error(traceback.format_exc()) | |
215 | self.sa.rollback() |
|
215 | self.sa.rollback() | |
216 | raise |
|
216 | raise | |
217 | log.debug('this %s user exists skipping creation of ldap account', |
|
217 | log.debug('this %s user exists skipping creation of ldap account', | |
218 | username) |
|
218 | username) | |
219 | return None |
|
219 | return None | |
220 |
|
220 | |||
221 | def create_registration(self, form_data): |
|
221 | def create_registration(self, form_data): | |
222 | from rhodecode.model.notification import NotificationModel |
|
222 | from rhodecode.model.notification import NotificationModel | |
223 |
|
223 | |||
224 | try: |
|
224 | try: | |
225 | form_data['admin'] = False |
|
225 | form_data['admin'] = False | |
226 | new_user = self.create(form_data) |
|
226 | new_user = self.create(form_data) | |
227 |
|
227 | |||
228 | self.sa.add(new_user) |
|
228 | self.sa.add(new_user) | |
229 | self.sa.flush() |
|
229 | self.sa.flush() | |
230 |
|
230 | |||
231 | # notification to admins |
|
231 | # notification to admins | |
232 | subject = _('new user registration') |
|
232 | subject = _('new user registration') | |
233 | body = ('New user registration\n' |
|
233 | body = ('New user registration\n' | |
234 | '---------------------\n' |
|
234 | '---------------------\n' | |
235 | '- Username: %s\n' |
|
235 | '- Username: %s\n' | |
236 | '- Full Name: %s\n' |
|
236 | '- Full Name: %s\n' | |
237 | '- Email: %s\n') |
|
237 | '- Email: %s\n') | |
238 | body = body % (new_user.username, new_user.full_name, |
|
238 | body = body % (new_user.username, new_user.full_name, | |
239 | new_user.email) |
|
239 | new_user.email) | |
240 | edit_url = url('edit_user', id=new_user.user_id, qualified=True) |
|
240 | edit_url = url('edit_user', id=new_user.user_id, qualified=True) | |
241 | kw = {'registered_user_url': edit_url} |
|
241 | kw = {'registered_user_url': edit_url} | |
242 | NotificationModel().create(created_by=new_user, subject=subject, |
|
242 | NotificationModel().create(created_by=new_user, subject=subject, | |
243 | body=body, recipients=None, |
|
243 | body=body, recipients=None, | |
244 | type_=Notification.TYPE_REGISTRATION, |
|
244 | type_=Notification.TYPE_REGISTRATION, | |
245 | email_kwargs=kw) |
|
245 | email_kwargs=kw) | |
246 |
|
246 | |||
247 | except: |
|
247 | except: | |
248 | log.error(traceback.format_exc()) |
|
248 | log.error(traceback.format_exc()) | |
249 | raise |
|
249 | raise | |
250 |
|
250 | |||
251 | def update(self, user_id, form_data, skip_attrs=[]): |
|
251 | def update(self, user_id, form_data, skip_attrs=[]): | |
252 | from rhodecode.lib.auth import get_crypt_password |
|
252 | from rhodecode.lib.auth import get_crypt_password | |
253 | try: |
|
253 | try: | |
254 | user = self.get(user_id, cache=False) |
|
254 | user = self.get(user_id, cache=False) | |
255 | if user.username == 'default': |
|
255 | if user.username == 'default': | |
256 | raise DefaultUserException( |
|
256 | raise DefaultUserException( | |
257 | _("You can't Edit this user since it's" |
|
257 | _("You can't Edit this user since it's" | |
258 | " crucial for entire application")) |
|
258 | " crucial for entire application")) | |
259 |
|
259 | |||
260 | for k, v in form_data.items(): |
|
260 | for k, v in form_data.items(): | |
261 | if k in skip_attrs: |
|
261 | if k in skip_attrs: | |
262 | continue |
|
262 | continue | |
263 | if k == 'new_password' and v: |
|
263 | if k == 'new_password' and v: | |
264 | user.password = get_crypt_password(v) |
|
264 | user.password = get_crypt_password(v) | |
265 | user.api_key = generate_api_key(user.username) |
|
265 | user.api_key = generate_api_key(user.username) | |
266 | else: |
|
266 | else: | |
267 | if k == 'firstname': |
|
267 | if k == 'firstname': | |
268 | k = 'name' |
|
268 | k = 'name' | |
269 | setattr(user, k, v) |
|
269 | setattr(user, k, v) | |
270 | self.sa.add(user) |
|
270 | self.sa.add(user) | |
271 | except: |
|
271 | except: | |
272 | log.error(traceback.format_exc()) |
|
272 | log.error(traceback.format_exc()) | |
273 | raise |
|
273 | raise | |
274 |
|
274 | |||
275 | def update_user(self, user, **kwargs): |
|
275 | def update_user(self, user, **kwargs): | |
276 | from rhodecode.lib.auth import get_crypt_password |
|
276 | from rhodecode.lib.auth import get_crypt_password | |
277 | try: |
|
277 | try: | |
278 | user = self._get_user(user) |
|
278 | user = self._get_user(user) | |
279 | if user.username == 'default': |
|
279 | if user.username == 'default': | |
280 | raise DefaultUserException( |
|
280 | raise DefaultUserException( | |
281 | _("You can't Edit this user since it's" |
|
281 | _("You can't Edit this user since it's" | |
282 | " crucial for entire application") |
|
282 | " crucial for entire application") | |
283 | ) |
|
283 | ) | |
284 |
|
284 | |||
285 | for k, v in kwargs.items(): |
|
285 | for k, v in kwargs.items(): | |
286 | if k == 'password' and v: |
|
286 | if k == 'password' and v: | |
287 | v = get_crypt_password(v) |
|
287 | v = get_crypt_password(v) | |
288 | user.api_key = generate_api_key(user.username) |
|
288 | user.api_key = generate_api_key(user.username) | |
289 |
|
289 | |||
290 | setattr(user, k, v) |
|
290 | setattr(user, k, v) | |
291 | self.sa.add(user) |
|
291 | self.sa.add(user) | |
292 | return user |
|
292 | return user | |
293 | except: |
|
293 | except: | |
294 | log.error(traceback.format_exc()) |
|
294 | log.error(traceback.format_exc()) | |
295 | raise |
|
295 | raise | |
296 |
|
296 | |||
297 | def delete(self, user): |
|
297 | def delete(self, user): | |
298 | user = self._get_user(user) |
|
298 | user = self._get_user(user) | |
299 |
|
299 | |||
300 | try: |
|
300 | try: | |
301 | if user.username == 'default': |
|
301 | if user.username == 'default': | |
302 | raise DefaultUserException( |
|
302 | raise DefaultUserException( | |
303 | _(u"You can't remove this user since it's" |
|
303 | _(u"You can't remove this user since it's" | |
304 | " crucial for entire application") |
|
304 | " crucial for entire application") | |
305 | ) |
|
305 | ) | |
306 | if user.repositories: |
|
306 | if user.repositories: | |
307 | repos = [x.repo_name for x in user.repositories] |
|
307 | repos = [x.repo_name for x in user.repositories] | |
308 | raise UserOwnsReposException( |
|
308 | raise UserOwnsReposException( | |
309 | _(u'user "%s" still owns %s repositories and cannot be ' |
|
309 | _(u'user "%s" still owns %s repositories and cannot be ' | |
310 | 'removed. Switch owners or remove those repositories. %s') |
|
310 | 'removed. Switch owners or remove those repositories. %s') | |
311 | % (user.username, len(repos), ', '.join(repos)) |
|
311 | % (user.username, len(repos), ', '.join(repos)) | |
312 | ) |
|
312 | ) | |
313 | self.sa.delete(user) |
|
313 | self.sa.delete(user) | |
314 | except: |
|
314 | except: | |
315 | log.error(traceback.format_exc()) |
|
315 | log.error(traceback.format_exc()) | |
316 | raise |
|
316 | raise | |
317 |
|
317 | |||
318 | def reset_password_link(self, data): |
|
318 | def reset_password_link(self, data): | |
319 | from rhodecode.lib.celerylib import tasks, run_task |
|
319 | from rhodecode.lib.celerylib import tasks, run_task | |
320 | from rhodecode.model.notification import EmailNotificationModel |
|
320 | from rhodecode.model.notification import EmailNotificationModel | |
321 | user_email = data['email'] |
|
321 | user_email = data['email'] | |
322 | try: |
|
322 | try: | |
323 | user = User.get_by_email(user_email) |
|
323 | user = User.get_by_email(user_email) | |
324 | if user: |
|
324 | if user: | |
325 | log.debug('password reset user found %s' % user) |
|
325 | log.debug('password reset user found %s' % user) | |
326 | link = url('reset_password_confirmation', key=user.api_key, |
|
326 | link = url('reset_password_confirmation', key=user.api_key, | |
327 | qualified=True) |
|
327 | qualified=True) | |
328 | reg_type = EmailNotificationModel.TYPE_PASSWORD_RESET |
|
328 | reg_type = EmailNotificationModel.TYPE_PASSWORD_RESET | |
329 | body = EmailNotificationModel().get_email_tmpl(reg_type, |
|
329 | body = EmailNotificationModel().get_email_tmpl(reg_type, | |
330 | **{'user': user.short_contact, |
|
330 | **{'user': user.short_contact, | |
331 | 'reset_url': link}) |
|
331 | 'reset_url': link}) | |
332 | log.debug('sending email') |
|
332 | log.debug('sending email') | |
333 | run_task(tasks.send_email, user_email, |
|
333 | run_task(tasks.send_email, user_email, | |
334 | _("password reset link"), body, body) |
|
334 | _("password reset link"), body, body) | |
335 | log.info('send new password mail to %s' % user_email) |
|
335 | log.info('send new password mail to %s' % user_email) | |
336 | else: |
|
336 | else: | |
337 | log.debug("password reset email %s not found" % user_email) |
|
337 | log.debug("password reset email %s not found" % user_email) | |
338 | except: |
|
338 | except: | |
339 | log.error(traceback.format_exc()) |
|
339 | log.error(traceback.format_exc()) | |
340 | return False |
|
340 | return False | |
341 |
|
341 | |||
342 | return True |
|
342 | return True | |
343 |
|
343 | |||
344 | def reset_password(self, data): |
|
344 | def reset_password(self, data): | |
345 | from rhodecode.lib.celerylib import tasks, run_task |
|
345 | from rhodecode.lib.celerylib import tasks, run_task | |
346 | from rhodecode.lib import auth |
|
346 | from rhodecode.lib import auth | |
347 | user_email = data['email'] |
|
347 | user_email = data['email'] | |
348 | try: |
|
348 | try: | |
349 | try: |
|
349 | try: | |
350 | user = User.get_by_email(user_email) |
|
350 | user = User.get_by_email(user_email) | |
351 | new_passwd = auth.PasswordGenerator().gen_password(8, |
|
351 | new_passwd = auth.PasswordGenerator().gen_password(8, | |
352 | auth.PasswordGenerator.ALPHABETS_BIG_SMALL) |
|
352 | auth.PasswordGenerator.ALPHABETS_BIG_SMALL) | |
353 | if user: |
|
353 | if user: | |
354 | user.password = auth.get_crypt_password(new_passwd) |
|
354 | user.password = auth.get_crypt_password(new_passwd) | |
355 | user.api_key = auth.generate_api_key(user.username) |
|
355 | user.api_key = auth.generate_api_key(user.username) | |
356 | Session().add(user) |
|
356 | Session().add(user) | |
357 | Session().commit() |
|
357 | Session().commit() | |
358 | log.info('change password for %s' % user_email) |
|
358 | log.info('change password for %s' % user_email) | |
359 | if new_passwd is None: |
|
359 | if new_passwd is None: | |
360 | raise Exception('unable to generate new password') |
|
360 | raise Exception('unable to generate new password') | |
361 | except: |
|
361 | except: | |
362 | log.error(traceback.format_exc()) |
|
362 | log.error(traceback.format_exc()) | |
363 | Session().rollback() |
|
363 | Session().rollback() | |
364 |
|
364 | |||
365 | run_task(tasks.send_email, user_email, |
|
365 | run_task(tasks.send_email, user_email, | |
366 | _('Your new password'), |
|
366 | _('Your new password'), | |
367 | _('Your new RhodeCode password:%s') % (new_passwd)) |
|
367 | _('Your new RhodeCode password:%s') % (new_passwd)) | |
368 | log.info('send new password mail to %s' % user_email) |
|
368 | log.info('send new password mail to %s' % user_email) | |
369 |
|
369 | |||
370 | except: |
|
370 | except: | |
371 | log.error('Failed to update user password') |
|
371 | log.error('Failed to update user password') | |
372 | log.error(traceback.format_exc()) |
|
372 | log.error(traceback.format_exc()) | |
373 |
|
373 | |||
374 | return True |
|
374 | return True | |
375 |
|
375 | |||
376 | def fill_data(self, auth_user, user_id=None, api_key=None): |
|
376 | def fill_data(self, auth_user, user_id=None, api_key=None): | |
377 | """ |
|
377 | """ | |
378 | Fetches auth_user by user_id,or api_key if present. |
|
378 | Fetches auth_user by user_id,or api_key if present. | |
379 | Fills auth_user attributes with those taken from database. |
|
379 | Fills auth_user attributes with those taken from database. | |
380 | Additionally set's is_authenitated if lookup fails |
|
380 | Additionally set's is_authenitated if lookup fails | |
381 | present in database |
|
381 | present in database | |
382 |
|
382 | |||
383 | :param auth_user: instance of user to set attributes |
|
383 | :param auth_user: instance of user to set attributes | |
384 | :param user_id: user id to fetch by |
|
384 | :param user_id: user id to fetch by | |
385 | :param api_key: api key to fetch by |
|
385 | :param api_key: api key to fetch by | |
386 | """ |
|
386 | """ | |
387 | if user_id is None and api_key is None: |
|
387 | if user_id is None and api_key is None: | |
388 | raise Exception('You need to pass user_id or api_key') |
|
388 | raise Exception('You need to pass user_id or api_key') | |
389 |
|
389 | |||
390 | try: |
|
390 | try: | |
391 | if api_key: |
|
391 | if api_key: | |
392 | dbuser = self.get_by_api_key(api_key) |
|
392 | dbuser = self.get_by_api_key(api_key) | |
393 | else: |
|
393 | else: | |
394 | dbuser = self.get(user_id) |
|
394 | dbuser = self.get(user_id) | |
395 |
|
395 | |||
396 | if dbuser is not None and dbuser.active: |
|
396 | if dbuser is not None and dbuser.active: | |
397 | log.debug('filling %s data' % dbuser) |
|
397 | log.debug('filling %s data' % dbuser) | |
398 | for k, v in dbuser.get_dict().items(): |
|
398 | for k, v in dbuser.get_dict().items(): | |
399 | setattr(auth_user, k, v) |
|
399 | setattr(auth_user, k, v) | |
400 | else: |
|
400 | else: | |
401 | return False |
|
401 | return False | |
402 |
|
402 | |||
403 | except: |
|
403 | except: | |
404 | log.error(traceback.format_exc()) |
|
404 | log.error(traceback.format_exc()) | |
405 | auth_user.is_authenticated = False |
|
405 | auth_user.is_authenticated = False | |
406 | return False |
|
406 | return False | |
407 |
|
407 | |||
408 | return True |
|
408 | return True | |
409 |
|
409 | |||
410 | def fill_perms(self, user, explicit=True, algo='higherwin'): |
|
410 | def fill_perms(self, user, explicit=True, algo='higherwin'): | |
411 | """ |
|
411 | """ | |
412 | Fills user permission attribute with permissions taken from database |
|
412 | Fills user permission attribute with permissions taken from database | |
413 | works for permissions given for repositories, and for permissions that |
|
413 | works for permissions given for repositories, and for permissions that | |
414 | are granted to groups |
|
414 | are granted to groups | |
415 |
|
415 | |||
416 | :param user: user instance to fill his perms |
|
416 | :param user: user instance to fill his perms | |
417 | :param explicit: In case there are permissions both for user and a group |
|
417 | :param explicit: In case there are permissions both for user and a group | |
418 | that user is part of, explicit flag will defiine if user will |
|
418 | that user is part of, explicit flag will defiine if user will | |
419 | explicitly override permissions from group, if it's False it will |
|
419 | explicitly override permissions from group, if it's False it will | |
420 | make decision based on the algo |
|
420 | make decision based on the algo | |
421 | :param algo: algorithm to decide what permission should be choose if |
|
421 | :param algo: algorithm to decide what permission should be choose if | |
422 | it's multiple defined, eg user in two different groups. It also |
|
422 | it's multiple defined, eg user in two different groups. It also | |
423 | decides if explicit flag is turned off how to specify the permission |
|
423 | decides if explicit flag is turned off how to specify the permission | |
424 | for case when user is in a group + have defined separate permission |
|
424 | for case when user is in a group + have defined separate permission | |
425 | """ |
|
425 | """ | |
426 | RK = 'repositories' |
|
426 | RK = 'repositories' | |
427 | GK = 'repositories_groups' |
|
427 | GK = 'repositories_groups' | |
428 | GLOBAL = 'global' |
|
428 | GLOBAL = 'global' | |
429 | user.permissions[RK] = {} |
|
429 | user.permissions[RK] = {} | |
430 | user.permissions[GK] = {} |
|
430 | user.permissions[GK] = {} | |
431 | user.permissions[GLOBAL] = set() |
|
431 | user.permissions[GLOBAL] = set() | |
432 |
|
432 | |||
433 | def _choose_perm(new_perm, cur_perm): |
|
433 | def _choose_perm(new_perm, cur_perm): | |
434 | new_perm_val = PERM_WEIGHTS[new_perm] |
|
434 | new_perm_val = PERM_WEIGHTS[new_perm] | |
435 | cur_perm_val = PERM_WEIGHTS[cur_perm] |
|
435 | cur_perm_val = PERM_WEIGHTS[cur_perm] | |
436 | if algo == 'higherwin': |
|
436 | if algo == 'higherwin': | |
437 | if new_perm_val > cur_perm_val: |
|
437 | if new_perm_val > cur_perm_val: | |
438 | return new_perm |
|
438 | return new_perm | |
439 | return cur_perm |
|
439 | return cur_perm | |
440 | elif algo == 'lowerwin': |
|
440 | elif algo == 'lowerwin': | |
441 | if new_perm_val < cur_perm_val: |
|
441 | if new_perm_val < cur_perm_val: | |
442 | return new_perm |
|
442 | return new_perm | |
443 | return cur_perm |
|
443 | return cur_perm | |
444 |
|
444 | |||
445 | #====================================================================== |
|
445 | #====================================================================== | |
446 | # fetch default permissions |
|
446 | # fetch default permissions | |
447 | #====================================================================== |
|
447 | #====================================================================== | |
448 | default_user = User.get_by_username('default', cache=True) |
|
448 | default_user = User.get_by_username('default', cache=True) | |
449 | default_user_id = default_user.user_id |
|
449 | default_user_id = default_user.user_id | |
450 |
|
450 | |||
451 | default_repo_perms = Permission.get_default_perms(default_user_id) |
|
451 | default_repo_perms = Permission.get_default_perms(default_user_id) | |
452 | default_repo_groups_perms = Permission.get_default_group_perms(default_user_id) |
|
452 | default_repo_groups_perms = Permission.get_default_group_perms(default_user_id) | |
453 |
|
453 | |||
454 | if user.is_admin: |
|
454 | if user.is_admin: | |
455 | #================================================================== |
|
455 | #================================================================== | |
456 | # admin user have all default rights for repositories |
|
456 | # admin user have all default rights for repositories | |
457 | # and groups set to admin |
|
457 | # and groups set to admin | |
458 | #================================================================== |
|
458 | #================================================================== | |
459 | user.permissions[GLOBAL].add('hg.admin') |
|
459 | user.permissions[GLOBAL].add('hg.admin') | |
460 |
|
460 | |||
461 | # repositories |
|
461 | # repositories | |
462 | for perm in default_repo_perms: |
|
462 | for perm in default_repo_perms: | |
463 | r_k = perm.UserRepoToPerm.repository.repo_name |
|
463 | r_k = perm.UserRepoToPerm.repository.repo_name | |
464 | p = 'repository.admin' |
|
464 | p = 'repository.admin' | |
465 | user.permissions[RK][r_k] = p |
|
465 | user.permissions[RK][r_k] = p | |
466 |
|
466 | |||
467 | # repository groups |
|
467 | # repository groups | |
468 | for perm in default_repo_groups_perms: |
|
468 | for perm in default_repo_groups_perms: | |
469 | rg_k = perm.UserRepoGroupToPerm.group.group_name |
|
469 | rg_k = perm.UserRepoGroupToPerm.group.group_name | |
470 | p = 'group.admin' |
|
470 | p = 'group.admin' | |
471 | user.permissions[GK][rg_k] = p |
|
471 | user.permissions[GK][rg_k] = p | |
472 | return user |
|
472 | return user | |
473 |
|
473 | |||
474 | #================================================================== |
|
474 | #================================================================== | |
475 | # SET DEFAULTS GLOBAL, REPOS, REPOS GROUPS |
|
475 | # SET DEFAULTS GLOBAL, REPOS, REPOS GROUPS | |
476 | #================================================================== |
|
476 | #================================================================== | |
477 | uid = user.user_id |
|
477 | uid = user.user_id | |
478 |
|
478 | |||
479 | # default global permissions taken fron the default user |
|
479 | # default global permissions taken fron the default user | |
480 | default_global_perms = self.sa.query(UserToPerm)\ |
|
480 | default_global_perms = self.sa.query(UserToPerm)\ | |
481 | .filter(UserToPerm.user_id == default_user_id) |
|
481 | .filter(UserToPerm.user_id == default_user_id) | |
482 |
|
482 | |||
483 | for perm in default_global_perms: |
|
483 | for perm in default_global_perms: | |
484 | user.permissions[GLOBAL].add(perm.permission.permission_name) |
|
484 | user.permissions[GLOBAL].add(perm.permission.permission_name) | |
485 |
|
485 | |||
486 | # defaults for repositories, taken from default user |
|
486 | # defaults for repositories, taken from default user | |
487 | for perm in default_repo_perms: |
|
487 | for perm in default_repo_perms: | |
488 | r_k = perm.UserRepoToPerm.repository.repo_name |
|
488 | r_k = perm.UserRepoToPerm.repository.repo_name | |
489 | if perm.Repository.private and not (perm.Repository.user_id == uid): |
|
489 | if perm.Repository.private and not (perm.Repository.user_id == uid): | |
490 | # disable defaults for private repos, |
|
490 | # disable defaults for private repos, | |
491 | p = 'repository.none' |
|
491 | p = 'repository.none' | |
492 | elif perm.Repository.user_id == uid: |
|
492 | elif perm.Repository.user_id == uid: | |
493 | # set admin if owner |
|
493 | # set admin if owner | |
494 | p = 'repository.admin' |
|
494 | p = 'repository.admin' | |
495 | else: |
|
495 | else: | |
496 | p = perm.Permission.permission_name |
|
496 | p = perm.Permission.permission_name | |
497 |
|
497 | |||
498 | user.permissions[RK][r_k] = p |
|
498 | user.permissions[RK][r_k] = p | |
499 |
|
499 | |||
500 | # defaults for repository groups taken from default user permission |
|
500 | # defaults for repository groups taken from default user permission | |
501 | # on given group |
|
501 | # on given group | |
502 | for perm in default_repo_groups_perms: |
|
502 | for perm in default_repo_groups_perms: | |
503 | rg_k = perm.UserRepoGroupToPerm.group.group_name |
|
503 | rg_k = perm.UserRepoGroupToPerm.group.group_name | |
504 | p = perm.Permission.permission_name |
|
504 | p = perm.Permission.permission_name | |
505 | user.permissions[GK][rg_k] = p |
|
505 | user.permissions[GK][rg_k] = p | |
506 |
|
506 | |||
507 | #====================================================================== |
|
507 | #====================================================================== | |
508 | # !! OVERRIDE GLOBALS !! with user permissions if any found |
|
508 | # !! OVERRIDE GLOBALS !! with user permissions if any found | |
509 | #====================================================================== |
|
509 | #====================================================================== | |
510 | # those can be configured from groups or users explicitly |
|
510 | # those can be configured from groups or users explicitly | |
511 | _configurable = set(['hg.fork.none', 'hg.fork.repository', |
|
511 | _configurable = set(['hg.fork.none', 'hg.fork.repository', | |
512 | 'hg.create.none', 'hg.create.repository']) |
|
512 | 'hg.create.none', 'hg.create.repository']) | |
513 |
|
513 | |||
514 | # USER GROUPS comes first |
|
514 | # USER GROUPS comes first | |
515 |
# user |
|
515 | # user group global permissions | |
516 | user_perms_from_users_groups = self.sa.query(UsersGroupToPerm)\ |
|
516 | user_perms_from_users_groups = self.sa.query(UsersGroupToPerm)\ | |
517 | .options(joinedload(UsersGroupToPerm.permission))\ |
|
517 | .options(joinedload(UsersGroupToPerm.permission))\ | |
518 | .join((UsersGroupMember, UsersGroupToPerm.users_group_id == |
|
518 | .join((UsersGroupMember, UsersGroupToPerm.users_group_id == | |
519 | UsersGroupMember.users_group_id))\ |
|
519 | UsersGroupMember.users_group_id))\ | |
520 | .filter(UsersGroupMember.user_id == uid)\ |
|
520 | .filter(UsersGroupMember.user_id == uid)\ | |
521 | .order_by(UsersGroupToPerm.users_group_id)\ |
|
521 | .order_by(UsersGroupToPerm.users_group_id)\ | |
522 | .all() |
|
522 | .all() | |
523 | #need to group here by groups since user can be in more than one group |
|
523 | #need to group here by groups since user can be in more than one group | |
524 | _grouped = [[x, list(y)] for x, y in |
|
524 | _grouped = [[x, list(y)] for x, y in | |
525 | itertools.groupby(user_perms_from_users_groups, |
|
525 | itertools.groupby(user_perms_from_users_groups, | |
526 | lambda x:x.users_group)] |
|
526 | lambda x:x.users_group)] | |
527 | for gr, perms in _grouped: |
|
527 | for gr, perms in _grouped: | |
528 | # since user can be in multiple groups iterate over them and |
|
528 | # since user can be in multiple groups iterate over them and | |
529 | # select the lowest permissions first (more explicit) |
|
529 | # select the lowest permissions first (more explicit) | |
530 | ##TODO: do this^^ |
|
530 | ##TODO: do this^^ | |
531 | if not gr.inherit_default_permissions: |
|
531 | if not gr.inherit_default_permissions: | |
532 | # NEED TO IGNORE all configurable permissions and |
|
532 | # NEED TO IGNORE all configurable permissions and | |
533 | # replace them with explicitly set |
|
533 | # replace them with explicitly set | |
534 | user.permissions[GLOBAL] = user.permissions[GLOBAL]\ |
|
534 | user.permissions[GLOBAL] = user.permissions[GLOBAL]\ | |
535 | .difference(_configurable) |
|
535 | .difference(_configurable) | |
536 | for perm in perms: |
|
536 | for perm in perms: | |
537 | user.permissions[GLOBAL].add(perm.permission.permission_name) |
|
537 | user.permissions[GLOBAL].add(perm.permission.permission_name) | |
538 |
|
538 | |||
539 | # user specific global permissions |
|
539 | # user specific global permissions | |
540 | user_perms = self.sa.query(UserToPerm)\ |
|
540 | user_perms = self.sa.query(UserToPerm)\ | |
541 | .options(joinedload(UserToPerm.permission))\ |
|
541 | .options(joinedload(UserToPerm.permission))\ | |
542 | .filter(UserToPerm.user_id == uid).all() |
|
542 | .filter(UserToPerm.user_id == uid).all() | |
543 |
|
543 | |||
544 | if not user.inherit_default_permissions: |
|
544 | if not user.inherit_default_permissions: | |
545 | # NEED TO IGNORE all configurable permissions and |
|
545 | # NEED TO IGNORE all configurable permissions and | |
546 | # replace them with explicitly set |
|
546 | # replace them with explicitly set | |
547 | user.permissions[GLOBAL] = user.permissions[GLOBAL]\ |
|
547 | user.permissions[GLOBAL] = user.permissions[GLOBAL]\ | |
548 | .difference(_configurable) |
|
548 | .difference(_configurable) | |
549 |
|
549 | |||
550 | for perm in user_perms: |
|
550 | for perm in user_perms: | |
551 | user.permissions[GLOBAL].add(perm.permission.permission_name) |
|
551 | user.permissions[GLOBAL].add(perm.permission.permission_name) | |
552 |
|
552 | |||
553 | #====================================================================== |
|
553 | #====================================================================== | |
554 | # !! PERMISSIONS FOR REPOSITORIES !! |
|
554 | # !! PERMISSIONS FOR REPOSITORIES !! | |
555 | #====================================================================== |
|
555 | #====================================================================== | |
556 | #====================================================================== |
|
556 | #====================================================================== | |
557 | # check if user is part of user groups for this repository and |
|
557 | # check if user is part of user groups for this repository and | |
558 | # fill in his permission from it. _choose_perm decides of which |
|
558 | # fill in his permission from it. _choose_perm decides of which | |
559 | # permission should be selected based on selected method |
|
559 | # permission should be selected based on selected method | |
560 | #====================================================================== |
|
560 | #====================================================================== | |
561 |
|
561 | |||
562 |
# user |
|
562 | # user group for repositories permissions | |
563 | user_repo_perms_from_users_groups = \ |
|
563 | user_repo_perms_from_users_groups = \ | |
564 | self.sa.query(UsersGroupRepoToPerm, Permission, Repository,)\ |
|
564 | self.sa.query(UsersGroupRepoToPerm, Permission, Repository,)\ | |
565 | .join((Repository, UsersGroupRepoToPerm.repository_id == |
|
565 | .join((Repository, UsersGroupRepoToPerm.repository_id == | |
566 | Repository.repo_id))\ |
|
566 | Repository.repo_id))\ | |
567 | .join((Permission, UsersGroupRepoToPerm.permission_id == |
|
567 | .join((Permission, UsersGroupRepoToPerm.permission_id == | |
568 | Permission.permission_id))\ |
|
568 | Permission.permission_id))\ | |
569 | .join((UsersGroupMember, UsersGroupRepoToPerm.users_group_id == |
|
569 | .join((UsersGroupMember, UsersGroupRepoToPerm.users_group_id == | |
570 | UsersGroupMember.users_group_id))\ |
|
570 | UsersGroupMember.users_group_id))\ | |
571 | .filter(UsersGroupMember.user_id == uid)\ |
|
571 | .filter(UsersGroupMember.user_id == uid)\ | |
572 | .all() |
|
572 | .all() | |
573 |
|
573 | |||
574 | multiple_counter = collections.defaultdict(int) |
|
574 | multiple_counter = collections.defaultdict(int) | |
575 | for perm in user_repo_perms_from_users_groups: |
|
575 | for perm in user_repo_perms_from_users_groups: | |
576 | r_k = perm.UsersGroupRepoToPerm.repository.repo_name |
|
576 | r_k = perm.UsersGroupRepoToPerm.repository.repo_name | |
577 | multiple_counter[r_k] += 1 |
|
577 | multiple_counter[r_k] += 1 | |
578 | p = perm.Permission.permission_name |
|
578 | p = perm.Permission.permission_name | |
579 | cur_perm = user.permissions[RK][r_k] |
|
579 | cur_perm = user.permissions[RK][r_k] | |
580 |
|
580 | |||
581 | if perm.Repository.user_id == uid: |
|
581 | if perm.Repository.user_id == uid: | |
582 | # set admin if owner |
|
582 | # set admin if owner | |
583 | p = 'repository.admin' |
|
583 | p = 'repository.admin' | |
584 | else: |
|
584 | else: | |
585 | if multiple_counter[r_k] > 1: |
|
585 | if multiple_counter[r_k] > 1: | |
586 | p = _choose_perm(p, cur_perm) |
|
586 | p = _choose_perm(p, cur_perm) | |
587 | user.permissions[RK][r_k] = p |
|
587 | user.permissions[RK][r_k] = p | |
588 |
|
588 | |||
589 | # user explicit permissions for repositories, overrides any specified |
|
589 | # user explicit permissions for repositories, overrides any specified | |
590 | # by the group permission |
|
590 | # by the group permission | |
591 | user_repo_perms = \ |
|
591 | user_repo_perms = \ | |
592 | self.sa.query(UserRepoToPerm, Permission, Repository)\ |
|
592 | self.sa.query(UserRepoToPerm, Permission, Repository)\ | |
593 | .join((Repository, UserRepoToPerm.repository_id == |
|
593 | .join((Repository, UserRepoToPerm.repository_id == | |
594 | Repository.repo_id))\ |
|
594 | Repository.repo_id))\ | |
595 | .join((Permission, UserRepoToPerm.permission_id == |
|
595 | .join((Permission, UserRepoToPerm.permission_id == | |
596 | Permission.permission_id))\ |
|
596 | Permission.permission_id))\ | |
597 | .filter(UserRepoToPerm.user_id == uid)\ |
|
597 | .filter(UserRepoToPerm.user_id == uid)\ | |
598 | .all() |
|
598 | .all() | |
599 |
|
599 | |||
600 | for perm in user_repo_perms: |
|
600 | for perm in user_repo_perms: | |
601 | r_k = perm.UserRepoToPerm.repository.repo_name |
|
601 | r_k = perm.UserRepoToPerm.repository.repo_name | |
602 | cur_perm = user.permissions[RK][r_k] |
|
602 | cur_perm = user.permissions[RK][r_k] | |
603 | # set admin if owner |
|
603 | # set admin if owner | |
604 | if perm.Repository.user_id == uid: |
|
604 | if perm.Repository.user_id == uid: | |
605 | p = 'repository.admin' |
|
605 | p = 'repository.admin' | |
606 | else: |
|
606 | else: | |
607 | p = perm.Permission.permission_name |
|
607 | p = perm.Permission.permission_name | |
608 | if not explicit: |
|
608 | if not explicit: | |
609 | p = _choose_perm(p, cur_perm) |
|
609 | p = _choose_perm(p, cur_perm) | |
610 | user.permissions[RK][r_k] = p |
|
610 | user.permissions[RK][r_k] = p | |
611 |
|
611 | |||
612 | #====================================================================== |
|
612 | #====================================================================== | |
613 | # !! PERMISSIONS FOR REPOSITORY GROUPS !! |
|
613 | # !! PERMISSIONS FOR REPOSITORY GROUPS !! | |
614 | #====================================================================== |
|
614 | #====================================================================== | |
615 | #====================================================================== |
|
615 | #====================================================================== | |
616 | # check if user is part of user groups for this repository groups and |
|
616 | # check if user is part of user groups for this repository groups and | |
617 | # fill in his permission from it. _choose_perm decides of which |
|
617 | # fill in his permission from it. _choose_perm decides of which | |
618 | # permission should be selected based on selected method |
|
618 | # permission should be selected based on selected method | |
619 | #====================================================================== |
|
619 | #====================================================================== | |
620 |
# user |
|
620 | # user group for repo groups permissions | |
621 | user_repo_group_perms_from_users_groups = \ |
|
621 | user_repo_group_perms_from_users_groups = \ | |
622 | self.sa.query(UsersGroupRepoGroupToPerm, Permission, RepoGroup)\ |
|
622 | self.sa.query(UsersGroupRepoGroupToPerm, Permission, RepoGroup)\ | |
623 | .join((RepoGroup, UsersGroupRepoGroupToPerm.group_id == RepoGroup.group_id))\ |
|
623 | .join((RepoGroup, UsersGroupRepoGroupToPerm.group_id == RepoGroup.group_id))\ | |
624 | .join((Permission, UsersGroupRepoGroupToPerm.permission_id |
|
624 | .join((Permission, UsersGroupRepoGroupToPerm.permission_id | |
625 | == Permission.permission_id))\ |
|
625 | == Permission.permission_id))\ | |
626 | .join((UsersGroupMember, UsersGroupRepoGroupToPerm.users_group_id |
|
626 | .join((UsersGroupMember, UsersGroupRepoGroupToPerm.users_group_id | |
627 | == UsersGroupMember.users_group_id))\ |
|
627 | == UsersGroupMember.users_group_id))\ | |
628 | .filter(UsersGroupMember.user_id == uid)\ |
|
628 | .filter(UsersGroupMember.user_id == uid)\ | |
629 | .all() |
|
629 | .all() | |
630 |
|
630 | |||
631 | multiple_counter = collections.defaultdict(int) |
|
631 | multiple_counter = collections.defaultdict(int) | |
632 | for perm in user_repo_group_perms_from_users_groups: |
|
632 | for perm in user_repo_group_perms_from_users_groups: | |
633 | g_k = perm.UsersGroupRepoGroupToPerm.group.group_name |
|
633 | g_k = perm.UsersGroupRepoGroupToPerm.group.group_name | |
634 | multiple_counter[g_k] += 1 |
|
634 | multiple_counter[g_k] += 1 | |
635 | p = perm.Permission.permission_name |
|
635 | p = perm.Permission.permission_name | |
636 | cur_perm = user.permissions[GK][g_k] |
|
636 | cur_perm = user.permissions[GK][g_k] | |
637 | if multiple_counter[g_k] > 1: |
|
637 | if multiple_counter[g_k] > 1: | |
638 | p = _choose_perm(p, cur_perm) |
|
638 | p = _choose_perm(p, cur_perm) | |
639 | user.permissions[GK][g_k] = p |
|
639 | user.permissions[GK][g_k] = p | |
640 |
|
640 | |||
641 | # user explicit permissions for repository groups |
|
641 | # user explicit permissions for repository groups | |
642 | user_repo_groups_perms = \ |
|
642 | user_repo_groups_perms = \ | |
643 | self.sa.query(UserRepoGroupToPerm, Permission, RepoGroup)\ |
|
643 | self.sa.query(UserRepoGroupToPerm, Permission, RepoGroup)\ | |
644 | .join((RepoGroup, UserRepoGroupToPerm.group_id == RepoGroup.group_id))\ |
|
644 | .join((RepoGroup, UserRepoGroupToPerm.group_id == RepoGroup.group_id))\ | |
645 | .join((Permission, UserRepoGroupToPerm.permission_id |
|
645 | .join((Permission, UserRepoGroupToPerm.permission_id | |
646 | == Permission.permission_id))\ |
|
646 | == Permission.permission_id))\ | |
647 | .filter(UserRepoGroupToPerm.user_id == uid)\ |
|
647 | .filter(UserRepoGroupToPerm.user_id == uid)\ | |
648 | .all() |
|
648 | .all() | |
649 |
|
649 | |||
650 | for perm in user_repo_groups_perms: |
|
650 | for perm in user_repo_groups_perms: | |
651 | rg_k = perm.UserRepoGroupToPerm.group.group_name |
|
651 | rg_k = perm.UserRepoGroupToPerm.group.group_name | |
652 | p = perm.Permission.permission_name |
|
652 | p = perm.Permission.permission_name | |
653 | cur_perm = user.permissions[GK][rg_k] |
|
653 | cur_perm = user.permissions[GK][rg_k] | |
654 | if not explicit: |
|
654 | if not explicit: | |
655 | p = _choose_perm(p, cur_perm) |
|
655 | p = _choose_perm(p, cur_perm) | |
656 | user.permissions[GK][rg_k] = p |
|
656 | user.permissions[GK][rg_k] = p | |
657 |
|
657 | |||
658 | return user |
|
658 | return user | |
659 |
|
659 | |||
660 | def has_perm(self, user, perm): |
|
660 | def has_perm(self, user, perm): | |
661 | perm = self._get_perm(perm) |
|
661 | perm = self._get_perm(perm) | |
662 | user = self._get_user(user) |
|
662 | user = self._get_user(user) | |
663 |
|
663 | |||
664 | return UserToPerm.query().filter(UserToPerm.user == user)\ |
|
664 | return UserToPerm.query().filter(UserToPerm.user == user)\ | |
665 | .filter(UserToPerm.permission == perm).scalar() is not None |
|
665 | .filter(UserToPerm.permission == perm).scalar() is not None | |
666 |
|
666 | |||
667 | def grant_perm(self, user, perm): |
|
667 | def grant_perm(self, user, perm): | |
668 | """ |
|
668 | """ | |
669 | Grant user global permissions |
|
669 | Grant user global permissions | |
670 |
|
670 | |||
671 | :param user: |
|
671 | :param user: | |
672 | :param perm: |
|
672 | :param perm: | |
673 | """ |
|
673 | """ | |
674 | user = self._get_user(user) |
|
674 | user = self._get_user(user) | |
675 | perm = self._get_perm(perm) |
|
675 | perm = self._get_perm(perm) | |
676 | # if this permission is already granted skip it |
|
676 | # if this permission is already granted skip it | |
677 | _perm = UserToPerm.query()\ |
|
677 | _perm = UserToPerm.query()\ | |
678 | .filter(UserToPerm.user == user)\ |
|
678 | .filter(UserToPerm.user == user)\ | |
679 | .filter(UserToPerm.permission == perm)\ |
|
679 | .filter(UserToPerm.permission == perm)\ | |
680 | .scalar() |
|
680 | .scalar() | |
681 | if _perm: |
|
681 | if _perm: | |
682 | return |
|
682 | return | |
683 | new = UserToPerm() |
|
683 | new = UserToPerm() | |
684 | new.user = user |
|
684 | new.user = user | |
685 | new.permission = perm |
|
685 | new.permission = perm | |
686 | self.sa.add(new) |
|
686 | self.sa.add(new) | |
687 |
|
687 | |||
688 | def revoke_perm(self, user, perm): |
|
688 | def revoke_perm(self, user, perm): | |
689 | """ |
|
689 | """ | |
690 | Revoke users global permissions |
|
690 | Revoke users global permissions | |
691 |
|
691 | |||
692 | :param user: |
|
692 | :param user: | |
693 | :param perm: |
|
693 | :param perm: | |
694 | """ |
|
694 | """ | |
695 | user = self._get_user(user) |
|
695 | user = self._get_user(user) | |
696 | perm = self._get_perm(perm) |
|
696 | perm = self._get_perm(perm) | |
697 |
|
697 | |||
698 | obj = UserToPerm.query()\ |
|
698 | obj = UserToPerm.query()\ | |
699 | .filter(UserToPerm.user == user)\ |
|
699 | .filter(UserToPerm.user == user)\ | |
700 | .filter(UserToPerm.permission == perm)\ |
|
700 | .filter(UserToPerm.permission == perm)\ | |
701 | .scalar() |
|
701 | .scalar() | |
702 | if obj: |
|
702 | if obj: | |
703 | self.sa.delete(obj) |
|
703 | self.sa.delete(obj) | |
704 |
|
704 | |||
705 | def add_extra_email(self, user, email): |
|
705 | def add_extra_email(self, user, email): | |
706 | """ |
|
706 | """ | |
707 | Adds email address to UserEmailMap |
|
707 | Adds email address to UserEmailMap | |
708 |
|
708 | |||
709 | :param user: |
|
709 | :param user: | |
710 | :param email: |
|
710 | :param email: | |
711 | """ |
|
711 | """ | |
712 | from rhodecode.model import forms |
|
712 | from rhodecode.model import forms | |
713 | form = forms.UserExtraEmailForm()() |
|
713 | form = forms.UserExtraEmailForm()() | |
714 | data = form.to_python(dict(email=email)) |
|
714 | data = form.to_python(dict(email=email)) | |
715 | user = self._get_user(user) |
|
715 | user = self._get_user(user) | |
716 |
|
716 | |||
717 | obj = UserEmailMap() |
|
717 | obj = UserEmailMap() | |
718 | obj.user = user |
|
718 | obj.user = user | |
719 | obj.email = data['email'] |
|
719 | obj.email = data['email'] | |
720 | self.sa.add(obj) |
|
720 | self.sa.add(obj) | |
721 | return obj |
|
721 | return obj | |
722 |
|
722 | |||
723 | def delete_extra_email(self, user, email_id): |
|
723 | def delete_extra_email(self, user, email_id): | |
724 | """ |
|
724 | """ | |
725 | Removes email address from UserEmailMap |
|
725 | Removes email address from UserEmailMap | |
726 |
|
726 | |||
727 | :param user: |
|
727 | :param user: | |
728 | :param email_id: |
|
728 | :param email_id: | |
729 | """ |
|
729 | """ | |
730 | user = self._get_user(user) |
|
730 | user = self._get_user(user) | |
731 | obj = UserEmailMap.query().get(email_id) |
|
731 | obj = UserEmailMap.query().get(email_id) | |
732 | if obj: |
|
732 | if obj: | |
733 | self.sa.delete(obj) |
|
733 | self.sa.delete(obj) | |
734 |
|
734 | |||
735 | def add_extra_ip(self, user, ip): |
|
735 | def add_extra_ip(self, user, ip): | |
736 | """ |
|
736 | """ | |
737 | Adds ip address to UserIpMap |
|
737 | Adds ip address to UserIpMap | |
738 |
|
738 | |||
739 | :param user: |
|
739 | :param user: | |
740 | :param ip: |
|
740 | :param ip: | |
741 | """ |
|
741 | """ | |
742 | from rhodecode.model import forms |
|
742 | from rhodecode.model import forms | |
743 | form = forms.UserExtraIpForm()() |
|
743 | form = forms.UserExtraIpForm()() | |
744 | data = form.to_python(dict(ip=ip)) |
|
744 | data = form.to_python(dict(ip=ip)) | |
745 | user = self._get_user(user) |
|
745 | user = self._get_user(user) | |
746 |
|
746 | |||
747 | obj = UserIpMap() |
|
747 | obj = UserIpMap() | |
748 | obj.user = user |
|
748 | obj.user = user | |
749 | obj.ip_addr = data['ip'] |
|
749 | obj.ip_addr = data['ip'] | |
750 | self.sa.add(obj) |
|
750 | self.sa.add(obj) | |
751 | return obj |
|
751 | return obj | |
752 |
|
752 | |||
753 | def delete_extra_ip(self, user, ip_id): |
|
753 | def delete_extra_ip(self, user, ip_id): | |
754 | """ |
|
754 | """ | |
755 | Removes ip address from UserIpMap |
|
755 | Removes ip address from UserIpMap | |
756 |
|
756 | |||
757 | :param user: |
|
757 | :param user: | |
758 | :param ip_id: |
|
758 | :param ip_id: | |
759 | """ |
|
759 | """ | |
760 | user = self._get_user(user) |
|
760 | user = self._get_user(user) | |
761 | obj = UserIpMap.query().get(ip_id) |
|
761 | obj = UserIpMap.query().get(ip_id) | |
762 | if obj: |
|
762 | if obj: | |
763 | self.sa.delete(obj) |
|
763 | self.sa.delete(obj) |
@@ -1,809 +1,809 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 collections import defaultdict |
|
8 | from collections import defaultdict | |
9 | from pylons.i18n.translation import _ |
|
9 | from pylons.i18n.translation import _ | |
10 | from webhelpers.pylonslib.secure_form import authentication_token |
|
10 | from webhelpers.pylonslib.secure_form import authentication_token | |
11 |
|
11 | |||
12 | from formencode.validators import ( |
|
12 | from formencode.validators import ( | |
13 | UnicodeString, OneOf, Int, Number, Regex, Email, Bool, StringBoolean, Set, |
|
13 | UnicodeString, OneOf, Int, Number, Regex, Email, Bool, StringBoolean, Set, | |
14 | NotEmpty, IPAddress, CIDR |
|
14 | NotEmpty, IPAddress, CIDR | |
15 | ) |
|
15 | ) | |
16 | from rhodecode.lib.compat import OrderedSet |
|
16 | from rhodecode.lib.compat import OrderedSet | |
17 | from rhodecode.lib import ipaddr |
|
17 | from rhodecode.lib import ipaddr | |
18 | from rhodecode.lib.utils import repo_name_slug |
|
18 | from rhodecode.lib.utils import repo_name_slug | |
19 | from rhodecode.model.db import RepoGroup, Repository, UsersGroup, User,\ |
|
19 | from rhodecode.model.db import RepoGroup, Repository, UsersGroup, User,\ | |
20 | ChangesetStatus |
|
20 | ChangesetStatus | |
21 | from rhodecode.lib.exceptions import LdapImportError |
|
21 | from rhodecode.lib.exceptions import LdapImportError | |
22 | from rhodecode.config.routing import ADMIN_PREFIX |
|
22 | from rhodecode.config.routing import ADMIN_PREFIX | |
23 | from rhodecode.lib.auth import HasReposGroupPermissionAny, HasPermissionAny |
|
23 | from rhodecode.lib.auth import HasReposGroupPermissionAny, HasPermissionAny | |
24 |
|
24 | |||
25 | # silence warnings and pylint |
|
25 | # silence warnings and pylint | |
26 | UnicodeString, OneOf, Int, Number, Regex, Email, Bool, StringBoolean, Set, \ |
|
26 | UnicodeString, OneOf, Int, Number, Regex, Email, Bool, StringBoolean, Set, \ | |
27 | NotEmpty, IPAddress, CIDR |
|
27 | NotEmpty, IPAddress, CIDR | |
28 |
|
28 | |||
29 | log = logging.getLogger(__name__) |
|
29 | log = logging.getLogger(__name__) | |
30 |
|
30 | |||
31 |
|
31 | |||
32 | class UniqueList(formencode.FancyValidator): |
|
32 | class UniqueList(formencode.FancyValidator): | |
33 | """ |
|
33 | """ | |
34 | Unique List ! |
|
34 | Unique List ! | |
35 | """ |
|
35 | """ | |
36 | messages = dict( |
|
36 | messages = dict( | |
37 | empty=_('Value cannot be an empty list'), |
|
37 | empty=_('Value cannot be an empty list'), | |
38 | missing_value=_('Value cannot be an empty list'), |
|
38 | missing_value=_('Value cannot be an empty list'), | |
39 | ) |
|
39 | ) | |
40 |
|
40 | |||
41 | def _to_python(self, value, state): |
|
41 | def _to_python(self, value, state): | |
42 | if isinstance(value, list): |
|
42 | if isinstance(value, list): | |
43 | return value |
|
43 | return value | |
44 | elif isinstance(value, set): |
|
44 | elif isinstance(value, set): | |
45 | return list(value) |
|
45 | return list(value) | |
46 | elif isinstance(value, tuple): |
|
46 | elif isinstance(value, tuple): | |
47 | return list(value) |
|
47 | return list(value) | |
48 | elif value is None: |
|
48 | elif value is None: | |
49 | return [] |
|
49 | return [] | |
50 | else: |
|
50 | else: | |
51 | return [value] |
|
51 | return [value] | |
52 |
|
52 | |||
53 | def empty_value(self, value): |
|
53 | def empty_value(self, value): | |
54 | return [] |
|
54 | return [] | |
55 |
|
55 | |||
56 |
|
56 | |||
57 | class StateObj(object): |
|
57 | class StateObj(object): | |
58 | """ |
|
58 | """ | |
59 | this is needed to translate the messages using _() in validators |
|
59 | this is needed to translate the messages using _() in validators | |
60 | """ |
|
60 | """ | |
61 | _ = staticmethod(_) |
|
61 | _ = staticmethod(_) | |
62 |
|
62 | |||
63 |
|
63 | |||
64 | def M(self, key, state=None, **kwargs): |
|
64 | def M(self, key, state=None, **kwargs): | |
65 | """ |
|
65 | """ | |
66 | returns string from self.message based on given key, |
|
66 | returns string from self.message based on given key, | |
67 | passed kw params are used to substitute %(named)s params inside |
|
67 | passed kw params are used to substitute %(named)s params inside | |
68 | translated strings |
|
68 | translated strings | |
69 |
|
69 | |||
70 | :param msg: |
|
70 | :param msg: | |
71 | :param state: |
|
71 | :param state: | |
72 | """ |
|
72 | """ | |
73 | if state is None: |
|
73 | if state is None: | |
74 | state = StateObj() |
|
74 | state = StateObj() | |
75 | else: |
|
75 | else: | |
76 | state._ = staticmethod(_) |
|
76 | state._ = staticmethod(_) | |
77 | #inject validator into state object |
|
77 | #inject validator into state object | |
78 | return self.message(key, state, **kwargs) |
|
78 | return self.message(key, state, **kwargs) | |
79 |
|
79 | |||
80 |
|
80 | |||
81 | def ValidUsername(edit=False, old_data={}): |
|
81 | def ValidUsername(edit=False, old_data={}): | |
82 | class _validator(formencode.validators.FancyValidator): |
|
82 | class _validator(formencode.validators.FancyValidator): | |
83 | messages = { |
|
83 | messages = { | |
84 | 'username_exists': _(u'Username "%(username)s" already exists'), |
|
84 | 'username_exists': _(u'Username "%(username)s" already exists'), | |
85 | 'system_invalid_username': |
|
85 | 'system_invalid_username': | |
86 | _(u'Username "%(username)s" is forbidden'), |
|
86 | _(u'Username "%(username)s" is forbidden'), | |
87 | 'invalid_username': |
|
87 | 'invalid_username': | |
88 | _(u'Username may only contain alphanumeric characters ' |
|
88 | _(u'Username may only contain alphanumeric characters ' | |
89 | 'underscores, periods or dashes and must begin with ' |
|
89 | 'underscores, periods or dashes and must begin with ' | |
90 | 'alphanumeric character') |
|
90 | 'alphanumeric character') | |
91 | } |
|
91 | } | |
92 |
|
92 | |||
93 | def validate_python(self, value, state): |
|
93 | def validate_python(self, value, state): | |
94 | if value in ['default', 'new_user']: |
|
94 | if value in ['default', 'new_user']: | |
95 | msg = M(self, 'system_invalid_username', state, username=value) |
|
95 | msg = M(self, 'system_invalid_username', state, username=value) | |
96 | raise formencode.Invalid(msg, value, state) |
|
96 | raise formencode.Invalid(msg, value, state) | |
97 | #check if user is unique |
|
97 | #check if user is unique | |
98 | old_un = None |
|
98 | old_un = None | |
99 | if edit: |
|
99 | if edit: | |
100 | old_un = User.get(old_data.get('user_id')).username |
|
100 | old_un = User.get(old_data.get('user_id')).username | |
101 |
|
101 | |||
102 | if old_un != value or not edit: |
|
102 | if old_un != value or not edit: | |
103 | if User.get_by_username(value, case_insensitive=True): |
|
103 | if User.get_by_username(value, case_insensitive=True): | |
104 | msg = M(self, 'username_exists', state, username=value) |
|
104 | msg = M(self, 'username_exists', state, username=value) | |
105 | raise formencode.Invalid(msg, value, state) |
|
105 | raise formencode.Invalid(msg, value, state) | |
106 |
|
106 | |||
107 | if re.match(r'^[a-zA-Z0-9]{1}[a-zA-Z0-9\-\_\.]*$', value) is None: |
|
107 | if re.match(r'^[a-zA-Z0-9]{1}[a-zA-Z0-9\-\_\.]*$', value) is None: | |
108 | msg = M(self, 'invalid_username', state) |
|
108 | msg = M(self, 'invalid_username', state) | |
109 | raise formencode.Invalid(msg, value, state) |
|
109 | raise formencode.Invalid(msg, value, state) | |
110 | return _validator |
|
110 | return _validator | |
111 |
|
111 | |||
112 |
|
112 | |||
113 | def ValidRepoUser(): |
|
113 | def ValidRepoUser(): | |
114 | class _validator(formencode.validators.FancyValidator): |
|
114 | class _validator(formencode.validators.FancyValidator): | |
115 | messages = { |
|
115 | messages = { | |
116 | 'invalid_username': _(u'Username %(username)s is not valid') |
|
116 | 'invalid_username': _(u'Username %(username)s is not valid') | |
117 | } |
|
117 | } | |
118 |
|
118 | |||
119 | def validate_python(self, value, state): |
|
119 | def validate_python(self, value, state): | |
120 | try: |
|
120 | try: | |
121 | User.query().filter(User.active == True)\ |
|
121 | User.query().filter(User.active == True)\ | |
122 | .filter(User.username == value).one() |
|
122 | .filter(User.username == value).one() | |
123 | except Exception: |
|
123 | except Exception: | |
124 | msg = M(self, 'invalid_username', state, username=value) |
|
124 | msg = M(self, 'invalid_username', state, username=value) | |
125 | raise formencode.Invalid(msg, value, state, |
|
125 | raise formencode.Invalid(msg, value, state, | |
126 | error_dict=dict(username=msg) |
|
126 | error_dict=dict(username=msg) | |
127 | ) |
|
127 | ) | |
128 |
|
128 | |||
129 | return _validator |
|
129 | return _validator | |
130 |
|
130 | |||
131 |
|
131 | |||
132 | def ValidUsersGroup(edit=False, old_data={}): |
|
132 | def ValidUsersGroup(edit=False, old_data={}): | |
133 | class _validator(formencode.validators.FancyValidator): |
|
133 | class _validator(formencode.validators.FancyValidator): | |
134 | messages = { |
|
134 | messages = { | |
135 |
'invalid_group': _(u'Invalid user |
|
135 | 'invalid_group': _(u'Invalid user group name'), | |
136 | 'group_exist': _(u'Users group "%(usersgroup)s" already exists'), |
|
136 | 'group_exist': _(u'Users group "%(usersgroup)s" already exists'), | |
137 | 'invalid_usersgroup_name': |
|
137 | 'invalid_usersgroup_name': | |
138 |
_(u'user |
|
138 | _(u'user group name may only contain alphanumeric ' | |
139 | 'characters underscores, periods or dashes and must begin ' |
|
139 | 'characters underscores, periods or dashes and must begin ' | |
140 | 'with alphanumeric character') |
|
140 | 'with alphanumeric character') | |
141 | } |
|
141 | } | |
142 |
|
142 | |||
143 | def validate_python(self, value, state): |
|
143 | def validate_python(self, value, state): | |
144 | if value in ['default']: |
|
144 | if value in ['default']: | |
145 | msg = M(self, 'invalid_group', state) |
|
145 | msg = M(self, 'invalid_group', state) | |
146 | raise formencode.Invalid(msg, value, state, |
|
146 | raise formencode.Invalid(msg, value, state, | |
147 | error_dict=dict(users_group_name=msg) |
|
147 | error_dict=dict(users_group_name=msg) | |
148 | ) |
|
148 | ) | |
149 | #check if group is unique |
|
149 | #check if group is unique | |
150 | old_ugname = None |
|
150 | old_ugname = None | |
151 | if edit: |
|
151 | if edit: | |
152 | old_id = old_data.get('users_group_id') |
|
152 | old_id = old_data.get('users_group_id') | |
153 | old_ugname = UsersGroup.get(old_id).users_group_name |
|
153 | old_ugname = UsersGroup.get(old_id).users_group_name | |
154 |
|
154 | |||
155 | if old_ugname != value or not edit: |
|
155 | if old_ugname != value or not edit: | |
156 | is_existing_group = UsersGroup.get_by_group_name(value, |
|
156 | is_existing_group = UsersGroup.get_by_group_name(value, | |
157 | case_insensitive=True) |
|
157 | case_insensitive=True) | |
158 | if is_existing_group: |
|
158 | if is_existing_group: | |
159 | msg = M(self, 'group_exist', state, usersgroup=value) |
|
159 | msg = M(self, 'group_exist', state, usersgroup=value) | |
160 | raise formencode.Invalid(msg, value, state, |
|
160 | raise formencode.Invalid(msg, value, state, | |
161 | error_dict=dict(users_group_name=msg) |
|
161 | error_dict=dict(users_group_name=msg) | |
162 | ) |
|
162 | ) | |
163 |
|
163 | |||
164 | if re.match(r'^[a-zA-Z0-9]{1}[a-zA-Z0-9\-\_\.]+$', value) is None: |
|
164 | if re.match(r'^[a-zA-Z0-9]{1}[a-zA-Z0-9\-\_\.]+$', value) is None: | |
165 | msg = M(self, 'invalid_usersgroup_name', state) |
|
165 | msg = M(self, 'invalid_usersgroup_name', state) | |
166 | raise formencode.Invalid(msg, value, state, |
|
166 | raise formencode.Invalid(msg, value, state, | |
167 | error_dict=dict(users_group_name=msg) |
|
167 | error_dict=dict(users_group_name=msg) | |
168 | ) |
|
168 | ) | |
169 |
|
169 | |||
170 | return _validator |
|
170 | return _validator | |
171 |
|
171 | |||
172 |
|
172 | |||
173 | def ValidReposGroup(edit=False, old_data={}): |
|
173 | def ValidReposGroup(edit=False, old_data={}): | |
174 | class _validator(formencode.validators.FancyValidator): |
|
174 | class _validator(formencode.validators.FancyValidator): | |
175 | messages = { |
|
175 | messages = { | |
176 | 'group_parent_id': _(u'Cannot assign this group as parent'), |
|
176 | 'group_parent_id': _(u'Cannot assign this group as parent'), | |
177 | 'group_exists': _(u'Group "%(group_name)s" already exists'), |
|
177 | 'group_exists': _(u'Group "%(group_name)s" already exists'), | |
178 | 'repo_exists': |
|
178 | 'repo_exists': | |
179 | _(u'Repository with name "%(group_name)s" already exists') |
|
179 | _(u'Repository with name "%(group_name)s" already exists') | |
180 | } |
|
180 | } | |
181 |
|
181 | |||
182 | def validate_python(self, value, state): |
|
182 | def validate_python(self, value, state): | |
183 | # TODO WRITE VALIDATIONS |
|
183 | # TODO WRITE VALIDATIONS | |
184 | group_name = value.get('group_name') |
|
184 | group_name = value.get('group_name') | |
185 | group_parent_id = value.get('group_parent_id') |
|
185 | group_parent_id = value.get('group_parent_id') | |
186 |
|
186 | |||
187 | # slugify repo group just in case :) |
|
187 | # slugify repo group just in case :) | |
188 | slug = repo_name_slug(group_name) |
|
188 | slug = repo_name_slug(group_name) | |
189 |
|
189 | |||
190 | # check for parent of self |
|
190 | # check for parent of self | |
191 | parent_of_self = lambda: ( |
|
191 | parent_of_self = lambda: ( | |
192 | old_data['group_id'] == int(group_parent_id) |
|
192 | old_data['group_id'] == int(group_parent_id) | |
193 | if group_parent_id else False |
|
193 | if group_parent_id else False | |
194 | ) |
|
194 | ) | |
195 | if edit and parent_of_self(): |
|
195 | if edit and parent_of_self(): | |
196 | msg = M(self, 'group_parent_id', state) |
|
196 | msg = M(self, 'group_parent_id', state) | |
197 | raise formencode.Invalid(msg, value, state, |
|
197 | raise formencode.Invalid(msg, value, state, | |
198 | error_dict=dict(group_parent_id=msg) |
|
198 | error_dict=dict(group_parent_id=msg) | |
199 | ) |
|
199 | ) | |
200 |
|
200 | |||
201 | old_gname = None |
|
201 | old_gname = None | |
202 | if edit: |
|
202 | if edit: | |
203 | old_gname = RepoGroup.get(old_data.get('group_id')).group_name |
|
203 | old_gname = RepoGroup.get(old_data.get('group_id')).group_name | |
204 |
|
204 | |||
205 | if old_gname != group_name or not edit: |
|
205 | if old_gname != group_name or not edit: | |
206 |
|
206 | |||
207 | # check group |
|
207 | # check group | |
208 | gr = RepoGroup.query()\ |
|
208 | gr = RepoGroup.query()\ | |
209 | .filter(RepoGroup.group_name == slug)\ |
|
209 | .filter(RepoGroup.group_name == slug)\ | |
210 | .filter(RepoGroup.group_parent_id == group_parent_id)\ |
|
210 | .filter(RepoGroup.group_parent_id == group_parent_id)\ | |
211 | .scalar() |
|
211 | .scalar() | |
212 |
|
212 | |||
213 | if gr: |
|
213 | if gr: | |
214 | msg = M(self, 'group_exists', state, group_name=slug) |
|
214 | msg = M(self, 'group_exists', state, group_name=slug) | |
215 | raise formencode.Invalid(msg, value, state, |
|
215 | raise formencode.Invalid(msg, value, state, | |
216 | error_dict=dict(group_name=msg) |
|
216 | error_dict=dict(group_name=msg) | |
217 | ) |
|
217 | ) | |
218 |
|
218 | |||
219 | # check for same repo |
|
219 | # check for same repo | |
220 | repo = Repository.query()\ |
|
220 | repo = Repository.query()\ | |
221 | .filter(Repository.repo_name == slug)\ |
|
221 | .filter(Repository.repo_name == slug)\ | |
222 | .scalar() |
|
222 | .scalar() | |
223 |
|
223 | |||
224 | if repo: |
|
224 | if repo: | |
225 | msg = M(self, 'repo_exists', state, group_name=slug) |
|
225 | msg = M(self, 'repo_exists', state, group_name=slug) | |
226 | raise formencode.Invalid(msg, value, state, |
|
226 | raise formencode.Invalid(msg, value, state, | |
227 | error_dict=dict(group_name=msg) |
|
227 | error_dict=dict(group_name=msg) | |
228 | ) |
|
228 | ) | |
229 |
|
229 | |||
230 | return _validator |
|
230 | return _validator | |
231 |
|
231 | |||
232 |
|
232 | |||
233 | def ValidPassword(): |
|
233 | def ValidPassword(): | |
234 | class _validator(formencode.validators.FancyValidator): |
|
234 | class _validator(formencode.validators.FancyValidator): | |
235 | messages = { |
|
235 | messages = { | |
236 | 'invalid_password': |
|
236 | 'invalid_password': | |
237 | _(u'Invalid characters (non-ascii) in password') |
|
237 | _(u'Invalid characters (non-ascii) in password') | |
238 | } |
|
238 | } | |
239 |
|
239 | |||
240 | def validate_python(self, value, state): |
|
240 | def validate_python(self, value, state): | |
241 | try: |
|
241 | try: | |
242 | (value or '').decode('ascii') |
|
242 | (value or '').decode('ascii') | |
243 | except UnicodeError: |
|
243 | except UnicodeError: | |
244 | msg = M(self, 'invalid_password', state) |
|
244 | msg = M(self, 'invalid_password', state) | |
245 | raise formencode.Invalid(msg, value, state,) |
|
245 | raise formencode.Invalid(msg, value, state,) | |
246 | return _validator |
|
246 | return _validator | |
247 |
|
247 | |||
248 |
|
248 | |||
249 | def ValidPasswordsMatch(): |
|
249 | def ValidPasswordsMatch(): | |
250 | class _validator(formencode.validators.FancyValidator): |
|
250 | class _validator(formencode.validators.FancyValidator): | |
251 | messages = { |
|
251 | messages = { | |
252 | 'password_mismatch': _(u'Passwords do not match'), |
|
252 | 'password_mismatch': _(u'Passwords do not match'), | |
253 | } |
|
253 | } | |
254 |
|
254 | |||
255 | def validate_python(self, value, state): |
|
255 | def validate_python(self, value, state): | |
256 |
|
256 | |||
257 | pass_val = value.get('password') or value.get('new_password') |
|
257 | pass_val = value.get('password') or value.get('new_password') | |
258 | if pass_val != value['password_confirmation']: |
|
258 | if pass_val != value['password_confirmation']: | |
259 | msg = M(self, 'password_mismatch', state) |
|
259 | msg = M(self, 'password_mismatch', state) | |
260 | raise formencode.Invalid(msg, value, state, |
|
260 | raise formencode.Invalid(msg, value, state, | |
261 | error_dict=dict(password_confirmation=msg) |
|
261 | error_dict=dict(password_confirmation=msg) | |
262 | ) |
|
262 | ) | |
263 | return _validator |
|
263 | return _validator | |
264 |
|
264 | |||
265 |
|
265 | |||
266 | def ValidAuth(): |
|
266 | def ValidAuth(): | |
267 | class _validator(formencode.validators.FancyValidator): |
|
267 | class _validator(formencode.validators.FancyValidator): | |
268 | messages = { |
|
268 | messages = { | |
269 | 'invalid_password': _(u'invalid password'), |
|
269 | 'invalid_password': _(u'invalid password'), | |
270 | 'invalid_username': _(u'invalid user name'), |
|
270 | 'invalid_username': _(u'invalid user name'), | |
271 | 'disabled_account': _(u'Your account is disabled') |
|
271 | 'disabled_account': _(u'Your account is disabled') | |
272 | } |
|
272 | } | |
273 |
|
273 | |||
274 | def validate_python(self, value, state): |
|
274 | def validate_python(self, value, state): | |
275 | from rhodecode.lib.auth import authenticate |
|
275 | from rhodecode.lib.auth import authenticate | |
276 |
|
276 | |||
277 | password = value['password'] |
|
277 | password = value['password'] | |
278 | username = value['username'] |
|
278 | username = value['username'] | |
279 |
|
279 | |||
280 | if not authenticate(username, password): |
|
280 | if not authenticate(username, password): | |
281 | user = User.get_by_username(username) |
|
281 | user = User.get_by_username(username) | |
282 | if user and user.active is False: |
|
282 | if user and user.active is False: | |
283 | log.warning('user %s is disabled' % username) |
|
283 | log.warning('user %s is disabled' % username) | |
284 | msg = M(self, 'disabled_account', state) |
|
284 | msg = M(self, 'disabled_account', state) | |
285 | raise formencode.Invalid(msg, value, state, |
|
285 | raise formencode.Invalid(msg, value, state, | |
286 | error_dict=dict(username=msg) |
|
286 | error_dict=dict(username=msg) | |
287 | ) |
|
287 | ) | |
288 | else: |
|
288 | else: | |
289 | log.warning('user %s failed to authenticate' % username) |
|
289 | log.warning('user %s failed to authenticate' % username) | |
290 | msg = M(self, 'invalid_username', state) |
|
290 | msg = M(self, 'invalid_username', state) | |
291 | msg2 = M(self, 'invalid_password', state) |
|
291 | msg2 = M(self, 'invalid_password', state) | |
292 | raise formencode.Invalid(msg, value, state, |
|
292 | raise formencode.Invalid(msg, value, state, | |
293 | error_dict=dict(username=msg, password=msg2) |
|
293 | error_dict=dict(username=msg, password=msg2) | |
294 | ) |
|
294 | ) | |
295 | return _validator |
|
295 | return _validator | |
296 |
|
296 | |||
297 |
|
297 | |||
298 | def ValidAuthToken(): |
|
298 | def ValidAuthToken(): | |
299 | class _validator(formencode.validators.FancyValidator): |
|
299 | class _validator(formencode.validators.FancyValidator): | |
300 | messages = { |
|
300 | messages = { | |
301 | 'invalid_token': _(u'Token mismatch') |
|
301 | 'invalid_token': _(u'Token mismatch') | |
302 | } |
|
302 | } | |
303 |
|
303 | |||
304 | def validate_python(self, value, state): |
|
304 | def validate_python(self, value, state): | |
305 | if value != authentication_token(): |
|
305 | if value != authentication_token(): | |
306 | msg = M(self, 'invalid_token', state) |
|
306 | msg = M(self, 'invalid_token', state) | |
307 | raise formencode.Invalid(msg, value, state) |
|
307 | raise formencode.Invalid(msg, value, state) | |
308 | return _validator |
|
308 | return _validator | |
309 |
|
309 | |||
310 |
|
310 | |||
311 | def ValidRepoName(edit=False, old_data={}): |
|
311 | def ValidRepoName(edit=False, old_data={}): | |
312 | class _validator(formencode.validators.FancyValidator): |
|
312 | class _validator(formencode.validators.FancyValidator): | |
313 | messages = { |
|
313 | messages = { | |
314 | 'invalid_repo_name': |
|
314 | 'invalid_repo_name': | |
315 | _(u'Repository name %(repo)s is disallowed'), |
|
315 | _(u'Repository name %(repo)s is disallowed'), | |
316 | 'repository_exists': |
|
316 | 'repository_exists': | |
317 | _(u'Repository named %(repo)s already exists'), |
|
317 | _(u'Repository named %(repo)s already exists'), | |
318 | 'repository_in_group_exists': _(u'Repository "%(repo)s" already ' |
|
318 | 'repository_in_group_exists': _(u'Repository "%(repo)s" already ' | |
319 | 'exists in group "%(group)s"'), |
|
319 | 'exists in group "%(group)s"'), | |
320 | 'same_group_exists': _(u'Repositories group with name "%(repo)s" ' |
|
320 | 'same_group_exists': _(u'Repositories group with name "%(repo)s" ' | |
321 | 'already exists') |
|
321 | 'already exists') | |
322 | } |
|
322 | } | |
323 |
|
323 | |||
324 | def _to_python(self, value, state): |
|
324 | def _to_python(self, value, state): | |
325 | repo_name = repo_name_slug(value.get('repo_name', '')) |
|
325 | repo_name = repo_name_slug(value.get('repo_name', '')) | |
326 | repo_group = value.get('repo_group') |
|
326 | repo_group = value.get('repo_group') | |
327 | if repo_group: |
|
327 | if repo_group: | |
328 | gr = RepoGroup.get(repo_group) |
|
328 | gr = RepoGroup.get(repo_group) | |
329 | group_path = gr.full_path |
|
329 | group_path = gr.full_path | |
330 | group_name = gr.group_name |
|
330 | group_name = gr.group_name | |
331 | # value needs to be aware of group name in order to check |
|
331 | # value needs to be aware of group name in order to check | |
332 | # db key This is an actual just the name to store in the |
|
332 | # db key This is an actual just the name to store in the | |
333 | # database |
|
333 | # database | |
334 | repo_name_full = group_path + RepoGroup.url_sep() + repo_name |
|
334 | repo_name_full = group_path + RepoGroup.url_sep() + repo_name | |
335 | else: |
|
335 | else: | |
336 | group_name = group_path = '' |
|
336 | group_name = group_path = '' | |
337 | repo_name_full = repo_name |
|
337 | repo_name_full = repo_name | |
338 |
|
338 | |||
339 | value['repo_name'] = repo_name |
|
339 | value['repo_name'] = repo_name | |
340 | value['repo_name_full'] = repo_name_full |
|
340 | value['repo_name_full'] = repo_name_full | |
341 | value['group_path'] = group_path |
|
341 | value['group_path'] = group_path | |
342 | value['group_name'] = group_name |
|
342 | value['group_name'] = group_name | |
343 | return value |
|
343 | return value | |
344 |
|
344 | |||
345 | def validate_python(self, value, state): |
|
345 | def validate_python(self, value, state): | |
346 |
|
346 | |||
347 | repo_name = value.get('repo_name') |
|
347 | repo_name = value.get('repo_name') | |
348 | repo_name_full = value.get('repo_name_full') |
|
348 | repo_name_full = value.get('repo_name_full') | |
349 | group_path = value.get('group_path') |
|
349 | group_path = value.get('group_path') | |
350 | group_name = value.get('group_name') |
|
350 | group_name = value.get('group_name') | |
351 |
|
351 | |||
352 | if repo_name in [ADMIN_PREFIX, '']: |
|
352 | if repo_name in [ADMIN_PREFIX, '']: | |
353 | msg = M(self, 'invalid_repo_name', state, repo=repo_name) |
|
353 | msg = M(self, 'invalid_repo_name', state, repo=repo_name) | |
354 | raise formencode.Invalid(msg, value, state, |
|
354 | raise formencode.Invalid(msg, value, state, | |
355 | error_dict=dict(repo_name=msg) |
|
355 | error_dict=dict(repo_name=msg) | |
356 | ) |
|
356 | ) | |
357 |
|
357 | |||
358 | rename = old_data.get('repo_name') != repo_name_full |
|
358 | rename = old_data.get('repo_name') != repo_name_full | |
359 | create = not edit |
|
359 | create = not edit | |
360 | if rename or create: |
|
360 | if rename or create: | |
361 |
|
361 | |||
362 | if group_path != '': |
|
362 | if group_path != '': | |
363 | if Repository.get_by_repo_name(repo_name_full): |
|
363 | if Repository.get_by_repo_name(repo_name_full): | |
364 | msg = M(self, 'repository_in_group_exists', state, |
|
364 | msg = M(self, 'repository_in_group_exists', state, | |
365 | repo=repo_name, group=group_name) |
|
365 | repo=repo_name, group=group_name) | |
366 | raise formencode.Invalid(msg, value, state, |
|
366 | raise formencode.Invalid(msg, value, state, | |
367 | error_dict=dict(repo_name=msg) |
|
367 | error_dict=dict(repo_name=msg) | |
368 | ) |
|
368 | ) | |
369 | elif RepoGroup.get_by_group_name(repo_name_full): |
|
369 | elif RepoGroup.get_by_group_name(repo_name_full): | |
370 | msg = M(self, 'same_group_exists', state, |
|
370 | msg = M(self, 'same_group_exists', state, | |
371 | repo=repo_name) |
|
371 | repo=repo_name) | |
372 | raise formencode.Invalid(msg, value, state, |
|
372 | raise formencode.Invalid(msg, value, state, | |
373 | error_dict=dict(repo_name=msg) |
|
373 | error_dict=dict(repo_name=msg) | |
374 | ) |
|
374 | ) | |
375 |
|
375 | |||
376 | elif Repository.get_by_repo_name(repo_name_full): |
|
376 | elif Repository.get_by_repo_name(repo_name_full): | |
377 | msg = M(self, 'repository_exists', state, |
|
377 | msg = M(self, 'repository_exists', state, | |
378 | repo=repo_name) |
|
378 | repo=repo_name) | |
379 | raise formencode.Invalid(msg, value, state, |
|
379 | raise formencode.Invalid(msg, value, state, | |
380 | error_dict=dict(repo_name=msg) |
|
380 | error_dict=dict(repo_name=msg) | |
381 | ) |
|
381 | ) | |
382 | return value |
|
382 | return value | |
383 | return _validator |
|
383 | return _validator | |
384 |
|
384 | |||
385 |
|
385 | |||
386 | def ValidForkName(*args, **kwargs): |
|
386 | def ValidForkName(*args, **kwargs): | |
387 | return ValidRepoName(*args, **kwargs) |
|
387 | return ValidRepoName(*args, **kwargs) | |
388 |
|
388 | |||
389 |
|
389 | |||
390 | def SlugifyName(): |
|
390 | def SlugifyName(): | |
391 | class _validator(formencode.validators.FancyValidator): |
|
391 | class _validator(formencode.validators.FancyValidator): | |
392 |
|
392 | |||
393 | def _to_python(self, value, state): |
|
393 | def _to_python(self, value, state): | |
394 | return repo_name_slug(value) |
|
394 | return repo_name_slug(value) | |
395 |
|
395 | |||
396 | def validate_python(self, value, state): |
|
396 | def validate_python(self, value, state): | |
397 | pass |
|
397 | pass | |
398 |
|
398 | |||
399 | return _validator |
|
399 | return _validator | |
400 |
|
400 | |||
401 |
|
401 | |||
402 | def ValidCloneUri(): |
|
402 | def ValidCloneUri(): | |
403 | from rhodecode.lib.utils import make_ui |
|
403 | from rhodecode.lib.utils import make_ui | |
404 |
|
404 | |||
405 | def url_handler(repo_type, url, ui=None): |
|
405 | def url_handler(repo_type, url, ui=None): | |
406 | if repo_type == 'hg': |
|
406 | if repo_type == 'hg': | |
407 | from rhodecode.lib.vcs.backends.hg.repository import MercurialRepository |
|
407 | from rhodecode.lib.vcs.backends.hg.repository import MercurialRepository | |
408 | from mercurial.httppeer import httppeer |
|
408 | from mercurial.httppeer import httppeer | |
409 | if url.startswith('http'): |
|
409 | if url.startswith('http'): | |
410 | ## initially check if it's at least the proper URL |
|
410 | ## initially check if it's at least the proper URL | |
411 | ## or does it pass basic auth |
|
411 | ## or does it pass basic auth | |
412 | MercurialRepository._check_url(url) |
|
412 | MercurialRepository._check_url(url) | |
413 | httppeer(ui, url)._capabilities() |
|
413 | httppeer(ui, url)._capabilities() | |
414 | elif url.startswith('svn+http'): |
|
414 | elif url.startswith('svn+http'): | |
415 | from hgsubversion.svnrepo import svnremoterepo |
|
415 | from hgsubversion.svnrepo import svnremoterepo | |
416 | svnremoterepo(ui, url).capabilities |
|
416 | svnremoterepo(ui, url).capabilities | |
417 | elif url.startswith('git+http'): |
|
417 | elif url.startswith('git+http'): | |
418 | raise NotImplementedError() |
|
418 | raise NotImplementedError() | |
419 |
|
419 | |||
420 | elif repo_type == 'git': |
|
420 | elif repo_type == 'git': | |
421 | from rhodecode.lib.vcs.backends.git.repository import GitRepository |
|
421 | from rhodecode.lib.vcs.backends.git.repository import GitRepository | |
422 | if url.startswith('http'): |
|
422 | if url.startswith('http'): | |
423 | ## initially check if it's at least the proper URL |
|
423 | ## initially check if it's at least the proper URL | |
424 | ## or does it pass basic auth |
|
424 | ## or does it pass basic auth | |
425 | GitRepository._check_url(url) |
|
425 | GitRepository._check_url(url) | |
426 | elif url.startswith('svn+http'): |
|
426 | elif url.startswith('svn+http'): | |
427 | raise NotImplementedError() |
|
427 | raise NotImplementedError() | |
428 | elif url.startswith('hg+http'): |
|
428 | elif url.startswith('hg+http'): | |
429 | raise NotImplementedError() |
|
429 | raise NotImplementedError() | |
430 |
|
430 | |||
431 | class _validator(formencode.validators.FancyValidator): |
|
431 | class _validator(formencode.validators.FancyValidator): | |
432 | messages = { |
|
432 | messages = { | |
433 | 'clone_uri': _(u'invalid clone url'), |
|
433 | 'clone_uri': _(u'invalid clone url'), | |
434 | 'invalid_clone_uri': _(u'Invalid clone url, provide a ' |
|
434 | 'invalid_clone_uri': _(u'Invalid clone url, provide a ' | |
435 | 'valid clone http(s)/svn+http(s) url') |
|
435 | 'valid clone http(s)/svn+http(s) url') | |
436 | } |
|
436 | } | |
437 |
|
437 | |||
438 | def validate_python(self, value, state): |
|
438 | def validate_python(self, value, state): | |
439 | repo_type = value.get('repo_type') |
|
439 | repo_type = value.get('repo_type') | |
440 | url = value.get('clone_uri') |
|
440 | url = value.get('clone_uri') | |
441 |
|
441 | |||
442 | if not url: |
|
442 | if not url: | |
443 | pass |
|
443 | pass | |
444 | else: |
|
444 | else: | |
445 | try: |
|
445 | try: | |
446 | url_handler(repo_type, url, make_ui('db', clear_session=False)) |
|
446 | url_handler(repo_type, url, make_ui('db', clear_session=False)) | |
447 | except Exception: |
|
447 | except Exception: | |
448 | log.exception('Url validation failed') |
|
448 | log.exception('Url validation failed') | |
449 | msg = M(self, 'clone_uri') |
|
449 | msg = M(self, 'clone_uri') | |
450 | raise formencode.Invalid(msg, value, state, |
|
450 | raise formencode.Invalid(msg, value, state, | |
451 | error_dict=dict(clone_uri=msg) |
|
451 | error_dict=dict(clone_uri=msg) | |
452 | ) |
|
452 | ) | |
453 | return _validator |
|
453 | return _validator | |
454 |
|
454 | |||
455 |
|
455 | |||
456 | def ValidForkType(old_data={}): |
|
456 | def ValidForkType(old_data={}): | |
457 | class _validator(formencode.validators.FancyValidator): |
|
457 | class _validator(formencode.validators.FancyValidator): | |
458 | messages = { |
|
458 | messages = { | |
459 | 'invalid_fork_type': _(u'Fork have to be the same type as parent') |
|
459 | 'invalid_fork_type': _(u'Fork have to be the same type as parent') | |
460 | } |
|
460 | } | |
461 |
|
461 | |||
462 | def validate_python(self, value, state): |
|
462 | def validate_python(self, value, state): | |
463 | if old_data['repo_type'] != value: |
|
463 | if old_data['repo_type'] != value: | |
464 | msg = M(self, 'invalid_fork_type', state) |
|
464 | msg = M(self, 'invalid_fork_type', state) | |
465 | raise formencode.Invalid(msg, value, state, |
|
465 | raise formencode.Invalid(msg, value, state, | |
466 | error_dict=dict(repo_type=msg) |
|
466 | error_dict=dict(repo_type=msg) | |
467 | ) |
|
467 | ) | |
468 | return _validator |
|
468 | return _validator | |
469 |
|
469 | |||
470 |
|
470 | |||
471 | def CanWriteGroup(): |
|
471 | def CanWriteGroup(): | |
472 | class _validator(formencode.validators.FancyValidator): |
|
472 | class _validator(formencode.validators.FancyValidator): | |
473 | messages = { |
|
473 | messages = { | |
474 | 'permission_denied': _(u"You don't have permissions " |
|
474 | 'permission_denied': _(u"You don't have permissions " | |
475 | "to create repository in this group"), |
|
475 | "to create repository in this group"), | |
476 | 'permission_denied_root': _(u"no permission to create repository " |
|
476 | 'permission_denied_root': _(u"no permission to create repository " | |
477 | "in root location") |
|
477 | "in root location") | |
478 | } |
|
478 | } | |
479 |
|
479 | |||
480 | def _to_python(self, value, state): |
|
480 | def _to_python(self, value, state): | |
481 | #root location |
|
481 | #root location | |
482 | if value in [-1, "-1"]: |
|
482 | if value in [-1, "-1"]: | |
483 | return None |
|
483 | return None | |
484 | return value |
|
484 | return value | |
485 |
|
485 | |||
486 | def validate_python(self, value, state): |
|
486 | def validate_python(self, value, state): | |
487 | gr = RepoGroup.get(value) |
|
487 | gr = RepoGroup.get(value) | |
488 | gr_name = gr.group_name if gr else None # None means ROOT location |
|
488 | gr_name = gr.group_name if gr else None # None means ROOT location | |
489 | val = HasReposGroupPermissionAny('group.write', 'group.admin') |
|
489 | val = HasReposGroupPermissionAny('group.write', 'group.admin') | |
490 | can_create_repos = HasPermissionAny('hg.admin', 'hg.create.repository') |
|
490 | can_create_repos = HasPermissionAny('hg.admin', 'hg.create.repository') | |
491 | forbidden = not val(gr_name, 'can write into group validator') |
|
491 | forbidden = not val(gr_name, 'can write into group validator') | |
492 | #parent group need to be existing |
|
492 | #parent group need to be existing | |
493 | if gr and forbidden: |
|
493 | if gr and forbidden: | |
494 | msg = M(self, 'permission_denied', state) |
|
494 | msg = M(self, 'permission_denied', state) | |
495 | raise formencode.Invalid(msg, value, state, |
|
495 | raise formencode.Invalid(msg, value, state, | |
496 | error_dict=dict(repo_type=msg) |
|
496 | error_dict=dict(repo_type=msg) | |
497 | ) |
|
497 | ) | |
498 | ## check if we can write to root location ! |
|
498 | ## check if we can write to root location ! | |
499 | elif gr is None and can_create_repos() is False: |
|
499 | elif gr is None and can_create_repos() is False: | |
500 | msg = M(self, 'permission_denied_root', state) |
|
500 | msg = M(self, 'permission_denied_root', state) | |
501 | raise formencode.Invalid(msg, value, state, |
|
501 | raise formencode.Invalid(msg, value, state, | |
502 | error_dict=dict(repo_type=msg) |
|
502 | error_dict=dict(repo_type=msg) | |
503 | ) |
|
503 | ) | |
504 |
|
504 | |||
505 | return _validator |
|
505 | return _validator | |
506 |
|
506 | |||
507 |
|
507 | |||
508 | def CanCreateGroup(can_create_in_root=False): |
|
508 | def CanCreateGroup(can_create_in_root=False): | |
509 | class _validator(formencode.validators.FancyValidator): |
|
509 | class _validator(formencode.validators.FancyValidator): | |
510 | messages = { |
|
510 | messages = { | |
511 | 'permission_denied': _(u"You don't have permissions " |
|
511 | 'permission_denied': _(u"You don't have permissions " | |
512 | "to create a group in this location") |
|
512 | "to create a group in this location") | |
513 | } |
|
513 | } | |
514 |
|
514 | |||
515 | def to_python(self, value, state): |
|
515 | def to_python(self, value, state): | |
516 | #root location |
|
516 | #root location | |
517 | if value in [-1, "-1"]: |
|
517 | if value in [-1, "-1"]: | |
518 | return None |
|
518 | return None | |
519 | return value |
|
519 | return value | |
520 |
|
520 | |||
521 | def validate_python(self, value, state): |
|
521 | def validate_python(self, value, state): | |
522 | gr = RepoGroup.get(value) |
|
522 | gr = RepoGroup.get(value) | |
523 | gr_name = gr.group_name if gr else None # None means ROOT location |
|
523 | gr_name = gr.group_name if gr else None # None means ROOT location | |
524 |
|
524 | |||
525 | if can_create_in_root and gr is None: |
|
525 | if can_create_in_root and gr is None: | |
526 | #we can create in root, we're fine no validations required |
|
526 | #we can create in root, we're fine no validations required | |
527 | return |
|
527 | return | |
528 |
|
528 | |||
529 | forbidden_in_root = gr is None and can_create_in_root is False |
|
529 | forbidden_in_root = gr is None and can_create_in_root is False | |
530 | val = HasReposGroupPermissionAny('group.admin') |
|
530 | val = HasReposGroupPermissionAny('group.admin') | |
531 | forbidden = not val(gr_name, 'can create group validator') |
|
531 | forbidden = not val(gr_name, 'can create group validator') | |
532 | if forbidden_in_root or forbidden: |
|
532 | if forbidden_in_root or forbidden: | |
533 | msg = M(self, 'permission_denied', state) |
|
533 | msg = M(self, 'permission_denied', state) | |
534 | raise formencode.Invalid(msg, value, state, |
|
534 | raise formencode.Invalid(msg, value, state, | |
535 | error_dict=dict(group_parent_id=msg) |
|
535 | error_dict=dict(group_parent_id=msg) | |
536 | ) |
|
536 | ) | |
537 |
|
537 | |||
538 | return _validator |
|
538 | return _validator | |
539 |
|
539 | |||
540 |
|
540 | |||
541 | def ValidPerms(type_='repo'): |
|
541 | def ValidPerms(type_='repo'): | |
542 | if type_ == 'group': |
|
542 | if type_ == 'group': | |
543 | EMPTY_PERM = 'group.none' |
|
543 | EMPTY_PERM = 'group.none' | |
544 | elif type_ == 'repo': |
|
544 | elif type_ == 'repo': | |
545 | EMPTY_PERM = 'repository.none' |
|
545 | EMPTY_PERM = 'repository.none' | |
546 |
|
546 | |||
547 | class _validator(formencode.validators.FancyValidator): |
|
547 | class _validator(formencode.validators.FancyValidator): | |
548 | messages = { |
|
548 | messages = { | |
549 | 'perm_new_member_name': |
|
549 | 'perm_new_member_name': | |
550 |
_(u'This username or user |
|
550 | _(u'This username or user group name is not valid') | |
551 | } |
|
551 | } | |
552 |
|
552 | |||
553 | def to_python(self, value, state): |
|
553 | def to_python(self, value, state): | |
554 | perms_update = OrderedSet() |
|
554 | perms_update = OrderedSet() | |
555 | perms_new = OrderedSet() |
|
555 | perms_new = OrderedSet() | |
556 | # build a list of permission to update and new permission to create |
|
556 | # build a list of permission to update and new permission to create | |
557 |
|
557 | |||
558 | #CLEAN OUT ORG VALUE FROM NEW MEMBERS, and group them using |
|
558 | #CLEAN OUT ORG VALUE FROM NEW MEMBERS, and group them using | |
559 | new_perms_group = defaultdict(dict) |
|
559 | new_perms_group = defaultdict(dict) | |
560 | for k, v in value.copy().iteritems(): |
|
560 | for k, v in value.copy().iteritems(): | |
561 | if k.startswith('perm_new_member'): |
|
561 | if k.startswith('perm_new_member'): | |
562 | del value[k] |
|
562 | del value[k] | |
563 | _type, part = k.split('perm_new_member_') |
|
563 | _type, part = k.split('perm_new_member_') | |
564 | args = part.split('_') |
|
564 | args = part.split('_') | |
565 | if len(args) == 1: |
|
565 | if len(args) == 1: | |
566 | new_perms_group[args[0]]['perm'] = v |
|
566 | new_perms_group[args[0]]['perm'] = v | |
567 | elif len(args) == 2: |
|
567 | elif len(args) == 2: | |
568 | _key, pos = args |
|
568 | _key, pos = args | |
569 | new_perms_group[pos][_key] = v |
|
569 | new_perms_group[pos][_key] = v | |
570 |
|
570 | |||
571 | # fill new permissions in order of how they were added |
|
571 | # fill new permissions in order of how they were added | |
572 | for k in sorted(map(int, new_perms_group.keys())): |
|
572 | for k in sorted(map(int, new_perms_group.keys())): | |
573 | perm_dict = new_perms_group[str(k)] |
|
573 | perm_dict = new_perms_group[str(k)] | |
574 | new_member = perm_dict.get('name') |
|
574 | new_member = perm_dict.get('name') | |
575 | new_perm = perm_dict.get('perm') |
|
575 | new_perm = perm_dict.get('perm') | |
576 | new_type = perm_dict.get('type') |
|
576 | new_type = perm_dict.get('type') | |
577 | if new_member and new_perm and new_type: |
|
577 | if new_member and new_perm and new_type: | |
578 | perms_new.add((new_member, new_perm, new_type)) |
|
578 | perms_new.add((new_member, new_perm, new_type)) | |
579 |
|
579 | |||
580 | for k, v in value.iteritems(): |
|
580 | for k, v in value.iteritems(): | |
581 | if k.startswith('u_perm_') or k.startswith('g_perm_'): |
|
581 | if k.startswith('u_perm_') or k.startswith('g_perm_'): | |
582 | member = k[7:] |
|
582 | member = k[7:] | |
583 | t = {'u': 'user', |
|
583 | t = {'u': 'user', | |
584 | 'g': 'users_group' |
|
584 | 'g': 'users_group' | |
585 | }[k[0]] |
|
585 | }[k[0]] | |
586 | if member == 'default': |
|
586 | if member == 'default': | |
587 | if value.get('repo_private'): |
|
587 | if value.get('repo_private'): | |
588 | # set none for default when updating to |
|
588 | # set none for default when updating to | |
589 | # private repo |
|
589 | # private repo | |
590 | v = EMPTY_PERM |
|
590 | v = EMPTY_PERM | |
591 | perms_update.add((member, v, t)) |
|
591 | perms_update.add((member, v, t)) | |
592 | #always set NONE when private flag is set |
|
592 | #always set NONE when private flag is set | |
593 | if value.get('repo_private'): |
|
593 | if value.get('repo_private'): | |
594 | perms_update.add(('default', EMPTY_PERM, 'user')) |
|
594 | perms_update.add(('default', EMPTY_PERM, 'user')) | |
595 |
|
595 | |||
596 | value['perms_updates'] = list(perms_update) |
|
596 | value['perms_updates'] = list(perms_update) | |
597 | value['perms_new'] = list(perms_new) |
|
597 | value['perms_new'] = list(perms_new) | |
598 |
|
598 | |||
599 | # update permissions |
|
599 | # update permissions | |
600 | for k, v, t in perms_new: |
|
600 | for k, v, t in perms_new: | |
601 | try: |
|
601 | try: | |
602 | if t is 'user': |
|
602 | if t is 'user': | |
603 | self.user_db = User.query()\ |
|
603 | self.user_db = User.query()\ | |
604 | .filter(User.active == True)\ |
|
604 | .filter(User.active == True)\ | |
605 | .filter(User.username == k).one() |
|
605 | .filter(User.username == k).one() | |
606 | if t is 'users_group': |
|
606 | if t is 'users_group': | |
607 | self.user_db = UsersGroup.query()\ |
|
607 | self.user_db = UsersGroup.query()\ | |
608 | .filter(UsersGroup.users_group_active == True)\ |
|
608 | .filter(UsersGroup.users_group_active == True)\ | |
609 | .filter(UsersGroup.users_group_name == k).one() |
|
609 | .filter(UsersGroup.users_group_name == k).one() | |
610 |
|
610 | |||
611 | except Exception: |
|
611 | except Exception: | |
612 | log.exception('Updated permission failed') |
|
612 | log.exception('Updated permission failed') | |
613 | msg = M(self, 'perm_new_member_type', state) |
|
613 | msg = M(self, 'perm_new_member_type', state) | |
614 | raise formencode.Invalid(msg, value, state, |
|
614 | raise formencode.Invalid(msg, value, state, | |
615 | error_dict=dict(perm_new_member_name=msg) |
|
615 | error_dict=dict(perm_new_member_name=msg) | |
616 | ) |
|
616 | ) | |
617 | return value |
|
617 | return value | |
618 | return _validator |
|
618 | return _validator | |
619 |
|
619 | |||
620 |
|
620 | |||
621 | def ValidSettings(): |
|
621 | def ValidSettings(): | |
622 | class _validator(formencode.validators.FancyValidator): |
|
622 | class _validator(formencode.validators.FancyValidator): | |
623 | def _to_python(self, value, state): |
|
623 | def _to_python(self, value, state): | |
624 | # settings form for users that are not admin |
|
624 | # settings form for users that are not admin | |
625 | # can't edit certain parameters, it's extra backup if they mangle |
|
625 | # can't edit certain parameters, it's extra backup if they mangle | |
626 | # with forms |
|
626 | # with forms | |
627 |
|
627 | |||
628 | forbidden_params = [ |
|
628 | forbidden_params = [ | |
629 | 'user', 'repo_type', 'repo_enable_locking', |
|
629 | 'user', 'repo_type', 'repo_enable_locking', | |
630 | 'repo_enable_downloads', 'repo_enable_statistics' |
|
630 | 'repo_enable_downloads', 'repo_enable_statistics' | |
631 | ] |
|
631 | ] | |
632 |
|
632 | |||
633 | for param in forbidden_params: |
|
633 | for param in forbidden_params: | |
634 | if param in value: |
|
634 | if param in value: | |
635 | del value[param] |
|
635 | del value[param] | |
636 | return value |
|
636 | return value | |
637 |
|
637 | |||
638 | def validate_python(self, value, state): |
|
638 | def validate_python(self, value, state): | |
639 | pass |
|
639 | pass | |
640 | return _validator |
|
640 | return _validator | |
641 |
|
641 | |||
642 |
|
642 | |||
643 | def ValidPath(): |
|
643 | def ValidPath(): | |
644 | class _validator(formencode.validators.FancyValidator): |
|
644 | class _validator(formencode.validators.FancyValidator): | |
645 | messages = { |
|
645 | messages = { | |
646 | 'invalid_path': _(u'This is not a valid path') |
|
646 | 'invalid_path': _(u'This is not a valid path') | |
647 | } |
|
647 | } | |
648 |
|
648 | |||
649 | def validate_python(self, value, state): |
|
649 | def validate_python(self, value, state): | |
650 | if not os.path.isdir(value): |
|
650 | if not os.path.isdir(value): | |
651 | msg = M(self, 'invalid_path', state) |
|
651 | msg = M(self, 'invalid_path', state) | |
652 | raise formencode.Invalid(msg, value, state, |
|
652 | raise formencode.Invalid(msg, value, state, | |
653 | error_dict=dict(paths_root_path=msg) |
|
653 | error_dict=dict(paths_root_path=msg) | |
654 | ) |
|
654 | ) | |
655 | return _validator |
|
655 | return _validator | |
656 |
|
656 | |||
657 |
|
657 | |||
658 | def UniqSystemEmail(old_data={}): |
|
658 | def UniqSystemEmail(old_data={}): | |
659 | class _validator(formencode.validators.FancyValidator): |
|
659 | class _validator(formencode.validators.FancyValidator): | |
660 | messages = { |
|
660 | messages = { | |
661 | 'email_taken': _(u'This e-mail address is already taken') |
|
661 | 'email_taken': _(u'This e-mail address is already taken') | |
662 | } |
|
662 | } | |
663 |
|
663 | |||
664 | def _to_python(self, value, state): |
|
664 | def _to_python(self, value, state): | |
665 | return value.lower() |
|
665 | return value.lower() | |
666 |
|
666 | |||
667 | def validate_python(self, value, state): |
|
667 | def validate_python(self, value, state): | |
668 | if (old_data.get('email') or '').lower() != value: |
|
668 | if (old_data.get('email') or '').lower() != value: | |
669 | user = User.get_by_email(value, case_insensitive=True) |
|
669 | user = User.get_by_email(value, case_insensitive=True) | |
670 | if user: |
|
670 | if user: | |
671 | msg = M(self, 'email_taken', state) |
|
671 | msg = M(self, 'email_taken', state) | |
672 | raise formencode.Invalid(msg, value, state, |
|
672 | raise formencode.Invalid(msg, value, state, | |
673 | error_dict=dict(email=msg) |
|
673 | error_dict=dict(email=msg) | |
674 | ) |
|
674 | ) | |
675 | return _validator |
|
675 | return _validator | |
676 |
|
676 | |||
677 |
|
677 | |||
678 | def ValidSystemEmail(): |
|
678 | def ValidSystemEmail(): | |
679 | class _validator(formencode.validators.FancyValidator): |
|
679 | class _validator(formencode.validators.FancyValidator): | |
680 | messages = { |
|
680 | messages = { | |
681 | 'non_existing_email': _(u'e-mail "%(email)s" does not exist.') |
|
681 | 'non_existing_email': _(u'e-mail "%(email)s" does not exist.') | |
682 | } |
|
682 | } | |
683 |
|
683 | |||
684 | def _to_python(self, value, state): |
|
684 | def _to_python(self, value, state): | |
685 | return value.lower() |
|
685 | return value.lower() | |
686 |
|
686 | |||
687 | def validate_python(self, value, state): |
|
687 | def validate_python(self, value, state): | |
688 | user = User.get_by_email(value, case_insensitive=True) |
|
688 | user = User.get_by_email(value, case_insensitive=True) | |
689 | if user is None: |
|
689 | if user is None: | |
690 | msg = M(self, 'non_existing_email', state, email=value) |
|
690 | msg = M(self, 'non_existing_email', state, email=value) | |
691 | raise formencode.Invalid(msg, value, state, |
|
691 | raise formencode.Invalid(msg, value, state, | |
692 | error_dict=dict(email=msg) |
|
692 | error_dict=dict(email=msg) | |
693 | ) |
|
693 | ) | |
694 |
|
694 | |||
695 | return _validator |
|
695 | return _validator | |
696 |
|
696 | |||
697 |
|
697 | |||
698 | def LdapLibValidator(): |
|
698 | def LdapLibValidator(): | |
699 | class _validator(formencode.validators.FancyValidator): |
|
699 | class _validator(formencode.validators.FancyValidator): | |
700 | messages = { |
|
700 | messages = { | |
701 |
|
701 | |||
702 | } |
|
702 | } | |
703 |
|
703 | |||
704 | def validate_python(self, value, state): |
|
704 | def validate_python(self, value, state): | |
705 | try: |
|
705 | try: | |
706 | import ldap |
|
706 | import ldap | |
707 | ldap # pyflakes silence ! |
|
707 | ldap # pyflakes silence ! | |
708 | except ImportError: |
|
708 | except ImportError: | |
709 | raise LdapImportError() |
|
709 | raise LdapImportError() | |
710 |
|
710 | |||
711 | return _validator |
|
711 | return _validator | |
712 |
|
712 | |||
713 |
|
713 | |||
714 | def AttrLoginValidator(): |
|
714 | def AttrLoginValidator(): | |
715 | class _validator(formencode.validators.FancyValidator): |
|
715 | class _validator(formencode.validators.FancyValidator): | |
716 | messages = { |
|
716 | messages = { | |
717 | 'invalid_cn': |
|
717 | 'invalid_cn': | |
718 | _(u'The LDAP Login attribute of the CN must be specified - ' |
|
718 | _(u'The LDAP Login attribute of the CN must be specified - ' | |
719 | 'this is the name of the attribute that is equivalent ' |
|
719 | 'this is the name of the attribute that is equivalent ' | |
720 | 'to "username"') |
|
720 | 'to "username"') | |
721 | } |
|
721 | } | |
722 |
|
722 | |||
723 | def validate_python(self, value, state): |
|
723 | def validate_python(self, value, state): | |
724 | if not value or not isinstance(value, (str, unicode)): |
|
724 | if not value or not isinstance(value, (str, unicode)): | |
725 | msg = M(self, 'invalid_cn', state) |
|
725 | msg = M(self, 'invalid_cn', state) | |
726 | raise formencode.Invalid(msg, value, state, |
|
726 | raise formencode.Invalid(msg, value, state, | |
727 | error_dict=dict(ldap_attr_login=msg) |
|
727 | error_dict=dict(ldap_attr_login=msg) | |
728 | ) |
|
728 | ) | |
729 |
|
729 | |||
730 | return _validator |
|
730 | return _validator | |
731 |
|
731 | |||
732 |
|
732 | |||
733 | def NotReviewedRevisions(repo_id): |
|
733 | def NotReviewedRevisions(repo_id): | |
734 | class _validator(formencode.validators.FancyValidator): |
|
734 | class _validator(formencode.validators.FancyValidator): | |
735 | messages = { |
|
735 | messages = { | |
736 | 'rev_already_reviewed': |
|
736 | 'rev_already_reviewed': | |
737 | _(u'Revisions %(revs)s are already part of pull request ' |
|
737 | _(u'Revisions %(revs)s are already part of pull request ' | |
738 | 'or have set status') |
|
738 | 'or have set status') | |
739 | } |
|
739 | } | |
740 |
|
740 | |||
741 | def validate_python(self, value, state): |
|
741 | def validate_python(self, value, state): | |
742 | # check revisions if they are not reviewed, or a part of another |
|
742 | # check revisions if they are not reviewed, or a part of another | |
743 | # pull request |
|
743 | # pull request | |
744 | statuses = ChangesetStatus.query()\ |
|
744 | statuses = ChangesetStatus.query()\ | |
745 | .filter(ChangesetStatus.revision.in_(value))\ |
|
745 | .filter(ChangesetStatus.revision.in_(value))\ | |
746 | .filter(ChangesetStatus.repo_id == repo_id)\ |
|
746 | .filter(ChangesetStatus.repo_id == repo_id)\ | |
747 | .all() |
|
747 | .all() | |
748 |
|
748 | |||
749 | errors = [] |
|
749 | errors = [] | |
750 | for cs in statuses: |
|
750 | for cs in statuses: | |
751 | if cs.pull_request_id: |
|
751 | if cs.pull_request_id: | |
752 | errors.append(['pull_req', cs.revision[:12]]) |
|
752 | errors.append(['pull_req', cs.revision[:12]]) | |
753 | elif cs.status: |
|
753 | elif cs.status: | |
754 | errors.append(['status', cs.revision[:12]]) |
|
754 | errors.append(['status', cs.revision[:12]]) | |
755 |
|
755 | |||
756 | if errors: |
|
756 | if errors: | |
757 | revs = ','.join([x[1] for x in errors]) |
|
757 | revs = ','.join([x[1] for x in errors]) | |
758 | msg = M(self, 'rev_already_reviewed', state, revs=revs) |
|
758 | msg = M(self, 'rev_already_reviewed', state, revs=revs) | |
759 | raise formencode.Invalid(msg, value, state, |
|
759 | raise formencode.Invalid(msg, value, state, | |
760 | error_dict=dict(revisions=revs) |
|
760 | error_dict=dict(revisions=revs) | |
761 | ) |
|
761 | ) | |
762 |
|
762 | |||
763 | return _validator |
|
763 | return _validator | |
764 |
|
764 | |||
765 |
|
765 | |||
766 | def ValidIp(): |
|
766 | def ValidIp(): | |
767 | class _validator(CIDR): |
|
767 | class _validator(CIDR): | |
768 | messages = dict( |
|
768 | messages = dict( | |
769 | badFormat=_('Please enter a valid IPv4 or IpV6 address'), |
|
769 | badFormat=_('Please enter a valid IPv4 or IpV6 address'), | |
770 | illegalBits=_('The network size (bits) must be within the range' |
|
770 | illegalBits=_('The network size (bits) must be within the range' | |
771 | ' of 0-32 (not %(bits)r)')) |
|
771 | ' of 0-32 (not %(bits)r)')) | |
772 |
|
772 | |||
773 | def to_python(self, value, state): |
|
773 | def to_python(self, value, state): | |
774 | v = super(_validator, self).to_python(value, state) |
|
774 | v = super(_validator, self).to_python(value, state) | |
775 | v = v.strip() |
|
775 | v = v.strip() | |
776 | net = ipaddr.IPNetwork(address=v) |
|
776 | net = ipaddr.IPNetwork(address=v) | |
777 | if isinstance(net, ipaddr.IPv4Network): |
|
777 | if isinstance(net, ipaddr.IPv4Network): | |
778 | #if IPv4 doesn't end with a mask, add /32 |
|
778 | #if IPv4 doesn't end with a mask, add /32 | |
779 | if '/' not in value: |
|
779 | if '/' not in value: | |
780 | v += '/32' |
|
780 | v += '/32' | |
781 | if isinstance(net, ipaddr.IPv6Network): |
|
781 | if isinstance(net, ipaddr.IPv6Network): | |
782 | #if IPv6 doesn't end with a mask, add /128 |
|
782 | #if IPv6 doesn't end with a mask, add /128 | |
783 | if '/' not in value: |
|
783 | if '/' not in value: | |
784 | v += '/128' |
|
784 | v += '/128' | |
785 | return v |
|
785 | return v | |
786 |
|
786 | |||
787 | def validate_python(self, value, state): |
|
787 | def validate_python(self, value, state): | |
788 | try: |
|
788 | try: | |
789 | addr = value.strip() |
|
789 | addr = value.strip() | |
790 | #this raises an ValueError if address is not IpV4 or IpV6 |
|
790 | #this raises an ValueError if address is not IpV4 or IpV6 | |
791 | ipaddr.IPNetwork(address=addr) |
|
791 | ipaddr.IPNetwork(address=addr) | |
792 | except ValueError: |
|
792 | except ValueError: | |
793 | raise formencode.Invalid(self.message('badFormat', state), |
|
793 | raise formencode.Invalid(self.message('badFormat', state), | |
794 | value, state) |
|
794 | value, state) | |
795 |
|
795 | |||
796 | return _validator |
|
796 | return _validator | |
797 |
|
797 | |||
798 |
|
798 | |||
799 | def FieldKey(): |
|
799 | def FieldKey(): | |
800 | class _validator(formencode.validators.FancyValidator): |
|
800 | class _validator(formencode.validators.FancyValidator): | |
801 | messages = dict( |
|
801 | messages = dict( | |
802 | badFormat=_('Key name can only consist of letters, ' |
|
802 | badFormat=_('Key name can only consist of letters, ' | |
803 | 'underscore, dash or numbers'),) |
|
803 | 'underscore, dash or numbers'),) | |
804 |
|
804 | |||
805 | def validate_python(self, value, state): |
|
805 | def validate_python(self, value, state): | |
806 | if not re.match('[a-zA-Z0-9_-]+$', value): |
|
806 | if not re.match('[a-zA-Z0-9_-]+$', value): | |
807 | raise formencode.Invalid(self.message('badFormat', state), |
|
807 | raise formencode.Invalid(self.message('badFormat', state), | |
808 | value, state) |
|
808 | value, state) | |
809 | return _validator |
|
809 | return _validator |
@@ -1,78 +1,78 b'' | |||||
1 | ## -*- coding: utf-8 -*- |
|
1 | ## -*- coding: utf-8 -*- | |
2 | <%inherit file="/base/base.html"/> |
|
2 | <%inherit file="/base/base.html"/> | |
3 |
|
3 | |||
4 | <%def name="title()"> |
|
4 | <%def name="title()"> | |
5 | ${_('Repository groups administration')} - ${c.rhodecode_name} |
|
5 | ${_('Repository groups administration')} - ${c.rhodecode_name} | |
6 | </%def> |
|
6 | </%def> | |
7 |
|
7 | |||
8 |
|
8 | |||
9 | <%def name="breadcrumbs_links()"> |
|
9 | <%def name="breadcrumbs_links()"> | |
10 | ${h.link_to(_('Admin'),h.url('admin_home'))} |
|
10 | ${h.link_to(_('Admin'),h.url('admin_home'))} | |
11 | » |
|
11 | » | |
12 |
${_('repositor |
|
12 | ${_('repository groups')} | |
13 | </%def> |
|
13 | </%def> | |
14 | <%def name="page_nav()"> |
|
14 | <%def name="page_nav()"> | |
15 | ${self.menu('admin')} |
|
15 | ${self.menu('admin')} | |
16 | </%def> |
|
16 | </%def> | |
17 | <%def name="main()"> |
|
17 | <%def name="main()"> | |
18 | <div class="box"> |
|
18 | <div class="box"> | |
19 | <!-- box / title --> |
|
19 | <!-- box / title --> | |
20 | <div class="title"> |
|
20 | <div class="title"> | |
21 | ${self.breadcrumbs()} |
|
21 | ${self.breadcrumbs()} | |
22 | <ul class="links"> |
|
22 | <ul class="links"> | |
23 | <li> |
|
23 | <li> | |
24 | %if h.HasPermissionAny('hg.admin')(): |
|
24 | %if h.HasPermissionAny('hg.admin')(): | |
25 | <span>${h.link_to(_(u'Add group'),h.url('new_repos_group'))}</span> |
|
25 | <span>${h.link_to(_(u'Add group'),h.url('new_repos_group'))}</span> | |
26 | %endif |
|
26 | %endif | |
27 | </li> |
|
27 | </li> | |
28 | </ul> |
|
28 | </ul> | |
29 | </div> |
|
29 | </div> | |
30 | <!-- end box / title --> |
|
30 | <!-- end box / title --> | |
31 | <div class="table"> |
|
31 | <div class="table"> | |
32 | % if c.groups: |
|
32 | % if c.groups: | |
33 | <table class="table_disp"> |
|
33 | <table class="table_disp"> | |
34 |
|
34 | |||
35 | <thead> |
|
35 | <thead> | |
36 | <tr> |
|
36 | <tr> | |
37 | <th class="left"><a href="#">${_('Group name')}</a></th> |
|
37 | <th class="left"><a href="#">${_('Group name')}</a></th> | |
38 | <th class="left"><a href="#">${_('Description')}</a></th> |
|
38 | <th class="left"><a href="#">${_('Description')}</a></th> | |
39 | <th class="left"><a href="#">${_('Number of toplevel repositories')}</a></th> |
|
39 | <th class="left"><a href="#">${_('Number of toplevel repositories')}</a></th> | |
40 | <th class="left" colspan="2">${_('action')}</th> |
|
40 | <th class="left" colspan="2">${_('action')}</th> | |
41 | </tr> |
|
41 | </tr> | |
42 | </thead> |
|
42 | </thead> | |
43 |
|
43 | |||
44 | ## REPO GROUPS |
|
44 | ## REPO GROUPS | |
45 |
|
45 | |||
46 | % for gr in c.groups: |
|
46 | % for gr in c.groups: | |
47 | <% gr_cn = gr.repositories.count() %> |
|
47 | <% gr_cn = gr.repositories.count() %> | |
48 | <tr> |
|
48 | <tr> | |
49 | <td> |
|
49 | <td> | |
50 | <div style="white-space: nowrap"> |
|
50 | <div style="white-space: nowrap"> | |
51 | <img class="icon" alt="${_('Repository group')}" src="${h.url('/images/icons/database_link.png')}"/> |
|
51 | <img class="icon" alt="${_('Repository group')}" src="${h.url('/images/icons/database_link.png')}"/> | |
52 | ${h.link_to(h.literal(' » '.join(map(h.safe_unicode,[g.name for g in gr.parents+[gr]]))), url('repos_group_home',group_name=gr.group_name))} |
|
52 | ${h.link_to(h.literal(' » '.join(map(h.safe_unicode,[g.name for g in gr.parents+[gr]]))), url('repos_group_home',group_name=gr.group_name))} | |
53 | </div> |
|
53 | </div> | |
54 | </td> |
|
54 | </td> | |
55 | <td>${gr.group_description}</td> |
|
55 | <td>${gr.group_description}</td> | |
56 | <td><b>${gr_cn}</b></td> |
|
56 | <td><b>${gr_cn}</b></td> | |
57 | <td> |
|
57 | <td> | |
58 | <a href="${h.url('edit_repos_group',group_name=gr.group_name)}" title="${_('edit')}"> |
|
58 | <a href="${h.url('edit_repos_group',group_name=gr.group_name)}" title="${_('edit')}"> | |
59 | ${h.submit('edit_%s' % gr.group_name,_('edit'),class_="edit_icon action_button")} |
|
59 | ${h.submit('edit_%s' % gr.group_name,_('edit'),class_="edit_icon action_button")} | |
60 | </a> |
|
60 | </a> | |
61 | </td> |
|
61 | </td> | |
62 | <td> |
|
62 | <td> | |
63 | ${h.form(url('repos_group', group_name=gr.group_name),method='delete')} |
|
63 | ${h.form(url('repos_group', group_name=gr.group_name),method='delete')} | |
64 | ${h.submit('remove_%s' % gr.name,_('delete'),class_="delete_icon action_button",onclick="return confirm('"+ungettext('Confirm to delete this group: %s with %s repository','Confirm to delete this group: %s with %s repositories',gr_cn) % (gr.name,gr_cn)+"');")} |
|
64 | ${h.submit('remove_%s' % gr.name,_('delete'),class_="delete_icon action_button",onclick="return confirm('"+ungettext('Confirm to delete this group: %s with %s repository','Confirm to delete this group: %s with %s repositories',gr_cn) % (gr.name,gr_cn)+"');")} | |
65 | ${h.end_form()} |
|
65 | ${h.end_form()} | |
66 | </td> |
|
66 | </td> | |
67 | </tr> |
|
67 | </tr> | |
68 | % endfor |
|
68 | % endfor | |
69 |
|
69 | |||
70 | </table> |
|
70 | </table> | |
71 | % else: |
|
71 | % else: | |
72 | ${_('There are no repository groups yet')} |
|
72 | ${_('There are no repository groups yet')} | |
73 | % endif |
|
73 | % endif | |
74 |
|
74 | |||
75 | </div> |
|
75 | </div> | |
76 | </div> |
|
76 | </div> | |
77 |
|
77 | |||
78 | </%def> |
|
78 | </%def> |
@@ -1,228 +1,228 b'' | |||||
1 | ## -*- coding: utf-8 -*- |
|
1 | ## -*- coding: utf-8 -*- | |
2 | <%inherit file="/base/base.html"/> |
|
2 | <%inherit file="/base/base.html"/> | |
3 |
|
3 | |||
4 | <%def name="title()"> |
|
4 | <%def name="title()"> | |
5 |
${_('Edit user |
|
5 | ${_('Edit user group')} ${c.users_group.users_group_name} - ${c.rhodecode_name} | |
6 | </%def> |
|
6 | </%def> | |
7 |
|
7 | |||
8 | <%def name="breadcrumbs_links()"> |
|
8 | <%def name="breadcrumbs_links()"> | |
9 | ${h.link_to(_('Admin'),h.url('admin_home'))} |
|
9 | ${h.link_to(_('Admin'),h.url('admin_home'))} | |
10 | » |
|
10 | » | |
11 | ${h.link_to(_('UsersGroups'),h.url('users_groups'))} |
|
11 | ${h.link_to(_('UsersGroups'),h.url('users_groups'))} | |
12 | » |
|
12 | » | |
13 | ${_('edit')} "${c.users_group.users_group_name}" |
|
13 | ${_('edit')} "${c.users_group.users_group_name}" | |
14 | </%def> |
|
14 | </%def> | |
15 |
|
15 | |||
16 | <%def name="page_nav()"> |
|
16 | <%def name="page_nav()"> | |
17 | ${self.menu('admin')} |
|
17 | ${self.menu('admin')} | |
18 | </%def> |
|
18 | </%def> | |
19 |
|
19 | |||
20 | <%def name="main()"> |
|
20 | <%def name="main()"> | |
21 | <div class="box box-left"> |
|
21 | <div class="box box-left"> | |
22 | <!-- box / title --> |
|
22 | <!-- box / title --> | |
23 | <div class="title"> |
|
23 | <div class="title"> | |
24 | ${self.breadcrumbs()} |
|
24 | ${self.breadcrumbs()} | |
25 | </div> |
|
25 | </div> | |
26 | <!-- end box / title --> |
|
26 | <!-- end box / title --> | |
27 | ${h.form(url('users_group', id=c.users_group.users_group_id),method='put', id='edit_users_group')} |
|
27 | ${h.form(url('users_group', id=c.users_group.users_group_id),method='put', id='edit_users_group')} | |
28 | <div class="form"> |
|
28 | <div class="form"> | |
29 | <!-- fields --> |
|
29 | <!-- fields --> | |
30 | <div class="fields"> |
|
30 | <div class="fields"> | |
31 | <div class="field"> |
|
31 | <div class="field"> | |
32 | <div class="label"> |
|
32 | <div class="label"> | |
33 | <label for="users_group_name">${_('Group name')}:</label> |
|
33 | <label for="users_group_name">${_('Group name')}:</label> | |
34 | </div> |
|
34 | </div> | |
35 | <div class="input"> |
|
35 | <div class="input"> | |
36 | ${h.text('users_group_name',class_='small')} |
|
36 | ${h.text('users_group_name',class_='small')} | |
37 | </div> |
|
37 | </div> | |
38 | </div> |
|
38 | </div> | |
39 |
|
39 | |||
40 | <div class="field"> |
|
40 | <div class="field"> | |
41 | <div class="label label-checkbox"> |
|
41 | <div class="label label-checkbox"> | |
42 | <label for="users_group_active">${_('Active')}:</label> |
|
42 | <label for="users_group_active">${_('Active')}:</label> | |
43 | </div> |
|
43 | </div> | |
44 | <div class="checkboxes"> |
|
44 | <div class="checkboxes"> | |
45 | ${h.checkbox('users_group_active',value=True)} |
|
45 | ${h.checkbox('users_group_active',value=True)} | |
46 | </div> |
|
46 | </div> | |
47 | </div> |
|
47 | </div> | |
48 | <div class="field"> |
|
48 | <div class="field"> | |
49 | <div class="label"> |
|
49 | <div class="label"> | |
50 | <label for="users_group_active">${_('Members')}:</label> |
|
50 | <label for="users_group_active">${_('Members')}:</label> | |
51 | </div> |
|
51 | </div> | |
52 | <div class="select"> |
|
52 | <div class="select"> | |
53 | <table> |
|
53 | <table> | |
54 | <tr> |
|
54 | <tr> | |
55 | <td> |
|
55 | <td> | |
56 | <div> |
|
56 | <div> | |
57 | <div style="float:left"> |
|
57 | <div style="float:left"> | |
58 | <div class="text" style="padding: 0px 0px 6px;">${_('Choosen group members')}</div> |
|
58 | <div class="text" style="padding: 0px 0px 6px;">${_('Choosen group members')}</div> | |
59 | ${h.select('users_group_members',[x[0] for x in c.group_members],c.group_members,multiple=True,size=8,style="min-width:210px")} |
|
59 | ${h.select('users_group_members',[x[0] for x in c.group_members],c.group_members,multiple=True,size=8,style="min-width:210px")} | |
60 | <div id="remove_all_elements" style="cursor:pointer;text-align:center"> |
|
60 | <div id="remove_all_elements" style="cursor:pointer;text-align:center"> | |
61 | ${_('Remove all elements')} |
|
61 | ${_('Remove all elements')} | |
62 | <img alt="remove" style="vertical-align:text-bottom" src="${h.url('/images/icons/arrow_right.png')}"/> |
|
62 | <img alt="remove" style="vertical-align:text-bottom" src="${h.url('/images/icons/arrow_right.png')}"/> | |
63 | </div> |
|
63 | </div> | |
64 | </div> |
|
64 | </div> | |
65 | <div style="float:left;width:20px;padding-top:50px"> |
|
65 | <div style="float:left;width:20px;padding-top:50px"> | |
66 | <img alt="add" id="add_element" |
|
66 | <img alt="add" id="add_element" | |
67 | style="padding:2px;cursor:pointer" |
|
67 | style="padding:2px;cursor:pointer" | |
68 | src="${h.url('/images/icons/arrow_left.png')}"/> |
|
68 | src="${h.url('/images/icons/arrow_left.png')}"/> | |
69 | <br /> |
|
69 | <br /> | |
70 | <img alt="remove" id="remove_element" |
|
70 | <img alt="remove" id="remove_element" | |
71 | style="padding:2px;cursor:pointer" |
|
71 | style="padding:2px;cursor:pointer" | |
72 | src="${h.url('/images/icons/arrow_right.png')}"/> |
|
72 | src="${h.url('/images/icons/arrow_right.png')}"/> | |
73 | </div> |
|
73 | </div> | |
74 | <div style="float:left"> |
|
74 | <div style="float:left"> | |
75 | <div class="text" style="padding: 0px 0px 6px;">${_('Available members')}</div> |
|
75 | <div class="text" style="padding: 0px 0px 6px;">${_('Available members')}</div> | |
76 | ${h.select('available_members',[],c.available_members,multiple=True,size=8,style="min-width:210px")} |
|
76 | ${h.select('available_members',[],c.available_members,multiple=True,size=8,style="min-width:210px")} | |
77 | <div id="add_all_elements" style="cursor:pointer;text-align:center"> |
|
77 | <div id="add_all_elements" style="cursor:pointer;text-align:center"> | |
78 | <img alt="add" style="vertical-align:text-bottom" src="${h.url('/images/icons/arrow_left.png')}"/> |
|
78 | <img alt="add" style="vertical-align:text-bottom" src="${h.url('/images/icons/arrow_left.png')}"/> | |
79 | ${_('Add all elements')} |
|
79 | ${_('Add all elements')} | |
80 | </div> |
|
80 | </div> | |
81 | </div> |
|
81 | </div> | |
82 | </div> |
|
82 | </div> | |
83 | </td> |
|
83 | </td> | |
84 | </tr> |
|
84 | </tr> | |
85 | </table> |
|
85 | </table> | |
86 | </div> |
|
86 | </div> | |
87 |
|
87 | |||
88 | </div> |
|
88 | </div> | |
89 | <div class="buttons"> |
|
89 | <div class="buttons"> | |
90 | ${h.submit('save',_('save'),class_="ui-btn large")} |
|
90 | ${h.submit('save',_('save'),class_="ui-btn large")} | |
91 | </div> |
|
91 | </div> | |
92 | </div> |
|
92 | </div> | |
93 | </div> |
|
93 | </div> | |
94 | ${h.end_form()} |
|
94 | ${h.end_form()} | |
95 | </div> |
|
95 | </div> | |
96 |
|
96 | |||
97 | <div class="box box-right"> |
|
97 | <div class="box box-right"> | |
98 | <!-- box / title --> |
|
98 | <!-- box / title --> | |
99 | <div class="title"> |
|
99 | <div class="title"> | |
100 | <h5>${_('Permissions')}</h5> |
|
100 | <h5>${_('Permissions')}</h5> | |
101 | </div> |
|
101 | </div> | |
102 | ${h.form(url('users_group_perm', id=c.users_group.users_group_id), method='put')} |
|
102 | ${h.form(url('users_group_perm', id=c.users_group.users_group_id), method='put')} | |
103 | <div class="form"> |
|
103 | <div class="form"> | |
104 | <!-- fields --> |
|
104 | <!-- fields --> | |
105 | <div class="fields"> |
|
105 | <div class="fields"> | |
106 | <div class="field"> |
|
106 | <div class="field"> | |
107 | <div class="label label-checkbox"> |
|
107 | <div class="label label-checkbox"> | |
108 | <label for="inherit_permissions">${_('Inherit default permissions')}:</label> |
|
108 | <label for="inherit_permissions">${_('Inherit default permissions')}:</label> | |
109 | </div> |
|
109 | </div> | |
110 | <div class="checkboxes"> |
|
110 | <div class="checkboxes"> | |
111 | ${h.checkbox('inherit_default_permissions',value=True)} |
|
111 | ${h.checkbox('inherit_default_permissions',value=True)} | |
112 | </div> |
|
112 | </div> | |
113 | <span class="help-block">${h.literal(_('Select to inherit permissions from %s settings. ' |
|
113 | <span class="help-block">${h.literal(_('Select to inherit permissions from %s settings. ' | |
114 | 'With this selected below options does not have any action') % h.link_to('default', url('edit_permission', id='default')))}</span> |
|
114 | 'With this selected below options does not have any action') % h.link_to('default', url('edit_permission', id='default')))}</span> | |
115 | </div> |
|
115 | </div> | |
116 | <div id="inherit_overlay" style="${'opacity:0.3' if c.users_group.inherit_default_permissions else ''}" > |
|
116 | <div id="inherit_overlay" style="${'opacity:0.3' if c.users_group.inherit_default_permissions else ''}" > | |
117 | <div class="field"> |
|
117 | <div class="field"> | |
118 | <div class="label label-checkbox"> |
|
118 | <div class="label label-checkbox"> | |
119 | <label for="create_repo_perm">${_('Create repositories')}:</label> |
|
119 | <label for="create_repo_perm">${_('Create repositories')}:</label> | |
120 | </div> |
|
120 | </div> | |
121 | <div class="checkboxes"> |
|
121 | <div class="checkboxes"> | |
122 | ${h.checkbox('create_repo_perm',value=True)} |
|
122 | ${h.checkbox('create_repo_perm',value=True)} | |
123 | </div> |
|
123 | </div> | |
124 | </div> |
|
124 | </div> | |
125 | <div class="field"> |
|
125 | <div class="field"> | |
126 | <div class="label label-checkbox"> |
|
126 | <div class="label label-checkbox"> | |
127 | <label for="fork_repo_perm">${_('Fork repositories')}:</label> |
|
127 | <label for="fork_repo_perm">${_('Fork repositories')}:</label> | |
128 | </div> |
|
128 | </div> | |
129 | <div class="checkboxes"> |
|
129 | <div class="checkboxes"> | |
130 | ${h.checkbox('fork_repo_perm',value=True)} |
|
130 | ${h.checkbox('fork_repo_perm',value=True)} | |
131 | </div> |
|
131 | </div> | |
132 | </div> |
|
132 | </div> | |
133 | </div> |
|
133 | </div> | |
134 | <div class="buttons"> |
|
134 | <div class="buttons"> | |
135 | ${h.submit('save',_('Save'),class_="ui-btn large")} |
|
135 | ${h.submit('save',_('Save'),class_="ui-btn large")} | |
136 | ${h.reset('reset',_('Reset'),class_="ui-btn large")} |
|
136 | ${h.reset('reset',_('Reset'),class_="ui-btn large")} | |
137 | </div> |
|
137 | </div> | |
138 | </div> |
|
138 | </div> | |
139 | </div> |
|
139 | </div> | |
140 | ${h.end_form()} |
|
140 | ${h.end_form()} | |
141 | </div> |
|
141 | </div> | |
142 |
|
142 | |||
143 | <div class="box box-right"> |
|
143 | <div class="box box-right"> | |
144 | <!-- box / title --> |
|
144 | <!-- box / title --> | |
145 | <div class="title"> |
|
145 | <div class="title"> | |
146 | <h5>${_('Group members')}</h5> |
|
146 | <h5>${_('Group members')}</h5> | |
147 | </div> |
|
147 | </div> | |
148 |
|
148 | |||
149 | <div class="group_members_wrap"> |
|
149 | <div class="group_members_wrap"> | |
150 | % if c.group_members_obj: |
|
150 | % if c.group_members_obj: | |
151 | <ul class="group_members"> |
|
151 | <ul class="group_members"> | |
152 | %for user in c.group_members_obj: |
|
152 | %for user in c.group_members_obj: | |
153 | <li> |
|
153 | <li> | |
154 | <div class="group_member"> |
|
154 | <div class="group_member"> | |
155 | <div class="gravatar"><img alt="gravatar" src="${h.gravatar_url(user.email,24)}"/> </div> |
|
155 | <div class="gravatar"><img alt="gravatar" src="${h.gravatar_url(user.email,24)}"/> </div> | |
156 | <div>${h.link_to(user.username, h.url('edit_user',id=user.user_id))}</div> |
|
156 | <div>${h.link_to(user.username, h.url('edit_user',id=user.user_id))}</div> | |
157 | <div>${user.full_name}</div> |
|
157 | <div>${user.full_name}</div> | |
158 | </div> |
|
158 | </div> | |
159 | </li> |
|
159 | </li> | |
160 | %endfor |
|
160 | %endfor | |
161 | </ul> |
|
161 | </ul> | |
162 | %else: |
|
162 | %else: | |
163 | <span class="empty_data">${_('No members yet')}</span> |
|
163 | <span class="empty_data">${_('No members yet')}</span> | |
164 | %endif |
|
164 | %endif | |
165 | </div> |
|
165 | </div> | |
166 | </div> |
|
166 | </div> | |
167 |
|
167 | |||
168 | <div class="box box-left"> |
|
168 | <div class="box box-left"> | |
169 | <!-- box / title --> |
|
169 | <!-- box / title --> | |
170 | <div class="title"> |
|
170 | <div class="title"> | |
171 | <h5>${_('Permissions defined for this group')}</h5> |
|
171 | <h5>${_('Permissions defined for this group')}</h5> | |
172 | </div> |
|
172 | </div> | |
173 | ## permissions overview |
|
173 | ## permissions overview | |
174 | <div id="perms" class="table"> |
|
174 | <div id="perms" class="table"> | |
175 | %for section in sorted(c.users_group.permissions.keys()): |
|
175 | %for section in sorted(c.users_group.permissions.keys()): | |
176 | <div class="perms_section_head">${section.replace("_"," ").capitalize()}</div> |
|
176 | <div class="perms_section_head">${section.replace("_"," ").capitalize()}</div> | |
177 | %if not c.users_group.permissions: |
|
177 | %if not c.users_group.permissions: | |
178 | <span class="empty_data">${_('No permissions set yet')}</span> |
|
178 | <span class="empty_data">${_('No permissions set yet')}</span> | |
179 | %else: |
|
179 | %else: | |
180 | <div id='tbl_list_wrap_${section}' class="yui-skin-sam"> |
|
180 | <div id='tbl_list_wrap_${section}' class="yui-skin-sam"> | |
181 | <table id="tbl_list_repository"> |
|
181 | <table id="tbl_list_repository"> | |
182 | <thead> |
|
182 | <thead> | |
183 | <tr> |
|
183 | <tr> | |
184 | <th class="left">${_('Name')}</th> |
|
184 | <th class="left">${_('Name')}</th> | |
185 | <th class="left">${_('Permission')}</th> |
|
185 | <th class="left">${_('Permission')}</th> | |
186 | <th class="left">${_('Edit Permission')}</th> |
|
186 | <th class="left">${_('Edit Permission')}</th> | |
187 | </thead> |
|
187 | </thead> | |
188 | <tbody> |
|
188 | <tbody> | |
189 | %for k in c.users_group.permissions[section]: |
|
189 | %for k in c.users_group.permissions[section]: | |
190 | <% |
|
190 | <% | |
191 | section_perm = c.users_group.permissions[section].get(k) |
|
191 | section_perm = c.users_group.permissions[section].get(k) | |
192 | _perm = section_perm.split('.')[-1] |
|
192 | _perm = section_perm.split('.')[-1] | |
193 | %> |
|
193 | %> | |
194 | <tr> |
|
194 | <tr> | |
195 | <td> |
|
195 | <td> | |
196 | %if section == 'repositories': |
|
196 | %if section == 'repositories': | |
197 | <a href="${h.url('summary_home',repo_name=k)}">${k}</a> |
|
197 | <a href="${h.url('summary_home',repo_name=k)}">${k}</a> | |
198 | %elif section == 'repositories_groups': |
|
198 | %elif section == 'repositories_groups': | |
199 | <a href="${h.url('repos_group_home',group_name=k)}">${k}</a> |
|
199 | <a href="${h.url('repos_group_home',group_name=k)}">${k}</a> | |
200 | %endif |
|
200 | %endif | |
201 | </td> |
|
201 | </td> | |
202 | <td> |
|
202 | <td> | |
203 | <span class="perm_tag ${_perm}">${section_perm}</span> |
|
203 | <span class="perm_tag ${_perm}">${section_perm}</span> | |
204 | </td> |
|
204 | </td> | |
205 | <td> |
|
205 | <td> | |
206 | %if section == 'repositories': |
|
206 | %if section == 'repositories': | |
207 | <a href="${h.url('edit_repo',repo_name=k,anchor='permissions_manage')}">${_('edit')}</a> |
|
207 | <a href="${h.url('edit_repo',repo_name=k,anchor='permissions_manage')}">${_('edit')}</a> | |
208 | %elif section == 'repositories_groups': |
|
208 | %elif section == 'repositories_groups': | |
209 | <a href="${h.url('edit_repos_group',group_name=k,anchor='permissions_manage')}">${_('edit')}</a> |
|
209 | <a href="${h.url('edit_repos_group',group_name=k,anchor='permissions_manage')}">${_('edit')}</a> | |
210 | %else: |
|
210 | %else: | |
211 | -- |
|
211 | -- | |
212 | %endif |
|
212 | %endif | |
213 | </td> |
|
213 | </td> | |
214 | </tr> |
|
214 | </tr> | |
215 | %endfor |
|
215 | %endfor | |
216 | </tbody> |
|
216 | </tbody> | |
217 | </table> |
|
217 | </table> | |
218 | </div> |
|
218 | </div> | |
219 | %endif |
|
219 | %endif | |
220 | %endfor |
|
220 | %endfor | |
221 | </div> |
|
221 | </div> | |
222 | </div> |
|
222 | </div> | |
223 |
|
223 | |||
224 |
|
224 | |||
225 | <script type="text/javascript"> |
|
225 | <script type="text/javascript"> | |
226 | MultiSelectWidget('users_group_members','available_members','edit_users_group'); |
|
226 | MultiSelectWidget('users_group_members','available_members','edit_users_group'); | |
227 | </script> |
|
227 | </script> | |
228 | </%def> |
|
228 | </%def> |
@@ -1,1294 +1,1294 b'' | |||||
1 | from __future__ import with_statement |
|
1 | from __future__ import with_statement | |
2 | import random |
|
2 | import random | |
3 | import mock |
|
3 | import mock | |
4 |
|
4 | |||
5 | from rhodecode.tests import * |
|
5 | from rhodecode.tests import * | |
6 | from rhodecode.lib.compat import json |
|
6 | from rhodecode.lib.compat import json | |
7 | from rhodecode.lib.auth import AuthUser |
|
7 | from rhodecode.lib.auth import AuthUser | |
8 | from rhodecode.model.user import UserModel |
|
8 | from rhodecode.model.user import UserModel | |
9 | from rhodecode.model.users_group import UsersGroupModel |
|
9 | from rhodecode.model.users_group import UsersGroupModel | |
10 | from rhodecode.model.repo import RepoModel |
|
10 | from rhodecode.model.repo import RepoModel | |
11 | from rhodecode.model.meta import Session |
|
11 | from rhodecode.model.meta import Session | |
12 | from rhodecode.model.scm import ScmModel |
|
12 | from rhodecode.model.scm import ScmModel | |
13 | from rhodecode.model.db import Repository |
|
13 | from rhodecode.model.db import Repository | |
14 |
|
14 | |||
15 | API_URL = '/_admin/api' |
|
15 | API_URL = '/_admin/api' | |
16 |
|
16 | |||
17 |
|
17 | |||
18 | def _build_data(apikey, method, **kw): |
|
18 | def _build_data(apikey, method, **kw): | |
19 | """ |
|
19 | """ | |
20 | Builds API data with given random ID |
|
20 | Builds API data with given random ID | |
21 |
|
21 | |||
22 | :param random_id: |
|
22 | :param random_id: | |
23 | :type random_id: |
|
23 | :type random_id: | |
24 | """ |
|
24 | """ | |
25 | random_id = random.randrange(1, 9999) |
|
25 | random_id = random.randrange(1, 9999) | |
26 | return random_id, json.dumps({ |
|
26 | return random_id, json.dumps({ | |
27 | "id": random_id, |
|
27 | "id": random_id, | |
28 | "api_key": apikey, |
|
28 | "api_key": apikey, | |
29 | "method": method, |
|
29 | "method": method, | |
30 | "args": kw |
|
30 | "args": kw | |
31 | }) |
|
31 | }) | |
32 |
|
32 | |||
33 | jsonify = lambda obj: json.loads(json.dumps(obj)) |
|
33 | jsonify = lambda obj: json.loads(json.dumps(obj)) | |
34 |
|
34 | |||
35 |
|
35 | |||
36 | def crash(*args, **kwargs): |
|
36 | def crash(*args, **kwargs): | |
37 | raise Exception('Total Crash !') |
|
37 | raise Exception('Total Crash !') | |
38 |
|
38 | |||
39 |
|
39 | |||
40 | def api_call(test_obj, params): |
|
40 | def api_call(test_obj, params): | |
41 | response = test_obj.app.post(API_URL, content_type='application/json', |
|
41 | response = test_obj.app.post(API_URL, content_type='application/json', | |
42 | params=params) |
|
42 | params=params) | |
43 | return response |
|
43 | return response | |
44 |
|
44 | |||
45 |
|
45 | |||
46 | TEST_USERS_GROUP = 'test_users_group' |
|
46 | TEST_USERS_GROUP = 'test_users_group' | |
47 |
|
47 | |||
48 |
|
48 | |||
49 | def make_users_group(name=TEST_USERS_GROUP): |
|
49 | def make_users_group(name=TEST_USERS_GROUP): | |
50 | gr = UsersGroupModel().create(name=name) |
|
50 | gr = UsersGroupModel().create(name=name) | |
51 | UsersGroupModel().add_user_to_group(users_group=gr, |
|
51 | UsersGroupModel().add_user_to_group(users_group=gr, | |
52 | user=TEST_USER_ADMIN_LOGIN) |
|
52 | user=TEST_USER_ADMIN_LOGIN) | |
53 | Session().commit() |
|
53 | Session().commit() | |
54 | return gr |
|
54 | return gr | |
55 |
|
55 | |||
56 |
|
56 | |||
57 | def destroy_users_group(name=TEST_USERS_GROUP): |
|
57 | def destroy_users_group(name=TEST_USERS_GROUP): | |
58 | UsersGroupModel().delete(users_group=name, force=True) |
|
58 | UsersGroupModel().delete(users_group=name, force=True) | |
59 | Session().commit() |
|
59 | Session().commit() | |
60 |
|
60 | |||
61 |
|
61 | |||
62 | def create_repo(repo_name, repo_type, owner=None): |
|
62 | def create_repo(repo_name, repo_type, owner=None): | |
63 | # create new repo |
|
63 | # create new repo | |
64 | form_data = _get_repo_create_params( |
|
64 | form_data = _get_repo_create_params( | |
65 | repo_name_full=repo_name, |
|
65 | repo_name_full=repo_name, | |
66 | repo_description='description %s' % repo_name, |
|
66 | repo_description='description %s' % repo_name, | |
67 | ) |
|
67 | ) | |
68 | cur_user = UserModel().get_by_username(owner or TEST_USER_ADMIN_LOGIN) |
|
68 | cur_user = UserModel().get_by_username(owner or TEST_USER_ADMIN_LOGIN) | |
69 | r = RepoModel().create(form_data, cur_user) |
|
69 | r = RepoModel().create(form_data, cur_user) | |
70 | Session().commit() |
|
70 | Session().commit() | |
71 | return r |
|
71 | return r | |
72 |
|
72 | |||
73 |
|
73 | |||
74 | def create_fork(fork_name, fork_type, fork_of): |
|
74 | def create_fork(fork_name, fork_type, fork_of): | |
75 | fork = RepoModel(Session())._get_repo(fork_of) |
|
75 | fork = RepoModel(Session())._get_repo(fork_of) | |
76 | r = create_repo(fork_name, fork_type) |
|
76 | r = create_repo(fork_name, fork_type) | |
77 | r.fork = fork |
|
77 | r.fork = fork | |
78 | Session().add(r) |
|
78 | Session().add(r) | |
79 | Session().commit() |
|
79 | Session().commit() | |
80 | return r |
|
80 | return r | |
81 |
|
81 | |||
82 |
|
82 | |||
83 | def destroy_repo(repo_name): |
|
83 | def destroy_repo(repo_name): | |
84 | RepoModel().delete(repo_name) |
|
84 | RepoModel().delete(repo_name) | |
85 | Session().commit() |
|
85 | Session().commit() | |
86 |
|
86 | |||
87 |
|
87 | |||
88 | class BaseTestApi(object): |
|
88 | class BaseTestApi(object): | |
89 | REPO = None |
|
89 | REPO = None | |
90 | REPO_TYPE = None |
|
90 | REPO_TYPE = None | |
91 |
|
91 | |||
92 | @classmethod |
|
92 | @classmethod | |
93 | def setUpClass(self): |
|
93 | def setUpClass(self): | |
94 | self.usr = UserModel().get_by_username(TEST_USER_ADMIN_LOGIN) |
|
94 | self.usr = UserModel().get_by_username(TEST_USER_ADMIN_LOGIN) | |
95 | self.apikey = self.usr.api_key |
|
95 | self.apikey = self.usr.api_key | |
96 | self.test_user = UserModel().create_or_update( |
|
96 | self.test_user = UserModel().create_or_update( | |
97 | username='test-api', |
|
97 | username='test-api', | |
98 | password='test', |
|
98 | password='test', | |
99 | email='test@api.rhodecode.org', |
|
99 | email='test@api.rhodecode.org', | |
100 | firstname='first', |
|
100 | firstname='first', | |
101 | lastname='last' |
|
101 | lastname='last' | |
102 | ) |
|
102 | ) | |
103 | Session().commit() |
|
103 | Session().commit() | |
104 | self.TEST_USER_LOGIN = self.test_user.username |
|
104 | self.TEST_USER_LOGIN = self.test_user.username | |
105 | self.apikey_regular = self.test_user.api_key |
|
105 | self.apikey_regular = self.test_user.api_key | |
106 |
|
106 | |||
107 | @classmethod |
|
107 | @classmethod | |
108 | def teardownClass(self): |
|
108 | def teardownClass(self): | |
109 | pass |
|
109 | pass | |
110 |
|
110 | |||
111 | def setUp(self): |
|
111 | def setUp(self): | |
112 | self.maxDiff = None |
|
112 | self.maxDiff = None | |
113 | make_users_group() |
|
113 | make_users_group() | |
114 |
|
114 | |||
115 | def tearDown(self): |
|
115 | def tearDown(self): | |
116 | destroy_users_group() |
|
116 | destroy_users_group() | |
117 |
|
117 | |||
118 | def _compare_ok(self, id_, expected, given): |
|
118 | def _compare_ok(self, id_, expected, given): | |
119 | expected = jsonify({ |
|
119 | expected = jsonify({ | |
120 | 'id': id_, |
|
120 | 'id': id_, | |
121 | 'error': None, |
|
121 | 'error': None, | |
122 | 'result': expected |
|
122 | 'result': expected | |
123 | }) |
|
123 | }) | |
124 | given = json.loads(given) |
|
124 | given = json.loads(given) | |
125 | self.assertEqual(expected, given) |
|
125 | self.assertEqual(expected, given) | |
126 |
|
126 | |||
127 | def _compare_error(self, id_, expected, given): |
|
127 | def _compare_error(self, id_, expected, given): | |
128 | expected = jsonify({ |
|
128 | expected = jsonify({ | |
129 | 'id': id_, |
|
129 | 'id': id_, | |
130 | 'error': expected, |
|
130 | 'error': expected, | |
131 | 'result': None |
|
131 | 'result': None | |
132 | }) |
|
132 | }) | |
133 | given = json.loads(given) |
|
133 | given = json.loads(given) | |
134 | self.assertEqual(expected, given) |
|
134 | self.assertEqual(expected, given) | |
135 |
|
135 | |||
136 | # def test_Optional(self): |
|
136 | # def test_Optional(self): | |
137 | # from rhodecode.controllers.api.api import Optional |
|
137 | # from rhodecode.controllers.api.api import Optional | |
138 | # option1 = Optional(None) |
|
138 | # option1 = Optional(None) | |
139 | # self.assertEqual('<Optional:%s>' % None, repr(option1)) |
|
139 | # self.assertEqual('<Optional:%s>' % None, repr(option1)) | |
140 | # |
|
140 | # | |
141 | # self.assertEqual(1, Optional.extract(Optional(1))) |
|
141 | # self.assertEqual(1, Optional.extract(Optional(1))) | |
142 | # self.assertEqual('trololo', Optional.extract('trololo')) |
|
142 | # self.assertEqual('trololo', Optional.extract('trololo')) | |
143 |
|
143 | |||
144 | def test_api_wrong_key(self): |
|
144 | def test_api_wrong_key(self): | |
145 | id_, params = _build_data('trololo', 'get_user') |
|
145 | id_, params = _build_data('trololo', 'get_user') | |
146 | response = api_call(self, params) |
|
146 | response = api_call(self, params) | |
147 |
|
147 | |||
148 | expected = 'Invalid API KEY' |
|
148 | expected = 'Invalid API KEY' | |
149 | self._compare_error(id_, expected, given=response.body) |
|
149 | self._compare_error(id_, expected, given=response.body) | |
150 |
|
150 | |||
151 | def test_api_missing_non_optional_param(self): |
|
151 | def test_api_missing_non_optional_param(self): | |
152 | id_, params = _build_data(self.apikey, 'get_repo') |
|
152 | id_, params = _build_data(self.apikey, 'get_repo') | |
153 | response = api_call(self, params) |
|
153 | response = api_call(self, params) | |
154 |
|
154 | |||
155 | expected = 'Missing non optional `repoid` arg in JSON DATA' |
|
155 | expected = 'Missing non optional `repoid` arg in JSON DATA' | |
156 | self._compare_error(id_, expected, given=response.body) |
|
156 | self._compare_error(id_, expected, given=response.body) | |
157 |
|
157 | |||
158 | def test_api_missing_non_optional_param_args_null(self): |
|
158 | def test_api_missing_non_optional_param_args_null(self): | |
159 | id_, params = _build_data(self.apikey, 'get_repo') |
|
159 | id_, params = _build_data(self.apikey, 'get_repo') | |
160 | params = params.replace('"args": {}', '"args": null') |
|
160 | params = params.replace('"args": {}', '"args": null') | |
161 | response = api_call(self, params) |
|
161 | response = api_call(self, params) | |
162 |
|
162 | |||
163 | expected = 'Missing non optional `repoid` arg in JSON DATA' |
|
163 | expected = 'Missing non optional `repoid` arg in JSON DATA' | |
164 | self._compare_error(id_, expected, given=response.body) |
|
164 | self._compare_error(id_, expected, given=response.body) | |
165 |
|
165 | |||
166 | def test_api_missing_non_optional_param_args_bad(self): |
|
166 | def test_api_missing_non_optional_param_args_bad(self): | |
167 | id_, params = _build_data(self.apikey, 'get_repo') |
|
167 | id_, params = _build_data(self.apikey, 'get_repo') | |
168 | params = params.replace('"args": {}', '"args": 1') |
|
168 | params = params.replace('"args": {}', '"args": 1') | |
169 | response = api_call(self, params) |
|
169 | response = api_call(self, params) | |
170 |
|
170 | |||
171 | expected = 'Missing non optional `repoid` arg in JSON DATA' |
|
171 | expected = 'Missing non optional `repoid` arg in JSON DATA' | |
172 | self._compare_error(id_, expected, given=response.body) |
|
172 | self._compare_error(id_, expected, given=response.body) | |
173 |
|
173 | |||
174 | def test_api_args_is_null(self): |
|
174 | def test_api_args_is_null(self): | |
175 | id_, params = _build_data(self.apikey, 'get_users',) |
|
175 | id_, params = _build_data(self.apikey, 'get_users',) | |
176 | params = params.replace('"args": {}', '"args": null') |
|
176 | params = params.replace('"args": {}', '"args": null') | |
177 | response = api_call(self, params) |
|
177 | response = api_call(self, params) | |
178 | self.assertEqual(response.status, '200 OK') |
|
178 | self.assertEqual(response.status, '200 OK') | |
179 |
|
179 | |||
180 | def test_api_args_is_bad(self): |
|
180 | def test_api_args_is_bad(self): | |
181 | id_, params = _build_data(self.apikey, 'get_users',) |
|
181 | id_, params = _build_data(self.apikey, 'get_users',) | |
182 | params = params.replace('"args": {}', '"args": 1') |
|
182 | params = params.replace('"args": {}', '"args": 1') | |
183 | response = api_call(self, params) |
|
183 | response = api_call(self, params) | |
184 | self.assertEqual(response.status, '200 OK') |
|
184 | self.assertEqual(response.status, '200 OK') | |
185 |
|
185 | |||
186 | def test_api_get_users(self): |
|
186 | def test_api_get_users(self): | |
187 | id_, params = _build_data(self.apikey, 'get_users',) |
|
187 | id_, params = _build_data(self.apikey, 'get_users',) | |
188 | response = api_call(self, params) |
|
188 | response = api_call(self, params) | |
189 | ret_all = [] |
|
189 | ret_all = [] | |
190 | for usr in UserModel().get_all(): |
|
190 | for usr in UserModel().get_all(): | |
191 | ret = usr.get_api_data() |
|
191 | ret = usr.get_api_data() | |
192 | ret_all.append(jsonify(ret)) |
|
192 | ret_all.append(jsonify(ret)) | |
193 | expected = ret_all |
|
193 | expected = ret_all | |
194 | self._compare_ok(id_, expected, given=response.body) |
|
194 | self._compare_ok(id_, expected, given=response.body) | |
195 |
|
195 | |||
196 | def test_api_get_user(self): |
|
196 | def test_api_get_user(self): | |
197 | id_, params = _build_data(self.apikey, 'get_user', |
|
197 | id_, params = _build_data(self.apikey, 'get_user', | |
198 | userid=TEST_USER_ADMIN_LOGIN) |
|
198 | userid=TEST_USER_ADMIN_LOGIN) | |
199 | response = api_call(self, params) |
|
199 | response = api_call(self, params) | |
200 |
|
200 | |||
201 | usr = UserModel().get_by_username(TEST_USER_ADMIN_LOGIN) |
|
201 | usr = UserModel().get_by_username(TEST_USER_ADMIN_LOGIN) | |
202 | ret = usr.get_api_data() |
|
202 | ret = usr.get_api_data() | |
203 | ret['permissions'] = AuthUser(usr.user_id).permissions |
|
203 | ret['permissions'] = AuthUser(usr.user_id).permissions | |
204 |
|
204 | |||
205 | expected = ret |
|
205 | expected = ret | |
206 | self._compare_ok(id_, expected, given=response.body) |
|
206 | self._compare_ok(id_, expected, given=response.body) | |
207 |
|
207 | |||
208 | def test_api_get_user_that_does_not_exist(self): |
|
208 | def test_api_get_user_that_does_not_exist(self): | |
209 | id_, params = _build_data(self.apikey, 'get_user', |
|
209 | id_, params = _build_data(self.apikey, 'get_user', | |
210 | userid='trololo') |
|
210 | userid='trololo') | |
211 | response = api_call(self, params) |
|
211 | response = api_call(self, params) | |
212 |
|
212 | |||
213 | expected = "user `%s` does not exist" % 'trololo' |
|
213 | expected = "user `%s` does not exist" % 'trololo' | |
214 | self._compare_error(id_, expected, given=response.body) |
|
214 | self._compare_error(id_, expected, given=response.body) | |
215 |
|
215 | |||
216 | def test_api_get_user_without_giving_userid(self): |
|
216 | def test_api_get_user_without_giving_userid(self): | |
217 | id_, params = _build_data(self.apikey, 'get_user') |
|
217 | id_, params = _build_data(self.apikey, 'get_user') | |
218 | response = api_call(self, params) |
|
218 | response = api_call(self, params) | |
219 |
|
219 | |||
220 | usr = UserModel().get_by_username(TEST_USER_ADMIN_LOGIN) |
|
220 | usr = UserModel().get_by_username(TEST_USER_ADMIN_LOGIN) | |
221 | ret = usr.get_api_data() |
|
221 | ret = usr.get_api_data() | |
222 | ret['permissions'] = AuthUser(usr.user_id).permissions |
|
222 | ret['permissions'] = AuthUser(usr.user_id).permissions | |
223 |
|
223 | |||
224 | expected = ret |
|
224 | expected = ret | |
225 | self._compare_ok(id_, expected, given=response.body) |
|
225 | self._compare_ok(id_, expected, given=response.body) | |
226 |
|
226 | |||
227 | def test_api_get_user_without_giving_userid_non_admin(self): |
|
227 | def test_api_get_user_without_giving_userid_non_admin(self): | |
228 | id_, params = _build_data(self.apikey_regular, 'get_user') |
|
228 | id_, params = _build_data(self.apikey_regular, 'get_user') | |
229 | response = api_call(self, params) |
|
229 | response = api_call(self, params) | |
230 |
|
230 | |||
231 | usr = UserModel().get_by_username(self.TEST_USER_LOGIN) |
|
231 | usr = UserModel().get_by_username(self.TEST_USER_LOGIN) | |
232 | ret = usr.get_api_data() |
|
232 | ret = usr.get_api_data() | |
233 | ret['permissions'] = AuthUser(usr.user_id).permissions |
|
233 | ret['permissions'] = AuthUser(usr.user_id).permissions | |
234 |
|
234 | |||
235 | expected = ret |
|
235 | expected = ret | |
236 | self._compare_ok(id_, expected, given=response.body) |
|
236 | self._compare_ok(id_, expected, given=response.body) | |
237 |
|
237 | |||
238 | def test_api_get_user_with_giving_userid_non_admin(self): |
|
238 | def test_api_get_user_with_giving_userid_non_admin(self): | |
239 | id_, params = _build_data(self.apikey_regular, 'get_user', |
|
239 | id_, params = _build_data(self.apikey_regular, 'get_user', | |
240 | userid=self.TEST_USER_LOGIN) |
|
240 | userid=self.TEST_USER_LOGIN) | |
241 | response = api_call(self, params) |
|
241 | response = api_call(self, params) | |
242 |
|
242 | |||
243 | expected = 'userid is not the same as your user' |
|
243 | expected = 'userid is not the same as your user' | |
244 | self._compare_error(id_, expected, given=response.body) |
|
244 | self._compare_error(id_, expected, given=response.body) | |
245 |
|
245 | |||
246 | def test_api_pull(self): |
|
246 | def test_api_pull(self): | |
247 | #TODO: issues with rhodecode_extras here.. not sure why ! |
|
247 | #TODO: issues with rhodecode_extras here.. not sure why ! | |
248 | pass |
|
248 | pass | |
249 |
|
249 | |||
250 | # repo_name = 'test_pull' |
|
250 | # repo_name = 'test_pull' | |
251 | # r = create_repo(repo_name, self.REPO_TYPE) |
|
251 | # r = create_repo(repo_name, self.REPO_TYPE) | |
252 | # r.clone_uri = TEST_self.REPO |
|
252 | # r.clone_uri = TEST_self.REPO | |
253 | # Session.add(r) |
|
253 | # Session.add(r) | |
254 | # Session.commit() |
|
254 | # Session.commit() | |
255 | # |
|
255 | # | |
256 | # id_, params = _build_data(self.apikey, 'pull', |
|
256 | # id_, params = _build_data(self.apikey, 'pull', | |
257 | # repoid=repo_name,) |
|
257 | # repoid=repo_name,) | |
258 | # response = self.app.post(API_URL, content_type='application/json', |
|
258 | # response = self.app.post(API_URL, content_type='application/json', | |
259 | # params=params) |
|
259 | # params=params) | |
260 | # |
|
260 | # | |
261 | # expected = 'Pulled from `%s`' % repo_name |
|
261 | # expected = 'Pulled from `%s`' % repo_name | |
262 | # self._compare_ok(id_, expected, given=response.body) |
|
262 | # self._compare_ok(id_, expected, given=response.body) | |
263 | # |
|
263 | # | |
264 | # destroy_repo(repo_name) |
|
264 | # destroy_repo(repo_name) | |
265 |
|
265 | |||
266 | def test_api_pull_error(self): |
|
266 | def test_api_pull_error(self): | |
267 | id_, params = _build_data(self.apikey, 'pull', |
|
267 | id_, params = _build_data(self.apikey, 'pull', | |
268 | repoid=self.REPO,) |
|
268 | repoid=self.REPO,) | |
269 | response = api_call(self, params) |
|
269 | response = api_call(self, params) | |
270 |
|
270 | |||
271 | expected = 'Unable to pull changes from `%s`' % self.REPO |
|
271 | expected = 'Unable to pull changes from `%s`' % self.REPO | |
272 | self._compare_error(id_, expected, given=response.body) |
|
272 | self._compare_error(id_, expected, given=response.body) | |
273 |
|
273 | |||
274 | def test_api_rescan_repos(self): |
|
274 | def test_api_rescan_repos(self): | |
275 | id_, params = _build_data(self.apikey, 'rescan_repos') |
|
275 | id_, params = _build_data(self.apikey, 'rescan_repos') | |
276 | response = api_call(self, params) |
|
276 | response = api_call(self, params) | |
277 |
|
277 | |||
278 | expected = {'added': [], 'removed': []} |
|
278 | expected = {'added': [], 'removed': []} | |
279 | self._compare_ok(id_, expected, given=response.body) |
|
279 | self._compare_ok(id_, expected, given=response.body) | |
280 |
|
280 | |||
281 | @mock.patch.object(ScmModel, 'repo_scan', crash) |
|
281 | @mock.patch.object(ScmModel, 'repo_scan', crash) | |
282 | def test_api_rescann_error(self): |
|
282 | def test_api_rescann_error(self): | |
283 | id_, params = _build_data(self.apikey, 'rescan_repos',) |
|
283 | id_, params = _build_data(self.apikey, 'rescan_repos',) | |
284 | response = api_call(self, params) |
|
284 | response = api_call(self, params) | |
285 |
|
285 | |||
286 | expected = 'Error occurred during rescan repositories action' |
|
286 | expected = 'Error occurred during rescan repositories action' | |
287 | self._compare_error(id_, expected, given=response.body) |
|
287 | self._compare_error(id_, expected, given=response.body) | |
288 |
|
288 | |||
289 | def test_api_invalidate_cache(self): |
|
289 | def test_api_invalidate_cache(self): | |
290 | id_, params = _build_data(self.apikey, 'invalidate_cache', |
|
290 | id_, params = _build_data(self.apikey, 'invalidate_cache', | |
291 | repoid=self.REPO) |
|
291 | repoid=self.REPO) | |
292 | response = api_call(self, params) |
|
292 | response = api_call(self, params) | |
293 |
|
293 | |||
294 | expected = ("Cache for repository `%s` was invalidated: " |
|
294 | expected = ("Cache for repository `%s` was invalidated: " | |
295 | "invalidated cache keys: %s" % (self.REPO, |
|
295 | "invalidated cache keys: %s" % (self.REPO, | |
296 | [unicode(self.REPO)])) |
|
296 | [unicode(self.REPO)])) | |
297 | self._compare_ok(id_, expected, given=response.body) |
|
297 | self._compare_ok(id_, expected, given=response.body) | |
298 |
|
298 | |||
299 | @mock.patch.object(ScmModel, 'mark_for_invalidation', crash) |
|
299 | @mock.patch.object(ScmModel, 'mark_for_invalidation', crash) | |
300 | def test_api_invalidate_cache_error(self): |
|
300 | def test_api_invalidate_cache_error(self): | |
301 | id_, params = _build_data(self.apikey, 'invalidate_cache', |
|
301 | id_, params = _build_data(self.apikey, 'invalidate_cache', | |
302 | repoid=self.REPO) |
|
302 | repoid=self.REPO) | |
303 | response = api_call(self, params) |
|
303 | response = api_call(self, params) | |
304 |
|
304 | |||
305 | expected = 'Error occurred during cache invalidation action' |
|
305 | expected = 'Error occurred during cache invalidation action' | |
306 | self._compare_error(id_, expected, given=response.body) |
|
306 | self._compare_error(id_, expected, given=response.body) | |
307 |
|
307 | |||
308 | def test_api_lock_repo_lock_aquire(self): |
|
308 | def test_api_lock_repo_lock_aquire(self): | |
309 | id_, params = _build_data(self.apikey, 'lock', |
|
309 | id_, params = _build_data(self.apikey, 'lock', | |
310 | userid=TEST_USER_ADMIN_LOGIN, |
|
310 | userid=TEST_USER_ADMIN_LOGIN, | |
311 | repoid=self.REPO, |
|
311 | repoid=self.REPO, | |
312 | locked=True) |
|
312 | locked=True) | |
313 | response = api_call(self, params) |
|
313 | response = api_call(self, params) | |
314 | expected = ('User `%s` set lock state for repo `%s` to `%s`' |
|
314 | expected = ('User `%s` set lock state for repo `%s` to `%s`' | |
315 | % (TEST_USER_ADMIN_LOGIN, self.REPO, True)) |
|
315 | % (TEST_USER_ADMIN_LOGIN, self.REPO, True)) | |
316 | self._compare_ok(id_, expected, given=response.body) |
|
316 | self._compare_ok(id_, expected, given=response.body) | |
317 |
|
317 | |||
318 | def test_api_lock_repo_lock_aquire_by_non_admin(self): |
|
318 | def test_api_lock_repo_lock_aquire_by_non_admin(self): | |
319 | repo_name = 'api_delete_me' |
|
319 | repo_name = 'api_delete_me' | |
320 | create_repo(repo_name, self.REPO_TYPE, owner=self.TEST_USER_LOGIN) |
|
320 | create_repo(repo_name, self.REPO_TYPE, owner=self.TEST_USER_LOGIN) | |
321 | try: |
|
321 | try: | |
322 | id_, params = _build_data(self.apikey_regular, 'lock', |
|
322 | id_, params = _build_data(self.apikey_regular, 'lock', | |
323 | repoid=repo_name, |
|
323 | repoid=repo_name, | |
324 | locked=True) |
|
324 | locked=True) | |
325 | response = api_call(self, params) |
|
325 | response = api_call(self, params) | |
326 | expected = ('User `%s` set lock state for repo `%s` to `%s`' |
|
326 | expected = ('User `%s` set lock state for repo `%s` to `%s`' | |
327 | % (self.TEST_USER_LOGIN, repo_name, True)) |
|
327 | % (self.TEST_USER_LOGIN, repo_name, True)) | |
328 | self._compare_ok(id_, expected, given=response.body) |
|
328 | self._compare_ok(id_, expected, given=response.body) | |
329 | finally: |
|
329 | finally: | |
330 | destroy_repo(repo_name) |
|
330 | destroy_repo(repo_name) | |
331 |
|
331 | |||
332 | def test_api_lock_repo_lock_aquire_non_admin_with_userid(self): |
|
332 | def test_api_lock_repo_lock_aquire_non_admin_with_userid(self): | |
333 | repo_name = 'api_delete_me' |
|
333 | repo_name = 'api_delete_me' | |
334 | create_repo(repo_name, self.REPO_TYPE, owner=self.TEST_USER_LOGIN) |
|
334 | create_repo(repo_name, self.REPO_TYPE, owner=self.TEST_USER_LOGIN) | |
335 | try: |
|
335 | try: | |
336 | id_, params = _build_data(self.apikey_regular, 'lock', |
|
336 | id_, params = _build_data(self.apikey_regular, 'lock', | |
337 | userid=TEST_USER_ADMIN_LOGIN, |
|
337 | userid=TEST_USER_ADMIN_LOGIN, | |
338 | repoid=repo_name, |
|
338 | repoid=repo_name, | |
339 | locked=True) |
|
339 | locked=True) | |
340 | response = api_call(self, params) |
|
340 | response = api_call(self, params) | |
341 | expected = 'userid is not the same as your user' |
|
341 | expected = 'userid is not the same as your user' | |
342 | self._compare_error(id_, expected, given=response.body) |
|
342 | self._compare_error(id_, expected, given=response.body) | |
343 | finally: |
|
343 | finally: | |
344 | destroy_repo(repo_name) |
|
344 | destroy_repo(repo_name) | |
345 |
|
345 | |||
346 | def test_api_lock_repo_lock_aquire_non_admin_not_his_repo(self): |
|
346 | def test_api_lock_repo_lock_aquire_non_admin_not_his_repo(self): | |
347 | id_, params = _build_data(self.apikey_regular, 'lock', |
|
347 | id_, params = _build_data(self.apikey_regular, 'lock', | |
348 | repoid=self.REPO, |
|
348 | repoid=self.REPO, | |
349 | locked=True) |
|
349 | locked=True) | |
350 | response = api_call(self, params) |
|
350 | response = api_call(self, params) | |
351 | expected = 'repository `%s` does not exist' % (self.REPO) |
|
351 | expected = 'repository `%s` does not exist' % (self.REPO) | |
352 | self._compare_error(id_, expected, given=response.body) |
|
352 | self._compare_error(id_, expected, given=response.body) | |
353 |
|
353 | |||
354 | def test_api_lock_repo_lock_release(self): |
|
354 | def test_api_lock_repo_lock_release(self): | |
355 | id_, params = _build_data(self.apikey, 'lock', |
|
355 | id_, params = _build_data(self.apikey, 'lock', | |
356 | userid=TEST_USER_ADMIN_LOGIN, |
|
356 | userid=TEST_USER_ADMIN_LOGIN, | |
357 | repoid=self.REPO, |
|
357 | repoid=self.REPO, | |
358 | locked=False) |
|
358 | locked=False) | |
359 | response = api_call(self, params) |
|
359 | response = api_call(self, params) | |
360 | expected = ('User `%s` set lock state for repo `%s` to `%s`' |
|
360 | expected = ('User `%s` set lock state for repo `%s` to `%s`' | |
361 | % (TEST_USER_ADMIN_LOGIN, self.REPO, False)) |
|
361 | % (TEST_USER_ADMIN_LOGIN, self.REPO, False)) | |
362 | self._compare_ok(id_, expected, given=response.body) |
|
362 | self._compare_ok(id_, expected, given=response.body) | |
363 |
|
363 | |||
364 | def test_api_lock_repo_lock_aquire_optional_userid(self): |
|
364 | def test_api_lock_repo_lock_aquire_optional_userid(self): | |
365 | id_, params = _build_data(self.apikey, 'lock', |
|
365 | id_, params = _build_data(self.apikey, 'lock', | |
366 | repoid=self.REPO, |
|
366 | repoid=self.REPO, | |
367 | locked=True) |
|
367 | locked=True) | |
368 | response = api_call(self, params) |
|
368 | response = api_call(self, params) | |
369 | expected = ('User `%s` set lock state for repo `%s` to `%s`' |
|
369 | expected = ('User `%s` set lock state for repo `%s` to `%s`' | |
370 | % (TEST_USER_ADMIN_LOGIN, self.REPO, True)) |
|
370 | % (TEST_USER_ADMIN_LOGIN, self.REPO, True)) | |
371 | self._compare_ok(id_, expected, given=response.body) |
|
371 | self._compare_ok(id_, expected, given=response.body) | |
372 |
|
372 | |||
373 | @mock.patch.object(Repository, 'lock', crash) |
|
373 | @mock.patch.object(Repository, 'lock', crash) | |
374 | def test_api_lock_error(self): |
|
374 | def test_api_lock_error(self): | |
375 | id_, params = _build_data(self.apikey, 'lock', |
|
375 | id_, params = _build_data(self.apikey, 'lock', | |
376 | userid=TEST_USER_ADMIN_LOGIN, |
|
376 | userid=TEST_USER_ADMIN_LOGIN, | |
377 | repoid=self.REPO, |
|
377 | repoid=self.REPO, | |
378 | locked=True) |
|
378 | locked=True) | |
379 | response = api_call(self, params) |
|
379 | response = api_call(self, params) | |
380 |
|
380 | |||
381 | expected = 'Error occurred locking repository `%s`' % self.REPO |
|
381 | expected = 'Error occurred locking repository `%s`' % self.REPO | |
382 | self._compare_error(id_, expected, given=response.body) |
|
382 | self._compare_error(id_, expected, given=response.body) | |
383 |
|
383 | |||
384 | def test_api_create_existing_user(self): |
|
384 | def test_api_create_existing_user(self): | |
385 | id_, params = _build_data(self.apikey, 'create_user', |
|
385 | id_, params = _build_data(self.apikey, 'create_user', | |
386 | username=TEST_USER_ADMIN_LOGIN, |
|
386 | username=TEST_USER_ADMIN_LOGIN, | |
387 | email='test@foo.com', |
|
387 | email='test@foo.com', | |
388 | password='trololo') |
|
388 | password='trololo') | |
389 | response = api_call(self, params) |
|
389 | response = api_call(self, params) | |
390 |
|
390 | |||
391 | expected = "user `%s` already exist" % TEST_USER_ADMIN_LOGIN |
|
391 | expected = "user `%s` already exist" % TEST_USER_ADMIN_LOGIN | |
392 | self._compare_error(id_, expected, given=response.body) |
|
392 | self._compare_error(id_, expected, given=response.body) | |
393 |
|
393 | |||
394 | def test_api_create_user_with_existing_email(self): |
|
394 | def test_api_create_user_with_existing_email(self): | |
395 | id_, params = _build_data(self.apikey, 'create_user', |
|
395 | id_, params = _build_data(self.apikey, 'create_user', | |
396 | username=TEST_USER_ADMIN_LOGIN + 'new', |
|
396 | username=TEST_USER_ADMIN_LOGIN + 'new', | |
397 | email=TEST_USER_REGULAR_EMAIL, |
|
397 | email=TEST_USER_REGULAR_EMAIL, | |
398 | password='trololo') |
|
398 | password='trololo') | |
399 | response = api_call(self, params) |
|
399 | response = api_call(self, params) | |
400 |
|
400 | |||
401 | expected = "email `%s` already exist" % TEST_USER_REGULAR_EMAIL |
|
401 | expected = "email `%s` already exist" % TEST_USER_REGULAR_EMAIL | |
402 | self._compare_error(id_, expected, given=response.body) |
|
402 | self._compare_error(id_, expected, given=response.body) | |
403 |
|
403 | |||
404 | def test_api_create_user(self): |
|
404 | def test_api_create_user(self): | |
405 | username = 'test_new_api_user' |
|
405 | username = 'test_new_api_user' | |
406 | email = username + "@foo.com" |
|
406 | email = username + "@foo.com" | |
407 |
|
407 | |||
408 | id_, params = _build_data(self.apikey, 'create_user', |
|
408 | id_, params = _build_data(self.apikey, 'create_user', | |
409 | username=username, |
|
409 | username=username, | |
410 | email=email, |
|
410 | email=email, | |
411 | password='trololo') |
|
411 | password='trololo') | |
412 | response = api_call(self, params) |
|
412 | response = api_call(self, params) | |
413 |
|
413 | |||
414 | usr = UserModel().get_by_username(username) |
|
414 | usr = UserModel().get_by_username(username) | |
415 | ret = dict( |
|
415 | ret = dict( | |
416 | msg='created new user `%s`' % username, |
|
416 | msg='created new user `%s`' % username, | |
417 | user=jsonify(usr.get_api_data()) |
|
417 | user=jsonify(usr.get_api_data()) | |
418 | ) |
|
418 | ) | |
419 |
|
419 | |||
420 | expected = ret |
|
420 | expected = ret | |
421 | self._compare_ok(id_, expected, given=response.body) |
|
421 | self._compare_ok(id_, expected, given=response.body) | |
422 |
|
422 | |||
423 | UserModel().delete(usr.user_id) |
|
423 | UserModel().delete(usr.user_id) | |
424 | Session().commit() |
|
424 | Session().commit() | |
425 |
|
425 | |||
426 | @mock.patch.object(UserModel, 'create_or_update', crash) |
|
426 | @mock.patch.object(UserModel, 'create_or_update', crash) | |
427 | def test_api_create_user_when_exception_happened(self): |
|
427 | def test_api_create_user_when_exception_happened(self): | |
428 |
|
428 | |||
429 | username = 'test_new_api_user' |
|
429 | username = 'test_new_api_user' | |
430 | email = username + "@foo.com" |
|
430 | email = username + "@foo.com" | |
431 |
|
431 | |||
432 | id_, params = _build_data(self.apikey, 'create_user', |
|
432 | id_, params = _build_data(self.apikey, 'create_user', | |
433 | username=username, |
|
433 | username=username, | |
434 | email=email, |
|
434 | email=email, | |
435 | password='trololo') |
|
435 | password='trololo') | |
436 | response = api_call(self, params) |
|
436 | response = api_call(self, params) | |
437 | expected = 'failed to create user `%s`' % username |
|
437 | expected = 'failed to create user `%s`' % username | |
438 | self._compare_error(id_, expected, given=response.body) |
|
438 | self._compare_error(id_, expected, given=response.body) | |
439 |
|
439 | |||
440 | def test_api_delete_user(self): |
|
440 | def test_api_delete_user(self): | |
441 | usr = UserModel().create_or_update(username=u'test_user', |
|
441 | usr = UserModel().create_or_update(username=u'test_user', | |
442 | password=u'qweqwe', |
|
442 | password=u'qweqwe', | |
443 | email=u'u232@rhodecode.org', |
|
443 | email=u'u232@rhodecode.org', | |
444 | firstname=u'u1', lastname=u'u1') |
|
444 | firstname=u'u1', lastname=u'u1') | |
445 | Session().commit() |
|
445 | Session().commit() | |
446 | username = usr.username |
|
446 | username = usr.username | |
447 | email = usr.email |
|
447 | email = usr.email | |
448 | usr_id = usr.user_id |
|
448 | usr_id = usr.user_id | |
449 | ## DELETE THIS USER NOW |
|
449 | ## DELETE THIS USER NOW | |
450 |
|
450 | |||
451 | id_, params = _build_data(self.apikey, 'delete_user', |
|
451 | id_, params = _build_data(self.apikey, 'delete_user', | |
452 | userid=username,) |
|
452 | userid=username,) | |
453 | response = api_call(self, params) |
|
453 | response = api_call(self, params) | |
454 |
|
454 | |||
455 | ret = {'msg': 'deleted user ID:%s %s' % (usr_id, username), |
|
455 | ret = {'msg': 'deleted user ID:%s %s' % (usr_id, username), | |
456 | 'user': None} |
|
456 | 'user': None} | |
457 | expected = ret |
|
457 | expected = ret | |
458 | self._compare_ok(id_, expected, given=response.body) |
|
458 | self._compare_ok(id_, expected, given=response.body) | |
459 |
|
459 | |||
460 | @mock.patch.object(UserModel, 'delete', crash) |
|
460 | @mock.patch.object(UserModel, 'delete', crash) | |
461 | def test_api_delete_user_when_exception_happened(self): |
|
461 | def test_api_delete_user_when_exception_happened(self): | |
462 | usr = UserModel().create_or_update(username=u'test_user', |
|
462 | usr = UserModel().create_or_update(username=u'test_user', | |
463 | password=u'qweqwe', |
|
463 | password=u'qweqwe', | |
464 | email=u'u232@rhodecode.org', |
|
464 | email=u'u232@rhodecode.org', | |
465 | firstname=u'u1', lastname=u'u1') |
|
465 | firstname=u'u1', lastname=u'u1') | |
466 | Session().commit() |
|
466 | Session().commit() | |
467 | username = usr.username |
|
467 | username = usr.username | |
468 |
|
468 | |||
469 | id_, params = _build_data(self.apikey, 'delete_user', |
|
469 | id_, params = _build_data(self.apikey, 'delete_user', | |
470 | userid=username,) |
|
470 | userid=username,) | |
471 | response = api_call(self, params) |
|
471 | response = api_call(self, params) | |
472 | ret = 'failed to delete ID:%s %s' % (usr.user_id, |
|
472 | ret = 'failed to delete ID:%s %s' % (usr.user_id, | |
473 | usr.username) |
|
473 | usr.username) | |
474 | expected = ret |
|
474 | expected = ret | |
475 | self._compare_error(id_, expected, given=response.body) |
|
475 | self._compare_error(id_, expected, given=response.body) | |
476 |
|
476 | |||
477 | @parameterized.expand([('firstname', 'new_username'), |
|
477 | @parameterized.expand([('firstname', 'new_username'), | |
478 | ('lastname', 'new_username'), |
|
478 | ('lastname', 'new_username'), | |
479 | ('email', 'new_username'), |
|
479 | ('email', 'new_username'), | |
480 | ('admin', True), |
|
480 | ('admin', True), | |
481 | ('admin', False), |
|
481 | ('admin', False), | |
482 | ('ldap_dn', 'test'), |
|
482 | ('ldap_dn', 'test'), | |
483 | ('ldap_dn', None), |
|
483 | ('ldap_dn', None), | |
484 | ('active', False), |
|
484 | ('active', False), | |
485 | ('active', True), |
|
485 | ('active', True), | |
486 | ('password', 'newpass') |
|
486 | ('password', 'newpass') | |
487 | ]) |
|
487 | ]) | |
488 | def test_api_update_user(self, name, expected): |
|
488 | def test_api_update_user(self, name, expected): | |
489 | usr = UserModel().get_by_username(self.TEST_USER_LOGIN) |
|
489 | usr = UserModel().get_by_username(self.TEST_USER_LOGIN) | |
490 | kw = {name: expected, |
|
490 | kw = {name: expected, | |
491 | 'userid': usr.user_id} |
|
491 | 'userid': usr.user_id} | |
492 | id_, params = _build_data(self.apikey, 'update_user', **kw) |
|
492 | id_, params = _build_data(self.apikey, 'update_user', **kw) | |
493 | response = api_call(self, params) |
|
493 | response = api_call(self, params) | |
494 |
|
494 | |||
495 | ret = { |
|
495 | ret = { | |
496 | 'msg': 'updated user ID:%s %s' % (usr.user_id, self.TEST_USER_LOGIN), |
|
496 | 'msg': 'updated user ID:%s %s' % (usr.user_id, self.TEST_USER_LOGIN), | |
497 | 'user': jsonify(UserModel()\ |
|
497 | 'user': jsonify(UserModel()\ | |
498 | .get_by_username(self.TEST_USER_LOGIN)\ |
|
498 | .get_by_username(self.TEST_USER_LOGIN)\ | |
499 | .get_api_data()) |
|
499 | .get_api_data()) | |
500 | } |
|
500 | } | |
501 |
|
501 | |||
502 | expected = ret |
|
502 | expected = ret | |
503 | self._compare_ok(id_, expected, given=response.body) |
|
503 | self._compare_ok(id_, expected, given=response.body) | |
504 |
|
504 | |||
505 | def test_api_update_user_no_changed_params(self): |
|
505 | def test_api_update_user_no_changed_params(self): | |
506 | usr = UserModel().get_by_username(TEST_USER_ADMIN_LOGIN) |
|
506 | usr = UserModel().get_by_username(TEST_USER_ADMIN_LOGIN) | |
507 | ret = jsonify(usr.get_api_data()) |
|
507 | ret = jsonify(usr.get_api_data()) | |
508 | id_, params = _build_data(self.apikey, 'update_user', |
|
508 | id_, params = _build_data(self.apikey, 'update_user', | |
509 | userid=TEST_USER_ADMIN_LOGIN) |
|
509 | userid=TEST_USER_ADMIN_LOGIN) | |
510 |
|
510 | |||
511 | response = api_call(self, params) |
|
511 | response = api_call(self, params) | |
512 | ret = { |
|
512 | ret = { | |
513 | 'msg': 'updated user ID:%s %s' % (usr.user_id, TEST_USER_ADMIN_LOGIN), |
|
513 | 'msg': 'updated user ID:%s %s' % (usr.user_id, TEST_USER_ADMIN_LOGIN), | |
514 | 'user': ret |
|
514 | 'user': ret | |
515 | } |
|
515 | } | |
516 | expected = ret |
|
516 | expected = ret | |
517 | self._compare_ok(id_, expected, given=response.body) |
|
517 | self._compare_ok(id_, expected, given=response.body) | |
518 |
|
518 | |||
519 | def test_api_update_user_by_user_id(self): |
|
519 | def test_api_update_user_by_user_id(self): | |
520 | usr = UserModel().get_by_username(TEST_USER_ADMIN_LOGIN) |
|
520 | usr = UserModel().get_by_username(TEST_USER_ADMIN_LOGIN) | |
521 | ret = jsonify(usr.get_api_data()) |
|
521 | ret = jsonify(usr.get_api_data()) | |
522 | id_, params = _build_data(self.apikey, 'update_user', |
|
522 | id_, params = _build_data(self.apikey, 'update_user', | |
523 | userid=usr.user_id) |
|
523 | userid=usr.user_id) | |
524 |
|
524 | |||
525 | response = api_call(self, params) |
|
525 | response = api_call(self, params) | |
526 | ret = { |
|
526 | ret = { | |
527 | 'msg': 'updated user ID:%s %s' % (usr.user_id, TEST_USER_ADMIN_LOGIN), |
|
527 | 'msg': 'updated user ID:%s %s' % (usr.user_id, TEST_USER_ADMIN_LOGIN), | |
528 | 'user': ret |
|
528 | 'user': ret | |
529 | } |
|
529 | } | |
530 | expected = ret |
|
530 | expected = ret | |
531 | self._compare_ok(id_, expected, given=response.body) |
|
531 | self._compare_ok(id_, expected, given=response.body) | |
532 |
|
532 | |||
533 | @mock.patch.object(UserModel, 'update_user', crash) |
|
533 | @mock.patch.object(UserModel, 'update_user', crash) | |
534 | def test_api_update_user_when_exception_happens(self): |
|
534 | def test_api_update_user_when_exception_happens(self): | |
535 | usr = UserModel().get_by_username(TEST_USER_ADMIN_LOGIN) |
|
535 | usr = UserModel().get_by_username(TEST_USER_ADMIN_LOGIN) | |
536 | ret = jsonify(usr.get_api_data()) |
|
536 | ret = jsonify(usr.get_api_data()) | |
537 | id_, params = _build_data(self.apikey, 'update_user', |
|
537 | id_, params = _build_data(self.apikey, 'update_user', | |
538 | userid=usr.user_id) |
|
538 | userid=usr.user_id) | |
539 |
|
539 | |||
540 | response = api_call(self, params) |
|
540 | response = api_call(self, params) | |
541 | ret = 'failed to update user `%s`' % usr.user_id |
|
541 | ret = 'failed to update user `%s`' % usr.user_id | |
542 |
|
542 | |||
543 | expected = ret |
|
543 | expected = ret | |
544 | self._compare_error(id_, expected, given=response.body) |
|
544 | self._compare_error(id_, expected, given=response.body) | |
545 |
|
545 | |||
546 | def test_api_get_repo(self): |
|
546 | def test_api_get_repo(self): | |
547 | new_group = 'some_new_group' |
|
547 | new_group = 'some_new_group' | |
548 | make_users_group(new_group) |
|
548 | make_users_group(new_group) | |
549 | RepoModel().grant_users_group_permission(repo=self.REPO, |
|
549 | RepoModel().grant_users_group_permission(repo=self.REPO, | |
550 | group_name=new_group, |
|
550 | group_name=new_group, | |
551 | perm='repository.read') |
|
551 | perm='repository.read') | |
552 | Session().commit() |
|
552 | Session().commit() | |
553 | id_, params = _build_data(self.apikey, 'get_repo', |
|
553 | id_, params = _build_data(self.apikey, 'get_repo', | |
554 | repoid=self.REPO) |
|
554 | repoid=self.REPO) | |
555 | response = api_call(self, params) |
|
555 | response = api_call(self, params) | |
556 |
|
556 | |||
557 | repo = RepoModel().get_by_repo_name(self.REPO) |
|
557 | repo = RepoModel().get_by_repo_name(self.REPO) | |
558 | ret = repo.get_api_data() |
|
558 | ret = repo.get_api_data() | |
559 |
|
559 | |||
560 | members = [] |
|
560 | members = [] | |
561 | followers = [] |
|
561 | followers = [] | |
562 | for user in repo.repo_to_perm: |
|
562 | for user in repo.repo_to_perm: | |
563 | perm = user.permission.permission_name |
|
563 | perm = user.permission.permission_name | |
564 | user = user.user |
|
564 | user = user.user | |
565 | user_data = user.get_api_data() |
|
565 | user_data = user.get_api_data() | |
566 | user_data['type'] = "user" |
|
566 | user_data['type'] = "user" | |
567 | user_data['permission'] = perm |
|
567 | user_data['permission'] = perm | |
568 | members.append(user_data) |
|
568 | members.append(user_data) | |
569 |
|
569 | |||
570 | for users_group in repo.users_group_to_perm: |
|
570 | for users_group in repo.users_group_to_perm: | |
571 | perm = users_group.permission.permission_name |
|
571 | perm = users_group.permission.permission_name | |
572 | users_group = users_group.users_group |
|
572 | users_group = users_group.users_group | |
573 | users_group_data = users_group.get_api_data() |
|
573 | users_group_data = users_group.get_api_data() | |
574 | users_group_data['type'] = "users_group" |
|
574 | users_group_data['type'] = "users_group" | |
575 | users_group_data['permission'] = perm |
|
575 | users_group_data['permission'] = perm | |
576 | members.append(users_group_data) |
|
576 | members.append(users_group_data) | |
577 |
|
577 | |||
578 | for user in repo.followers: |
|
578 | for user in repo.followers: | |
579 | followers.append(user.user.get_api_data()) |
|
579 | followers.append(user.user.get_api_data()) | |
580 |
|
580 | |||
581 | ret['members'] = members |
|
581 | ret['members'] = members | |
582 | ret['followers'] = followers |
|
582 | ret['followers'] = followers | |
583 |
|
583 | |||
584 | expected = ret |
|
584 | expected = ret | |
585 | self._compare_ok(id_, expected, given=response.body) |
|
585 | self._compare_ok(id_, expected, given=response.body) | |
586 | destroy_users_group(new_group) |
|
586 | destroy_users_group(new_group) | |
587 |
|
587 | |||
588 | def test_api_get_repo_by_non_admin(self): |
|
588 | def test_api_get_repo_by_non_admin(self): | |
589 | id_, params = _build_data(self.apikey, 'get_repo', |
|
589 | id_, params = _build_data(self.apikey, 'get_repo', | |
590 | repoid=self.REPO) |
|
590 | repoid=self.REPO) | |
591 | response = api_call(self, params) |
|
591 | response = api_call(self, params) | |
592 |
|
592 | |||
593 | repo = RepoModel().get_by_repo_name(self.REPO) |
|
593 | repo = RepoModel().get_by_repo_name(self.REPO) | |
594 | ret = repo.get_api_data() |
|
594 | ret = repo.get_api_data() | |
595 |
|
595 | |||
596 | members = [] |
|
596 | members = [] | |
597 | followers = [] |
|
597 | followers = [] | |
598 | for user in repo.repo_to_perm: |
|
598 | for user in repo.repo_to_perm: | |
599 | perm = user.permission.permission_name |
|
599 | perm = user.permission.permission_name | |
600 | user = user.user |
|
600 | user = user.user | |
601 | user_data = user.get_api_data() |
|
601 | user_data = user.get_api_data() | |
602 | user_data['type'] = "user" |
|
602 | user_data['type'] = "user" | |
603 | user_data['permission'] = perm |
|
603 | user_data['permission'] = perm | |
604 | members.append(user_data) |
|
604 | members.append(user_data) | |
605 |
|
605 | |||
606 | for users_group in repo.users_group_to_perm: |
|
606 | for users_group in repo.users_group_to_perm: | |
607 | perm = users_group.permission.permission_name |
|
607 | perm = users_group.permission.permission_name | |
608 | users_group = users_group.users_group |
|
608 | users_group = users_group.users_group | |
609 | users_group_data = users_group.get_api_data() |
|
609 | users_group_data = users_group.get_api_data() | |
610 | users_group_data['type'] = "users_group" |
|
610 | users_group_data['type'] = "users_group" | |
611 | users_group_data['permission'] = perm |
|
611 | users_group_data['permission'] = perm | |
612 | members.append(users_group_data) |
|
612 | members.append(users_group_data) | |
613 |
|
613 | |||
614 | for user in repo.followers: |
|
614 | for user in repo.followers: | |
615 | followers.append(user.user.get_api_data()) |
|
615 | followers.append(user.user.get_api_data()) | |
616 |
|
616 | |||
617 | ret['members'] = members |
|
617 | ret['members'] = members | |
618 | ret['followers'] = followers |
|
618 | ret['followers'] = followers | |
619 |
|
619 | |||
620 | expected = ret |
|
620 | expected = ret | |
621 | self._compare_ok(id_, expected, given=response.body) |
|
621 | self._compare_ok(id_, expected, given=response.body) | |
622 |
|
622 | |||
623 | def test_api_get_repo_by_non_admin_no_permission_to_repo(self): |
|
623 | def test_api_get_repo_by_non_admin_no_permission_to_repo(self): | |
624 | RepoModel().grant_user_permission(repo=self.REPO, |
|
624 | RepoModel().grant_user_permission(repo=self.REPO, | |
625 | user=self.TEST_USER_LOGIN, |
|
625 | user=self.TEST_USER_LOGIN, | |
626 | perm='repository.none') |
|
626 | perm='repository.none') | |
627 |
|
627 | |||
628 | id_, params = _build_data(self.apikey_regular, 'get_repo', |
|
628 | id_, params = _build_data(self.apikey_regular, 'get_repo', | |
629 | repoid=self.REPO) |
|
629 | repoid=self.REPO) | |
630 | response = api_call(self, params) |
|
630 | response = api_call(self, params) | |
631 |
|
631 | |||
632 | expected = 'repository `%s` does not exist' % (self.REPO) |
|
632 | expected = 'repository `%s` does not exist' % (self.REPO) | |
633 | self._compare_error(id_, expected, given=response.body) |
|
633 | self._compare_error(id_, expected, given=response.body) | |
634 |
|
634 | |||
635 | def test_api_get_repo_that_doesn_not_exist(self): |
|
635 | def test_api_get_repo_that_doesn_not_exist(self): | |
636 | id_, params = _build_data(self.apikey, 'get_repo', |
|
636 | id_, params = _build_data(self.apikey, 'get_repo', | |
637 | repoid='no-such-repo') |
|
637 | repoid='no-such-repo') | |
638 | response = api_call(self, params) |
|
638 | response = api_call(self, params) | |
639 |
|
639 | |||
640 | ret = 'repository `%s` does not exist' % 'no-such-repo' |
|
640 | ret = 'repository `%s` does not exist' % 'no-such-repo' | |
641 | expected = ret |
|
641 | expected = ret | |
642 | self._compare_error(id_, expected, given=response.body) |
|
642 | self._compare_error(id_, expected, given=response.body) | |
643 |
|
643 | |||
644 | def test_api_get_repos(self): |
|
644 | def test_api_get_repos(self): | |
645 | id_, params = _build_data(self.apikey, 'get_repos') |
|
645 | id_, params = _build_data(self.apikey, 'get_repos') | |
646 | response = api_call(self, params) |
|
646 | response = api_call(self, params) | |
647 |
|
647 | |||
648 | result = [] |
|
648 | result = [] | |
649 | for repo in RepoModel().get_all(): |
|
649 | for repo in RepoModel().get_all(): | |
650 | result.append(repo.get_api_data()) |
|
650 | result.append(repo.get_api_data()) | |
651 | ret = jsonify(result) |
|
651 | ret = jsonify(result) | |
652 |
|
652 | |||
653 | expected = ret |
|
653 | expected = ret | |
654 | self._compare_ok(id_, expected, given=response.body) |
|
654 | self._compare_ok(id_, expected, given=response.body) | |
655 |
|
655 | |||
656 | def test_api_get_repos_non_admin(self): |
|
656 | def test_api_get_repos_non_admin(self): | |
657 | id_, params = _build_data(self.apikey_regular, 'get_repos') |
|
657 | id_, params = _build_data(self.apikey_regular, 'get_repos') | |
658 | response = api_call(self, params) |
|
658 | response = api_call(self, params) | |
659 |
|
659 | |||
660 | result = [] |
|
660 | result = [] | |
661 | for repo in RepoModel().get_all_user_repos(self.TEST_USER_LOGIN): |
|
661 | for repo in RepoModel().get_all_user_repos(self.TEST_USER_LOGIN): | |
662 | result.append(repo.get_api_data()) |
|
662 | result.append(repo.get_api_data()) | |
663 | ret = jsonify(result) |
|
663 | ret = jsonify(result) | |
664 |
|
664 | |||
665 | expected = ret |
|
665 | expected = ret | |
666 | self._compare_ok(id_, expected, given=response.body) |
|
666 | self._compare_ok(id_, expected, given=response.body) | |
667 |
|
667 | |||
668 | @parameterized.expand([('all', 'all'), |
|
668 | @parameterized.expand([('all', 'all'), | |
669 | ('dirs', 'dirs'), |
|
669 | ('dirs', 'dirs'), | |
670 | ('files', 'files'), ]) |
|
670 | ('files', 'files'), ]) | |
671 | def test_api_get_repo_nodes(self, name, ret_type): |
|
671 | def test_api_get_repo_nodes(self, name, ret_type): | |
672 | rev = 'tip' |
|
672 | rev = 'tip' | |
673 | path = '/' |
|
673 | path = '/' | |
674 | id_, params = _build_data(self.apikey, 'get_repo_nodes', |
|
674 | id_, params = _build_data(self.apikey, 'get_repo_nodes', | |
675 | repoid=self.REPO, revision=rev, |
|
675 | repoid=self.REPO, revision=rev, | |
676 | root_path=path, |
|
676 | root_path=path, | |
677 | ret_type=ret_type) |
|
677 | ret_type=ret_type) | |
678 | response = api_call(self, params) |
|
678 | response = api_call(self, params) | |
679 |
|
679 | |||
680 | # we don't the actual return types here since it's tested somewhere |
|
680 | # we don't the actual return types here since it's tested somewhere | |
681 | # else |
|
681 | # else | |
682 | expected = json.loads(response.body)['result'] |
|
682 | expected = json.loads(response.body)['result'] | |
683 | self._compare_ok(id_, expected, given=response.body) |
|
683 | self._compare_ok(id_, expected, given=response.body) | |
684 |
|
684 | |||
685 | def test_api_get_repo_nodes_bad_revisions(self): |
|
685 | def test_api_get_repo_nodes_bad_revisions(self): | |
686 | rev = 'i-dont-exist' |
|
686 | rev = 'i-dont-exist' | |
687 | path = '/' |
|
687 | path = '/' | |
688 | id_, params = _build_data(self.apikey, 'get_repo_nodes', |
|
688 | id_, params = _build_data(self.apikey, 'get_repo_nodes', | |
689 | repoid=self.REPO, revision=rev, |
|
689 | repoid=self.REPO, revision=rev, | |
690 | root_path=path,) |
|
690 | root_path=path,) | |
691 | response = api_call(self, params) |
|
691 | response = api_call(self, params) | |
692 |
|
692 | |||
693 | expected = 'failed to get repo: `%s` nodes' % self.REPO |
|
693 | expected = 'failed to get repo: `%s` nodes' % self.REPO | |
694 | self._compare_error(id_, expected, given=response.body) |
|
694 | self._compare_error(id_, expected, given=response.body) | |
695 |
|
695 | |||
696 | def test_api_get_repo_nodes_bad_path(self): |
|
696 | def test_api_get_repo_nodes_bad_path(self): | |
697 | rev = 'tip' |
|
697 | rev = 'tip' | |
698 | path = '/idontexits' |
|
698 | path = '/idontexits' | |
699 | id_, params = _build_data(self.apikey, 'get_repo_nodes', |
|
699 | id_, params = _build_data(self.apikey, 'get_repo_nodes', | |
700 | repoid=self.REPO, revision=rev, |
|
700 | repoid=self.REPO, revision=rev, | |
701 | root_path=path,) |
|
701 | root_path=path,) | |
702 | response = api_call(self, params) |
|
702 | response = api_call(self, params) | |
703 |
|
703 | |||
704 | expected = 'failed to get repo: `%s` nodes' % self.REPO |
|
704 | expected = 'failed to get repo: `%s` nodes' % self.REPO | |
705 | self._compare_error(id_, expected, given=response.body) |
|
705 | self._compare_error(id_, expected, given=response.body) | |
706 |
|
706 | |||
707 | def test_api_get_repo_nodes_bad_ret_type(self): |
|
707 | def test_api_get_repo_nodes_bad_ret_type(self): | |
708 | rev = 'tip' |
|
708 | rev = 'tip' | |
709 | path = '/' |
|
709 | path = '/' | |
710 | ret_type = 'error' |
|
710 | ret_type = 'error' | |
711 | id_, params = _build_data(self.apikey, 'get_repo_nodes', |
|
711 | id_, params = _build_data(self.apikey, 'get_repo_nodes', | |
712 | repoid=self.REPO, revision=rev, |
|
712 | repoid=self.REPO, revision=rev, | |
713 | root_path=path, |
|
713 | root_path=path, | |
714 | ret_type=ret_type) |
|
714 | ret_type=ret_type) | |
715 | response = api_call(self, params) |
|
715 | response = api_call(self, params) | |
716 |
|
716 | |||
717 | expected = 'ret_type must be one of %s' % (['files', 'dirs', 'all']) |
|
717 | expected = 'ret_type must be one of %s' % (['files', 'dirs', 'all']) | |
718 | self._compare_error(id_, expected, given=response.body) |
|
718 | self._compare_error(id_, expected, given=response.body) | |
719 |
|
719 | |||
720 | def test_api_create_repo(self): |
|
720 | def test_api_create_repo(self): | |
721 | repo_name = 'api-repo' |
|
721 | repo_name = 'api-repo' | |
722 | id_, params = _build_data(self.apikey, 'create_repo', |
|
722 | id_, params = _build_data(self.apikey, 'create_repo', | |
723 | repo_name=repo_name, |
|
723 | repo_name=repo_name, | |
724 | owner=TEST_USER_ADMIN_LOGIN, |
|
724 | owner=TEST_USER_ADMIN_LOGIN, | |
725 | repo_type='hg', |
|
725 | repo_type='hg', | |
726 | ) |
|
726 | ) | |
727 | response = api_call(self, params) |
|
727 | response = api_call(self, params) | |
728 |
|
728 | |||
729 | repo = RepoModel().get_by_repo_name(repo_name) |
|
729 | repo = RepoModel().get_by_repo_name(repo_name) | |
730 | ret = { |
|
730 | ret = { | |
731 | 'msg': 'Created new repository `%s`' % repo_name, |
|
731 | 'msg': 'Created new repository `%s`' % repo_name, | |
732 | 'repo': jsonify(repo.get_api_data()) |
|
732 | 'repo': jsonify(repo.get_api_data()) | |
733 | } |
|
733 | } | |
734 | expected = ret |
|
734 | expected = ret | |
735 | self._compare_ok(id_, expected, given=response.body) |
|
735 | self._compare_ok(id_, expected, given=response.body) | |
736 | destroy_repo(repo_name) |
|
736 | destroy_repo(repo_name) | |
737 |
|
737 | |||
738 | def test_api_create_repo_unknown_owner(self): |
|
738 | def test_api_create_repo_unknown_owner(self): | |
739 | repo_name = 'api-repo' |
|
739 | repo_name = 'api-repo' | |
740 | owner = 'i-dont-exist' |
|
740 | owner = 'i-dont-exist' | |
741 | id_, params = _build_data(self.apikey, 'create_repo', |
|
741 | id_, params = _build_data(self.apikey, 'create_repo', | |
742 | repo_name=repo_name, |
|
742 | repo_name=repo_name, | |
743 | owner=owner, |
|
743 | owner=owner, | |
744 | repo_type='hg', |
|
744 | repo_type='hg', | |
745 | ) |
|
745 | ) | |
746 | response = api_call(self, params) |
|
746 | response = api_call(self, params) | |
747 | expected = 'user `%s` does not exist' % owner |
|
747 | expected = 'user `%s` does not exist' % owner | |
748 | self._compare_error(id_, expected, given=response.body) |
|
748 | self._compare_error(id_, expected, given=response.body) | |
749 |
|
749 | |||
750 | def test_api_create_repo_dont_specify_owner(self): |
|
750 | def test_api_create_repo_dont_specify_owner(self): | |
751 | repo_name = 'api-repo' |
|
751 | repo_name = 'api-repo' | |
752 | owner = 'i-dont-exist' |
|
752 | owner = 'i-dont-exist' | |
753 | id_, params = _build_data(self.apikey, 'create_repo', |
|
753 | id_, params = _build_data(self.apikey, 'create_repo', | |
754 | repo_name=repo_name, |
|
754 | repo_name=repo_name, | |
755 | repo_type='hg', |
|
755 | repo_type='hg', | |
756 | ) |
|
756 | ) | |
757 | response = api_call(self, params) |
|
757 | response = api_call(self, params) | |
758 |
|
758 | |||
759 | repo = RepoModel().get_by_repo_name(repo_name) |
|
759 | repo = RepoModel().get_by_repo_name(repo_name) | |
760 | ret = { |
|
760 | ret = { | |
761 | 'msg': 'Created new repository `%s`' % repo_name, |
|
761 | 'msg': 'Created new repository `%s`' % repo_name, | |
762 | 'repo': jsonify(repo.get_api_data()) |
|
762 | 'repo': jsonify(repo.get_api_data()) | |
763 | } |
|
763 | } | |
764 | expected = ret |
|
764 | expected = ret | |
765 | self._compare_ok(id_, expected, given=response.body) |
|
765 | self._compare_ok(id_, expected, given=response.body) | |
766 | destroy_repo(repo_name) |
|
766 | destroy_repo(repo_name) | |
767 |
|
767 | |||
768 | def test_api_create_repo_by_non_admin(self): |
|
768 | def test_api_create_repo_by_non_admin(self): | |
769 | repo_name = 'api-repo' |
|
769 | repo_name = 'api-repo' | |
770 | owner = 'i-dont-exist' |
|
770 | owner = 'i-dont-exist' | |
771 | id_, params = _build_data(self.apikey_regular, 'create_repo', |
|
771 | id_, params = _build_data(self.apikey_regular, 'create_repo', | |
772 | repo_name=repo_name, |
|
772 | repo_name=repo_name, | |
773 | repo_type='hg', |
|
773 | repo_type='hg', | |
774 | ) |
|
774 | ) | |
775 | response = api_call(self, params) |
|
775 | response = api_call(self, params) | |
776 |
|
776 | |||
777 | repo = RepoModel().get_by_repo_name(repo_name) |
|
777 | repo = RepoModel().get_by_repo_name(repo_name) | |
778 | ret = { |
|
778 | ret = { | |
779 | 'msg': 'Created new repository `%s`' % repo_name, |
|
779 | 'msg': 'Created new repository `%s`' % repo_name, | |
780 | 'repo': jsonify(repo.get_api_data()) |
|
780 | 'repo': jsonify(repo.get_api_data()) | |
781 | } |
|
781 | } | |
782 | expected = ret |
|
782 | expected = ret | |
783 | self._compare_ok(id_, expected, given=response.body) |
|
783 | self._compare_ok(id_, expected, given=response.body) | |
784 | destroy_repo(repo_name) |
|
784 | destroy_repo(repo_name) | |
785 |
|
785 | |||
786 | def test_api_create_repo_by_non_admin_specify_owner(self): |
|
786 | def test_api_create_repo_by_non_admin_specify_owner(self): | |
787 | repo_name = 'api-repo' |
|
787 | repo_name = 'api-repo' | |
788 | owner = 'i-dont-exist' |
|
788 | owner = 'i-dont-exist' | |
789 | id_, params = _build_data(self.apikey_regular, 'create_repo', |
|
789 | id_, params = _build_data(self.apikey_regular, 'create_repo', | |
790 | repo_name=repo_name, |
|
790 | repo_name=repo_name, | |
791 | repo_type='hg', |
|
791 | repo_type='hg', | |
792 | owner=owner |
|
792 | owner=owner | |
793 | ) |
|
793 | ) | |
794 | response = api_call(self, params) |
|
794 | response = api_call(self, params) | |
795 |
|
795 | |||
796 | expected = 'Only RhodeCode admin can specify `owner` param' |
|
796 | expected = 'Only RhodeCode admin can specify `owner` param' | |
797 | self._compare_error(id_, expected, given=response.body) |
|
797 | self._compare_error(id_, expected, given=response.body) | |
798 | destroy_repo(repo_name) |
|
798 | destroy_repo(repo_name) | |
799 |
|
799 | |||
800 | def test_api_create_repo_exists(self): |
|
800 | def test_api_create_repo_exists(self): | |
801 | repo_name = self.REPO |
|
801 | repo_name = self.REPO | |
802 | id_, params = _build_data(self.apikey, 'create_repo', |
|
802 | id_, params = _build_data(self.apikey, 'create_repo', | |
803 | repo_name=repo_name, |
|
803 | repo_name=repo_name, | |
804 | owner=TEST_USER_ADMIN_LOGIN, |
|
804 | owner=TEST_USER_ADMIN_LOGIN, | |
805 | repo_type='hg', |
|
805 | repo_type='hg', | |
806 | ) |
|
806 | ) | |
807 | response = api_call(self, params) |
|
807 | response = api_call(self, params) | |
808 | expected = "repo `%s` already exist" % repo_name |
|
808 | expected = "repo `%s` already exist" % repo_name | |
809 | self._compare_error(id_, expected, given=response.body) |
|
809 | self._compare_error(id_, expected, given=response.body) | |
810 |
|
810 | |||
811 | @mock.patch.object(RepoModel, 'create_repo', crash) |
|
811 | @mock.patch.object(RepoModel, 'create_repo', crash) | |
812 | def test_api_create_repo_exception_occurred(self): |
|
812 | def test_api_create_repo_exception_occurred(self): | |
813 | repo_name = 'api-repo' |
|
813 | repo_name = 'api-repo' | |
814 | id_, params = _build_data(self.apikey, 'create_repo', |
|
814 | id_, params = _build_data(self.apikey, 'create_repo', | |
815 | repo_name=repo_name, |
|
815 | repo_name=repo_name, | |
816 | owner=TEST_USER_ADMIN_LOGIN, |
|
816 | owner=TEST_USER_ADMIN_LOGIN, | |
817 | repo_type='hg', |
|
817 | repo_type='hg', | |
818 | ) |
|
818 | ) | |
819 | response = api_call(self, params) |
|
819 | response = api_call(self, params) | |
820 | expected = 'failed to create repository `%s`' % repo_name |
|
820 | expected = 'failed to create repository `%s`' % repo_name | |
821 | self._compare_error(id_, expected, given=response.body) |
|
821 | self._compare_error(id_, expected, given=response.body) | |
822 |
|
822 | |||
823 | def test_api_delete_repo(self): |
|
823 | def test_api_delete_repo(self): | |
824 | repo_name = 'api_delete_me' |
|
824 | repo_name = 'api_delete_me' | |
825 | create_repo(repo_name, self.REPO_TYPE) |
|
825 | create_repo(repo_name, self.REPO_TYPE) | |
826 |
|
826 | |||
827 | id_, params = _build_data(self.apikey, 'delete_repo', |
|
827 | id_, params = _build_data(self.apikey, 'delete_repo', | |
828 | repoid=repo_name,) |
|
828 | repoid=repo_name,) | |
829 | response = api_call(self, params) |
|
829 | response = api_call(self, params) | |
830 |
|
830 | |||
831 | ret = { |
|
831 | ret = { | |
832 | 'msg': 'Deleted repository `%s`' % repo_name, |
|
832 | 'msg': 'Deleted repository `%s`' % repo_name, | |
833 | 'success': True |
|
833 | 'success': True | |
834 | } |
|
834 | } | |
835 | expected = ret |
|
835 | expected = ret | |
836 | self._compare_ok(id_, expected, given=response.body) |
|
836 | self._compare_ok(id_, expected, given=response.body) | |
837 |
|
837 | |||
838 | def test_api_delete_repo_by_non_admin(self): |
|
838 | def test_api_delete_repo_by_non_admin(self): | |
839 | repo_name = 'api_delete_me' |
|
839 | repo_name = 'api_delete_me' | |
840 | create_repo(repo_name, self.REPO_TYPE, owner=self.TEST_USER_LOGIN) |
|
840 | create_repo(repo_name, self.REPO_TYPE, owner=self.TEST_USER_LOGIN) | |
841 | try: |
|
841 | try: | |
842 | id_, params = _build_data(self.apikey_regular, 'delete_repo', |
|
842 | id_, params = _build_data(self.apikey_regular, 'delete_repo', | |
843 | repoid=repo_name,) |
|
843 | repoid=repo_name,) | |
844 | response = api_call(self, params) |
|
844 | response = api_call(self, params) | |
845 |
|
845 | |||
846 | ret = { |
|
846 | ret = { | |
847 | 'msg': 'Deleted repository `%s`' % repo_name, |
|
847 | 'msg': 'Deleted repository `%s`' % repo_name, | |
848 | 'success': True |
|
848 | 'success': True | |
849 | } |
|
849 | } | |
850 | expected = ret |
|
850 | expected = ret | |
851 | self._compare_ok(id_, expected, given=response.body) |
|
851 | self._compare_ok(id_, expected, given=response.body) | |
852 | finally: |
|
852 | finally: | |
853 | destroy_repo(repo_name) |
|
853 | destroy_repo(repo_name) | |
854 |
|
854 | |||
855 | def test_api_delete_repo_by_non_admin_no_permission(self): |
|
855 | def test_api_delete_repo_by_non_admin_no_permission(self): | |
856 | repo_name = 'api_delete_me' |
|
856 | repo_name = 'api_delete_me' | |
857 | create_repo(repo_name, self.REPO_TYPE) |
|
857 | create_repo(repo_name, self.REPO_TYPE) | |
858 | try: |
|
858 | try: | |
859 | id_, params = _build_data(self.apikey_regular, 'delete_repo', |
|
859 | id_, params = _build_data(self.apikey_regular, 'delete_repo', | |
860 | repoid=repo_name,) |
|
860 | repoid=repo_name,) | |
861 | response = api_call(self, params) |
|
861 | response = api_call(self, params) | |
862 | expected = 'repository `%s` does not exist' % (repo_name) |
|
862 | expected = 'repository `%s` does not exist' % (repo_name) | |
863 | self._compare_error(id_, expected, given=response.body) |
|
863 | self._compare_error(id_, expected, given=response.body) | |
864 | finally: |
|
864 | finally: | |
865 | destroy_repo(repo_name) |
|
865 | destroy_repo(repo_name) | |
866 |
|
866 | |||
867 | def test_api_delete_repo_exception_occurred(self): |
|
867 | def test_api_delete_repo_exception_occurred(self): | |
868 | repo_name = 'api_delete_me' |
|
868 | repo_name = 'api_delete_me' | |
869 | create_repo(repo_name, self.REPO_TYPE) |
|
869 | create_repo(repo_name, self.REPO_TYPE) | |
870 | try: |
|
870 | try: | |
871 | with mock.patch.object(RepoModel, 'delete', crash): |
|
871 | with mock.patch.object(RepoModel, 'delete', crash): | |
872 | id_, params = _build_data(self.apikey, 'delete_repo', |
|
872 | id_, params = _build_data(self.apikey, 'delete_repo', | |
873 | repoid=repo_name,) |
|
873 | repoid=repo_name,) | |
874 | response = api_call(self, params) |
|
874 | response = api_call(self, params) | |
875 |
|
875 | |||
876 | expected = 'failed to delete repository `%s`' % repo_name |
|
876 | expected = 'failed to delete repository `%s`' % repo_name | |
877 | self._compare_error(id_, expected, given=response.body) |
|
877 | self._compare_error(id_, expected, given=response.body) | |
878 | finally: |
|
878 | finally: | |
879 | destroy_repo(repo_name) |
|
879 | destroy_repo(repo_name) | |
880 |
|
880 | |||
881 | def test_api_fork_repo(self): |
|
881 | def test_api_fork_repo(self): | |
882 | fork_name = 'api-repo-fork' |
|
882 | fork_name = 'api-repo-fork' | |
883 | id_, params = _build_data(self.apikey, 'fork_repo', |
|
883 | id_, params = _build_data(self.apikey, 'fork_repo', | |
884 | repoid=self.REPO, |
|
884 | repoid=self.REPO, | |
885 | fork_name=fork_name, |
|
885 | fork_name=fork_name, | |
886 | owner=TEST_USER_ADMIN_LOGIN, |
|
886 | owner=TEST_USER_ADMIN_LOGIN, | |
887 | ) |
|
887 | ) | |
888 | response = api_call(self, params) |
|
888 | response = api_call(self, params) | |
889 |
|
889 | |||
890 | ret = { |
|
890 | ret = { | |
891 | 'msg': 'Created fork of `%s` as `%s`' % (self.REPO, |
|
891 | 'msg': 'Created fork of `%s` as `%s`' % (self.REPO, | |
892 | fork_name), |
|
892 | fork_name), | |
893 | 'success': True |
|
893 | 'success': True | |
894 | } |
|
894 | } | |
895 | expected = ret |
|
895 | expected = ret | |
896 | self._compare_ok(id_, expected, given=response.body) |
|
896 | self._compare_ok(id_, expected, given=response.body) | |
897 | destroy_repo(fork_name) |
|
897 | destroy_repo(fork_name) | |
898 |
|
898 | |||
899 | def test_api_fork_repo_non_admin(self): |
|
899 | def test_api_fork_repo_non_admin(self): | |
900 | fork_name = 'api-repo-fork' |
|
900 | fork_name = 'api-repo-fork' | |
901 | id_, params = _build_data(self.apikey_regular, 'fork_repo', |
|
901 | id_, params = _build_data(self.apikey_regular, 'fork_repo', | |
902 | repoid=self.REPO, |
|
902 | repoid=self.REPO, | |
903 | fork_name=fork_name, |
|
903 | fork_name=fork_name, | |
904 | ) |
|
904 | ) | |
905 | response = api_call(self, params) |
|
905 | response = api_call(self, params) | |
906 |
|
906 | |||
907 | ret = { |
|
907 | ret = { | |
908 | 'msg': 'Created fork of `%s` as `%s`' % (self.REPO, |
|
908 | 'msg': 'Created fork of `%s` as `%s`' % (self.REPO, | |
909 | fork_name), |
|
909 | fork_name), | |
910 | 'success': True |
|
910 | 'success': True | |
911 | } |
|
911 | } | |
912 | expected = ret |
|
912 | expected = ret | |
913 | self._compare_ok(id_, expected, given=response.body) |
|
913 | self._compare_ok(id_, expected, given=response.body) | |
914 | destroy_repo(fork_name) |
|
914 | destroy_repo(fork_name) | |
915 |
|
915 | |||
916 | def test_api_fork_repo_non_admin_specify_owner(self): |
|
916 | def test_api_fork_repo_non_admin_specify_owner(self): | |
917 | fork_name = 'api-repo-fork' |
|
917 | fork_name = 'api-repo-fork' | |
918 | id_, params = _build_data(self.apikey_regular, 'fork_repo', |
|
918 | id_, params = _build_data(self.apikey_regular, 'fork_repo', | |
919 | repoid=self.REPO, |
|
919 | repoid=self.REPO, | |
920 | fork_name=fork_name, |
|
920 | fork_name=fork_name, | |
921 | owner=TEST_USER_ADMIN_LOGIN, |
|
921 | owner=TEST_USER_ADMIN_LOGIN, | |
922 | ) |
|
922 | ) | |
923 | response = api_call(self, params) |
|
923 | response = api_call(self, params) | |
924 | expected = 'Only RhodeCode admin can specify `owner` param' |
|
924 | expected = 'Only RhodeCode admin can specify `owner` param' | |
925 | self._compare_error(id_, expected, given=response.body) |
|
925 | self._compare_error(id_, expected, given=response.body) | |
926 | destroy_repo(fork_name) |
|
926 | destroy_repo(fork_name) | |
927 |
|
927 | |||
928 | def test_api_fork_repo_non_admin_no_permission_to_fork(self): |
|
928 | def test_api_fork_repo_non_admin_no_permission_to_fork(self): | |
929 | RepoModel().grant_user_permission(repo=self.REPO, |
|
929 | RepoModel().grant_user_permission(repo=self.REPO, | |
930 | user=self.TEST_USER_LOGIN, |
|
930 | user=self.TEST_USER_LOGIN, | |
931 | perm='repository.none') |
|
931 | perm='repository.none') | |
932 | fork_name = 'api-repo-fork' |
|
932 | fork_name = 'api-repo-fork' | |
933 | id_, params = _build_data(self.apikey_regular, 'fork_repo', |
|
933 | id_, params = _build_data(self.apikey_regular, 'fork_repo', | |
934 | repoid=self.REPO, |
|
934 | repoid=self.REPO, | |
935 | fork_name=fork_name, |
|
935 | fork_name=fork_name, | |
936 | ) |
|
936 | ) | |
937 | response = api_call(self, params) |
|
937 | response = api_call(self, params) | |
938 | expected = 'repository `%s` does not exist' % (self.REPO) |
|
938 | expected = 'repository `%s` does not exist' % (self.REPO) | |
939 | self._compare_error(id_, expected, given=response.body) |
|
939 | self._compare_error(id_, expected, given=response.body) | |
940 | destroy_repo(fork_name) |
|
940 | destroy_repo(fork_name) | |
941 |
|
941 | |||
942 | def test_api_fork_repo_unknown_owner(self): |
|
942 | def test_api_fork_repo_unknown_owner(self): | |
943 | fork_name = 'api-repo-fork' |
|
943 | fork_name = 'api-repo-fork' | |
944 | owner = 'i-dont-exist' |
|
944 | owner = 'i-dont-exist' | |
945 | id_, params = _build_data(self.apikey, 'fork_repo', |
|
945 | id_, params = _build_data(self.apikey, 'fork_repo', | |
946 | repoid=self.REPO, |
|
946 | repoid=self.REPO, | |
947 | fork_name=fork_name, |
|
947 | fork_name=fork_name, | |
948 | owner=owner, |
|
948 | owner=owner, | |
949 | ) |
|
949 | ) | |
950 | response = api_call(self, params) |
|
950 | response = api_call(self, params) | |
951 | expected = 'user `%s` does not exist' % owner |
|
951 | expected = 'user `%s` does not exist' % owner | |
952 | self._compare_error(id_, expected, given=response.body) |
|
952 | self._compare_error(id_, expected, given=response.body) | |
953 |
|
953 | |||
954 | def test_api_fork_repo_fork_exists(self): |
|
954 | def test_api_fork_repo_fork_exists(self): | |
955 | fork_name = 'api-repo-fork' |
|
955 | fork_name = 'api-repo-fork' | |
956 | create_fork(fork_name, self.REPO_TYPE, self.REPO) |
|
956 | create_fork(fork_name, self.REPO_TYPE, self.REPO) | |
957 |
|
957 | |||
958 | try: |
|
958 | try: | |
959 | fork_name = 'api-repo-fork' |
|
959 | fork_name = 'api-repo-fork' | |
960 |
|
960 | |||
961 | id_, params = _build_data(self.apikey, 'fork_repo', |
|
961 | id_, params = _build_data(self.apikey, 'fork_repo', | |
962 | repoid=self.REPO, |
|
962 | repoid=self.REPO, | |
963 | fork_name=fork_name, |
|
963 | fork_name=fork_name, | |
964 | owner=TEST_USER_ADMIN_LOGIN, |
|
964 | owner=TEST_USER_ADMIN_LOGIN, | |
965 | ) |
|
965 | ) | |
966 | response = api_call(self, params) |
|
966 | response = api_call(self, params) | |
967 |
|
967 | |||
968 | expected = "fork `%s` already exist" % fork_name |
|
968 | expected = "fork `%s` already exist" % fork_name | |
969 | self._compare_error(id_, expected, given=response.body) |
|
969 | self._compare_error(id_, expected, given=response.body) | |
970 | finally: |
|
970 | finally: | |
971 | destroy_repo(fork_name) |
|
971 | destroy_repo(fork_name) | |
972 |
|
972 | |||
973 | def test_api_fork_repo_repo_exists(self): |
|
973 | def test_api_fork_repo_repo_exists(self): | |
974 | fork_name = self.REPO |
|
974 | fork_name = self.REPO | |
975 |
|
975 | |||
976 | id_, params = _build_data(self.apikey, 'fork_repo', |
|
976 | id_, params = _build_data(self.apikey, 'fork_repo', | |
977 | repoid=self.REPO, |
|
977 | repoid=self.REPO, | |
978 | fork_name=fork_name, |
|
978 | fork_name=fork_name, | |
979 | owner=TEST_USER_ADMIN_LOGIN, |
|
979 | owner=TEST_USER_ADMIN_LOGIN, | |
980 | ) |
|
980 | ) | |
981 | response = api_call(self, params) |
|
981 | response = api_call(self, params) | |
982 |
|
982 | |||
983 | expected = "repo `%s` already exist" % fork_name |
|
983 | expected = "repo `%s` already exist" % fork_name | |
984 | self._compare_error(id_, expected, given=response.body) |
|
984 | self._compare_error(id_, expected, given=response.body) | |
985 |
|
985 | |||
986 | @mock.patch.object(RepoModel, 'create_fork', crash) |
|
986 | @mock.patch.object(RepoModel, 'create_fork', crash) | |
987 | def test_api_fork_repo_exception_occurred(self): |
|
987 | def test_api_fork_repo_exception_occurred(self): | |
988 | fork_name = 'api-repo-fork' |
|
988 | fork_name = 'api-repo-fork' | |
989 | id_, params = _build_data(self.apikey, 'fork_repo', |
|
989 | id_, params = _build_data(self.apikey, 'fork_repo', | |
990 | repoid=self.REPO, |
|
990 | repoid=self.REPO, | |
991 | fork_name=fork_name, |
|
991 | fork_name=fork_name, | |
992 | owner=TEST_USER_ADMIN_LOGIN, |
|
992 | owner=TEST_USER_ADMIN_LOGIN, | |
993 | ) |
|
993 | ) | |
994 | response = api_call(self, params) |
|
994 | response = api_call(self, params) | |
995 |
|
995 | |||
996 | expected = 'failed to fork repository `%s` as `%s`' % (self.REPO, |
|
996 | expected = 'failed to fork repository `%s` as `%s`' % (self.REPO, | |
997 | fork_name) |
|
997 | fork_name) | |
998 | self._compare_error(id_, expected, given=response.body) |
|
998 | self._compare_error(id_, expected, given=response.body) | |
999 |
|
999 | |||
1000 | def test_api_get_users_group(self): |
|
1000 | def test_api_get_users_group(self): | |
1001 | id_, params = _build_data(self.apikey, 'get_users_group', |
|
1001 | id_, params = _build_data(self.apikey, 'get_users_group', | |
1002 | usersgroupid=TEST_USERS_GROUP) |
|
1002 | usersgroupid=TEST_USERS_GROUP) | |
1003 | response = api_call(self, params) |
|
1003 | response = api_call(self, params) | |
1004 |
|
1004 | |||
1005 | users_group = UsersGroupModel().get_group(TEST_USERS_GROUP) |
|
1005 | users_group = UsersGroupModel().get_group(TEST_USERS_GROUP) | |
1006 | members = [] |
|
1006 | members = [] | |
1007 | for user in users_group.members: |
|
1007 | for user in users_group.members: | |
1008 | user = user.user |
|
1008 | user = user.user | |
1009 | members.append(user.get_api_data()) |
|
1009 | members.append(user.get_api_data()) | |
1010 |
|
1010 | |||
1011 | ret = users_group.get_api_data() |
|
1011 | ret = users_group.get_api_data() | |
1012 | ret['members'] = members |
|
1012 | ret['members'] = members | |
1013 | expected = ret |
|
1013 | expected = ret | |
1014 | self._compare_ok(id_, expected, given=response.body) |
|
1014 | self._compare_ok(id_, expected, given=response.body) | |
1015 |
|
1015 | |||
1016 | def test_api_get_users_groups(self): |
|
1016 | def test_api_get_users_groups(self): | |
1017 |
|
1017 | |||
1018 | make_users_group('test_users_group2') |
|
1018 | make_users_group('test_users_group2') | |
1019 |
|
1019 | |||
1020 | id_, params = _build_data(self.apikey, 'get_users_groups',) |
|
1020 | id_, params = _build_data(self.apikey, 'get_users_groups',) | |
1021 | response = api_call(self, params) |
|
1021 | response = api_call(self, params) | |
1022 |
|
1022 | |||
1023 | expected = [] |
|
1023 | expected = [] | |
1024 | for gr_name in [TEST_USERS_GROUP, 'test_users_group2']: |
|
1024 | for gr_name in [TEST_USERS_GROUP, 'test_users_group2']: | |
1025 | users_group = UsersGroupModel().get_group(gr_name) |
|
1025 | users_group = UsersGroupModel().get_group(gr_name) | |
1026 | ret = users_group.get_api_data() |
|
1026 | ret = users_group.get_api_data() | |
1027 | expected.append(ret) |
|
1027 | expected.append(ret) | |
1028 | self._compare_ok(id_, expected, given=response.body) |
|
1028 | self._compare_ok(id_, expected, given=response.body) | |
1029 |
|
1029 | |||
1030 | UsersGroupModel().delete(users_group='test_users_group2') |
|
1030 | UsersGroupModel().delete(users_group='test_users_group2') | |
1031 | Session().commit() |
|
1031 | Session().commit() | |
1032 |
|
1032 | |||
1033 | def test_api_create_users_group(self): |
|
1033 | def test_api_create_users_group(self): | |
1034 | group_name = 'some_new_group' |
|
1034 | group_name = 'some_new_group' | |
1035 | id_, params = _build_data(self.apikey, 'create_users_group', |
|
1035 | id_, params = _build_data(self.apikey, 'create_users_group', | |
1036 | group_name=group_name) |
|
1036 | group_name=group_name) | |
1037 | response = api_call(self, params) |
|
1037 | response = api_call(self, params) | |
1038 |
|
1038 | |||
1039 | ret = { |
|
1039 | ret = { | |
1040 |
'msg': 'created new user |
|
1040 | 'msg': 'created new user group `%s`' % group_name, | |
1041 | 'users_group': jsonify(UsersGroupModel()\ |
|
1041 | 'users_group': jsonify(UsersGroupModel()\ | |
1042 | .get_by_name(group_name)\ |
|
1042 | .get_by_name(group_name)\ | |
1043 | .get_api_data()) |
|
1043 | .get_api_data()) | |
1044 | } |
|
1044 | } | |
1045 | expected = ret |
|
1045 | expected = ret | |
1046 | self._compare_ok(id_, expected, given=response.body) |
|
1046 | self._compare_ok(id_, expected, given=response.body) | |
1047 |
|
1047 | |||
1048 | destroy_users_group(group_name) |
|
1048 | destroy_users_group(group_name) | |
1049 |
|
1049 | |||
1050 | def test_api_get_users_group_that_exist(self): |
|
1050 | def test_api_get_users_group_that_exist(self): | |
1051 | id_, params = _build_data(self.apikey, 'create_users_group', |
|
1051 | id_, params = _build_data(self.apikey, 'create_users_group', | |
1052 | group_name=TEST_USERS_GROUP) |
|
1052 | group_name=TEST_USERS_GROUP) | |
1053 | response = api_call(self, params) |
|
1053 | response = api_call(self, params) | |
1054 |
|
1054 | |||
1055 |
expected = "user |
|
1055 | expected = "user group `%s` already exist" % TEST_USERS_GROUP | |
1056 | self._compare_error(id_, expected, given=response.body) |
|
1056 | self._compare_error(id_, expected, given=response.body) | |
1057 |
|
1057 | |||
1058 | @mock.patch.object(UsersGroupModel, 'create', crash) |
|
1058 | @mock.patch.object(UsersGroupModel, 'create', crash) | |
1059 | def test_api_get_users_group_exception_occurred(self): |
|
1059 | def test_api_get_users_group_exception_occurred(self): | |
1060 | group_name = 'exception_happens' |
|
1060 | group_name = 'exception_happens' | |
1061 | id_, params = _build_data(self.apikey, 'create_users_group', |
|
1061 | id_, params = _build_data(self.apikey, 'create_users_group', | |
1062 | group_name=group_name) |
|
1062 | group_name=group_name) | |
1063 | response = api_call(self, params) |
|
1063 | response = api_call(self, params) | |
1064 |
|
1064 | |||
1065 | expected = 'failed to create group `%s`' % group_name |
|
1065 | expected = 'failed to create group `%s`' % group_name | |
1066 | self._compare_error(id_, expected, given=response.body) |
|
1066 | self._compare_error(id_, expected, given=response.body) | |
1067 |
|
1067 | |||
1068 | def test_api_add_user_to_users_group(self): |
|
1068 | def test_api_add_user_to_users_group(self): | |
1069 | gr_name = 'test_group' |
|
1069 | gr_name = 'test_group' | |
1070 | UsersGroupModel().create(gr_name) |
|
1070 | UsersGroupModel().create(gr_name) | |
1071 | Session().commit() |
|
1071 | Session().commit() | |
1072 | id_, params = _build_data(self.apikey, 'add_user_to_users_group', |
|
1072 | id_, params = _build_data(self.apikey, 'add_user_to_users_group', | |
1073 | usersgroupid=gr_name, |
|
1073 | usersgroupid=gr_name, | |
1074 | userid=TEST_USER_ADMIN_LOGIN) |
|
1074 | userid=TEST_USER_ADMIN_LOGIN) | |
1075 | response = api_call(self, params) |
|
1075 | response = api_call(self, params) | |
1076 |
|
1076 | |||
1077 | expected = { |
|
1077 | expected = { | |
1078 |
'msg': 'added member `%s` to user |
|
1078 | 'msg': 'added member `%s` to user group `%s`' % ( | |
1079 | TEST_USER_ADMIN_LOGIN, gr_name |
|
1079 | TEST_USER_ADMIN_LOGIN, gr_name | |
1080 | ), |
|
1080 | ), | |
1081 | 'success': True} |
|
1081 | 'success': True} | |
1082 | self._compare_ok(id_, expected, given=response.body) |
|
1082 | self._compare_ok(id_, expected, given=response.body) | |
1083 |
|
1083 | |||
1084 | UsersGroupModel().delete(users_group=gr_name) |
|
1084 | UsersGroupModel().delete(users_group=gr_name) | |
1085 | Session().commit() |
|
1085 | Session().commit() | |
1086 |
|
1086 | |||
1087 | def test_api_add_user_to_users_group_that_doesnt_exist(self): |
|
1087 | def test_api_add_user_to_users_group_that_doesnt_exist(self): | |
1088 | id_, params = _build_data(self.apikey, 'add_user_to_users_group', |
|
1088 | id_, params = _build_data(self.apikey, 'add_user_to_users_group', | |
1089 | usersgroupid='false-group', |
|
1089 | usersgroupid='false-group', | |
1090 | userid=TEST_USER_ADMIN_LOGIN) |
|
1090 | userid=TEST_USER_ADMIN_LOGIN) | |
1091 | response = api_call(self, params) |
|
1091 | response = api_call(self, params) | |
1092 |
|
1092 | |||
1093 |
expected = 'user |
|
1093 | expected = 'user group `%s` does not exist' % 'false-group' | |
1094 | self._compare_error(id_, expected, given=response.body) |
|
1094 | self._compare_error(id_, expected, given=response.body) | |
1095 |
|
1095 | |||
1096 | @mock.patch.object(UsersGroupModel, 'add_user_to_group', crash) |
|
1096 | @mock.patch.object(UsersGroupModel, 'add_user_to_group', crash) | |
1097 | def test_api_add_user_to_users_group_exception_occurred(self): |
|
1097 | def test_api_add_user_to_users_group_exception_occurred(self): | |
1098 | gr_name = 'test_group' |
|
1098 | gr_name = 'test_group' | |
1099 | UsersGroupModel().create(gr_name) |
|
1099 | UsersGroupModel().create(gr_name) | |
1100 | Session().commit() |
|
1100 | Session().commit() | |
1101 | id_, params = _build_data(self.apikey, 'add_user_to_users_group', |
|
1101 | id_, params = _build_data(self.apikey, 'add_user_to_users_group', | |
1102 | usersgroupid=gr_name, |
|
1102 | usersgroupid=gr_name, | |
1103 | userid=TEST_USER_ADMIN_LOGIN) |
|
1103 | userid=TEST_USER_ADMIN_LOGIN) | |
1104 | response = api_call(self, params) |
|
1104 | response = api_call(self, params) | |
1105 |
|
1105 | |||
1106 |
expected = 'failed to add member to user |
|
1106 | expected = 'failed to add member to user group `%s`' % gr_name | |
1107 | self._compare_error(id_, expected, given=response.body) |
|
1107 | self._compare_error(id_, expected, given=response.body) | |
1108 |
|
1108 | |||
1109 | UsersGroupModel().delete(users_group=gr_name) |
|
1109 | UsersGroupModel().delete(users_group=gr_name) | |
1110 | Session().commit() |
|
1110 | Session().commit() | |
1111 |
|
1111 | |||
1112 | def test_api_remove_user_from_users_group(self): |
|
1112 | def test_api_remove_user_from_users_group(self): | |
1113 | gr_name = 'test_group_3' |
|
1113 | gr_name = 'test_group_3' | |
1114 | gr = UsersGroupModel().create(gr_name) |
|
1114 | gr = UsersGroupModel().create(gr_name) | |
1115 | UsersGroupModel().add_user_to_group(gr, user=TEST_USER_ADMIN_LOGIN) |
|
1115 | UsersGroupModel().add_user_to_group(gr, user=TEST_USER_ADMIN_LOGIN) | |
1116 | Session().commit() |
|
1116 | Session().commit() | |
1117 | id_, params = _build_data(self.apikey, 'remove_user_from_users_group', |
|
1117 | id_, params = _build_data(self.apikey, 'remove_user_from_users_group', | |
1118 | usersgroupid=gr_name, |
|
1118 | usersgroupid=gr_name, | |
1119 | userid=TEST_USER_ADMIN_LOGIN) |
|
1119 | userid=TEST_USER_ADMIN_LOGIN) | |
1120 | response = api_call(self, params) |
|
1120 | response = api_call(self, params) | |
1121 |
|
1121 | |||
1122 | expected = { |
|
1122 | expected = { | |
1123 |
'msg': 'removed member `%s` from user |
|
1123 | 'msg': 'removed member `%s` from user group `%s`' % ( | |
1124 | TEST_USER_ADMIN_LOGIN, gr_name |
|
1124 | TEST_USER_ADMIN_LOGIN, gr_name | |
1125 | ), |
|
1125 | ), | |
1126 | 'success': True} |
|
1126 | 'success': True} | |
1127 | self._compare_ok(id_, expected, given=response.body) |
|
1127 | self._compare_ok(id_, expected, given=response.body) | |
1128 |
|
1128 | |||
1129 | UsersGroupModel().delete(users_group=gr_name) |
|
1129 | UsersGroupModel().delete(users_group=gr_name) | |
1130 | Session().commit() |
|
1130 | Session().commit() | |
1131 |
|
1131 | |||
1132 | @mock.patch.object(UsersGroupModel, 'remove_user_from_group', crash) |
|
1132 | @mock.patch.object(UsersGroupModel, 'remove_user_from_group', crash) | |
1133 | def test_api_remove_user_from_users_group_exception_occurred(self): |
|
1133 | def test_api_remove_user_from_users_group_exception_occurred(self): | |
1134 | gr_name = 'test_group_3' |
|
1134 | gr_name = 'test_group_3' | |
1135 | gr = UsersGroupModel().create(gr_name) |
|
1135 | gr = UsersGroupModel().create(gr_name) | |
1136 | UsersGroupModel().add_user_to_group(gr, user=TEST_USER_ADMIN_LOGIN) |
|
1136 | UsersGroupModel().add_user_to_group(gr, user=TEST_USER_ADMIN_LOGIN) | |
1137 | Session().commit() |
|
1137 | Session().commit() | |
1138 | id_, params = _build_data(self.apikey, 'remove_user_from_users_group', |
|
1138 | id_, params = _build_data(self.apikey, 'remove_user_from_users_group', | |
1139 | usersgroupid=gr_name, |
|
1139 | usersgroupid=gr_name, | |
1140 | userid=TEST_USER_ADMIN_LOGIN) |
|
1140 | userid=TEST_USER_ADMIN_LOGIN) | |
1141 | response = api_call(self, params) |
|
1141 | response = api_call(self, params) | |
1142 |
|
1142 | |||
1143 |
expected = 'failed to remove member from user |
|
1143 | expected = 'failed to remove member from user group `%s`' % gr_name | |
1144 | self._compare_error(id_, expected, given=response.body) |
|
1144 | self._compare_error(id_, expected, given=response.body) | |
1145 |
|
1145 | |||
1146 | UsersGroupModel().delete(users_group=gr_name) |
|
1146 | UsersGroupModel().delete(users_group=gr_name) | |
1147 | Session().commit() |
|
1147 | Session().commit() | |
1148 |
|
1148 | |||
1149 | @parameterized.expand([('none', 'repository.none'), |
|
1149 | @parameterized.expand([('none', 'repository.none'), | |
1150 | ('read', 'repository.read'), |
|
1150 | ('read', 'repository.read'), | |
1151 | ('write', 'repository.write'), |
|
1151 | ('write', 'repository.write'), | |
1152 | ('admin', 'repository.admin')]) |
|
1152 | ('admin', 'repository.admin')]) | |
1153 | def test_api_grant_user_permission(self, name, perm): |
|
1153 | def test_api_grant_user_permission(self, name, perm): | |
1154 | id_, params = _build_data(self.apikey, 'grant_user_permission', |
|
1154 | id_, params = _build_data(self.apikey, 'grant_user_permission', | |
1155 | repoid=self.REPO, |
|
1155 | repoid=self.REPO, | |
1156 | userid=TEST_USER_ADMIN_LOGIN, |
|
1156 | userid=TEST_USER_ADMIN_LOGIN, | |
1157 | perm=perm) |
|
1157 | perm=perm) | |
1158 | response = api_call(self, params) |
|
1158 | response = api_call(self, params) | |
1159 |
|
1159 | |||
1160 | ret = { |
|
1160 | ret = { | |
1161 | 'msg': 'Granted perm: `%s` for user: `%s` in repo: `%s`' % ( |
|
1161 | 'msg': 'Granted perm: `%s` for user: `%s` in repo: `%s`' % ( | |
1162 | perm, TEST_USER_ADMIN_LOGIN, self.REPO |
|
1162 | perm, TEST_USER_ADMIN_LOGIN, self.REPO | |
1163 | ), |
|
1163 | ), | |
1164 | 'success': True |
|
1164 | 'success': True | |
1165 | } |
|
1165 | } | |
1166 | expected = ret |
|
1166 | expected = ret | |
1167 | self._compare_ok(id_, expected, given=response.body) |
|
1167 | self._compare_ok(id_, expected, given=response.body) | |
1168 |
|
1168 | |||
1169 | def test_api_grant_user_permission_wrong_permission(self): |
|
1169 | def test_api_grant_user_permission_wrong_permission(self): | |
1170 | perm = 'haha.no.permission' |
|
1170 | perm = 'haha.no.permission' | |
1171 | id_, params = _build_data(self.apikey, 'grant_user_permission', |
|
1171 | id_, params = _build_data(self.apikey, 'grant_user_permission', | |
1172 | repoid=self.REPO, |
|
1172 | repoid=self.REPO, | |
1173 | userid=TEST_USER_ADMIN_LOGIN, |
|
1173 | userid=TEST_USER_ADMIN_LOGIN, | |
1174 | perm=perm) |
|
1174 | perm=perm) | |
1175 | response = api_call(self, params) |
|
1175 | response = api_call(self, params) | |
1176 |
|
1176 | |||
1177 | expected = 'permission `%s` does not exist' % perm |
|
1177 | expected = 'permission `%s` does not exist' % perm | |
1178 | self._compare_error(id_, expected, given=response.body) |
|
1178 | self._compare_error(id_, expected, given=response.body) | |
1179 |
|
1179 | |||
1180 | @mock.patch.object(RepoModel, 'grant_user_permission', crash) |
|
1180 | @mock.patch.object(RepoModel, 'grant_user_permission', crash) | |
1181 | def test_api_grant_user_permission_exception_when_adding(self): |
|
1181 | def test_api_grant_user_permission_exception_when_adding(self): | |
1182 | perm = 'repository.read' |
|
1182 | perm = 'repository.read' | |
1183 | id_, params = _build_data(self.apikey, 'grant_user_permission', |
|
1183 | id_, params = _build_data(self.apikey, 'grant_user_permission', | |
1184 | repoid=self.REPO, |
|
1184 | repoid=self.REPO, | |
1185 | userid=TEST_USER_ADMIN_LOGIN, |
|
1185 | userid=TEST_USER_ADMIN_LOGIN, | |
1186 | perm=perm) |
|
1186 | perm=perm) | |
1187 | response = api_call(self, params) |
|
1187 | response = api_call(self, params) | |
1188 |
|
1188 | |||
1189 | expected = 'failed to edit permission for user: `%s` in repo: `%s`' % ( |
|
1189 | expected = 'failed to edit permission for user: `%s` in repo: `%s`' % ( | |
1190 | TEST_USER_ADMIN_LOGIN, self.REPO |
|
1190 | TEST_USER_ADMIN_LOGIN, self.REPO | |
1191 | ) |
|
1191 | ) | |
1192 | self._compare_error(id_, expected, given=response.body) |
|
1192 | self._compare_error(id_, expected, given=response.body) | |
1193 |
|
1193 | |||
1194 | def test_api_revoke_user_permission(self): |
|
1194 | def test_api_revoke_user_permission(self): | |
1195 | id_, params = _build_data(self.apikey, 'revoke_user_permission', |
|
1195 | id_, params = _build_data(self.apikey, 'revoke_user_permission', | |
1196 | repoid=self.REPO, |
|
1196 | repoid=self.REPO, | |
1197 | userid=TEST_USER_ADMIN_LOGIN,) |
|
1197 | userid=TEST_USER_ADMIN_LOGIN,) | |
1198 | response = api_call(self, params) |
|
1198 | response = api_call(self, params) | |
1199 |
|
1199 | |||
1200 | expected = { |
|
1200 | expected = { | |
1201 | 'msg': 'Revoked perm for user: `%s` in repo: `%s`' % ( |
|
1201 | 'msg': 'Revoked perm for user: `%s` in repo: `%s`' % ( | |
1202 | TEST_USER_ADMIN_LOGIN, self.REPO |
|
1202 | TEST_USER_ADMIN_LOGIN, self.REPO | |
1203 | ), |
|
1203 | ), | |
1204 | 'success': True |
|
1204 | 'success': True | |
1205 | } |
|
1205 | } | |
1206 | self._compare_ok(id_, expected, given=response.body) |
|
1206 | self._compare_ok(id_, expected, given=response.body) | |
1207 |
|
1207 | |||
1208 | @mock.patch.object(RepoModel, 'revoke_user_permission', crash) |
|
1208 | @mock.patch.object(RepoModel, 'revoke_user_permission', crash) | |
1209 | def test_api_revoke_user_permission_exception_when_adding(self): |
|
1209 | def test_api_revoke_user_permission_exception_when_adding(self): | |
1210 | id_, params = _build_data(self.apikey, 'revoke_user_permission', |
|
1210 | id_, params = _build_data(self.apikey, 'revoke_user_permission', | |
1211 | repoid=self.REPO, |
|
1211 | repoid=self.REPO, | |
1212 | userid=TEST_USER_ADMIN_LOGIN,) |
|
1212 | userid=TEST_USER_ADMIN_LOGIN,) | |
1213 | response = api_call(self, params) |
|
1213 | response = api_call(self, params) | |
1214 |
|
1214 | |||
1215 | expected = 'failed to edit permission for user: `%s` in repo: `%s`' % ( |
|
1215 | expected = 'failed to edit permission for user: `%s` in repo: `%s`' % ( | |
1216 | TEST_USER_ADMIN_LOGIN, self.REPO |
|
1216 | TEST_USER_ADMIN_LOGIN, self.REPO | |
1217 | ) |
|
1217 | ) | |
1218 | self._compare_error(id_, expected, given=response.body) |
|
1218 | self._compare_error(id_, expected, given=response.body) | |
1219 |
|
1219 | |||
1220 | @parameterized.expand([('none', 'repository.none'), |
|
1220 | @parameterized.expand([('none', 'repository.none'), | |
1221 | ('read', 'repository.read'), |
|
1221 | ('read', 'repository.read'), | |
1222 | ('write', 'repository.write'), |
|
1222 | ('write', 'repository.write'), | |
1223 | ('admin', 'repository.admin')]) |
|
1223 | ('admin', 'repository.admin')]) | |
1224 | def test_api_grant_users_group_permission(self, name, perm): |
|
1224 | def test_api_grant_users_group_permission(self, name, perm): | |
1225 | id_, params = _build_data(self.apikey, 'grant_users_group_permission', |
|
1225 | id_, params = _build_data(self.apikey, 'grant_users_group_permission', | |
1226 | repoid=self.REPO, |
|
1226 | repoid=self.REPO, | |
1227 | usersgroupid=TEST_USERS_GROUP, |
|
1227 | usersgroupid=TEST_USERS_GROUP, | |
1228 | perm=perm) |
|
1228 | perm=perm) | |
1229 | response = api_call(self, params) |
|
1229 | response = api_call(self, params) | |
1230 |
|
1230 | |||
1231 | ret = { |
|
1231 | ret = { | |
1232 |
'msg': 'Granted perm: `%s` for user |
|
1232 | 'msg': 'Granted perm: `%s` for user group: `%s` in repo: `%s`' % ( | |
1233 | perm, TEST_USERS_GROUP, self.REPO |
|
1233 | perm, TEST_USERS_GROUP, self.REPO | |
1234 | ), |
|
1234 | ), | |
1235 | 'success': True |
|
1235 | 'success': True | |
1236 | } |
|
1236 | } | |
1237 | expected = ret |
|
1237 | expected = ret | |
1238 | self._compare_ok(id_, expected, given=response.body) |
|
1238 | self._compare_ok(id_, expected, given=response.body) | |
1239 |
|
1239 | |||
1240 | def test_api_grant_users_group_permission_wrong_permission(self): |
|
1240 | def test_api_grant_users_group_permission_wrong_permission(self): | |
1241 | perm = 'haha.no.permission' |
|
1241 | perm = 'haha.no.permission' | |
1242 | id_, params = _build_data(self.apikey, 'grant_users_group_permission', |
|
1242 | id_, params = _build_data(self.apikey, 'grant_users_group_permission', | |
1243 | repoid=self.REPO, |
|
1243 | repoid=self.REPO, | |
1244 | usersgroupid=TEST_USERS_GROUP, |
|
1244 | usersgroupid=TEST_USERS_GROUP, | |
1245 | perm=perm) |
|
1245 | perm=perm) | |
1246 | response = api_call(self, params) |
|
1246 | response = api_call(self, params) | |
1247 |
|
1247 | |||
1248 | expected = 'permission `%s` does not exist' % perm |
|
1248 | expected = 'permission `%s` does not exist' % perm | |
1249 | self._compare_error(id_, expected, given=response.body) |
|
1249 | self._compare_error(id_, expected, given=response.body) | |
1250 |
|
1250 | |||
1251 | @mock.patch.object(RepoModel, 'grant_users_group_permission', crash) |
|
1251 | @mock.patch.object(RepoModel, 'grant_users_group_permission', crash) | |
1252 | def test_api_grant_users_group_permission_exception_when_adding(self): |
|
1252 | def test_api_grant_users_group_permission_exception_when_adding(self): | |
1253 | perm = 'repository.read' |
|
1253 | perm = 'repository.read' | |
1254 | id_, params = _build_data(self.apikey, 'grant_users_group_permission', |
|
1254 | id_, params = _build_data(self.apikey, 'grant_users_group_permission', | |
1255 | repoid=self.REPO, |
|
1255 | repoid=self.REPO, | |
1256 | usersgroupid=TEST_USERS_GROUP, |
|
1256 | usersgroupid=TEST_USERS_GROUP, | |
1257 | perm=perm) |
|
1257 | perm=perm) | |
1258 | response = api_call(self, params) |
|
1258 | response = api_call(self, params) | |
1259 |
|
1259 | |||
1260 |
expected = 'failed to edit permission for user |
|
1260 | expected = 'failed to edit permission for user group: `%s` in repo: `%s`' % ( | |
1261 | TEST_USERS_GROUP, self.REPO |
|
1261 | TEST_USERS_GROUP, self.REPO | |
1262 | ) |
|
1262 | ) | |
1263 | self._compare_error(id_, expected, given=response.body) |
|
1263 | self._compare_error(id_, expected, given=response.body) | |
1264 |
|
1264 | |||
1265 | def test_api_revoke_users_group_permission(self): |
|
1265 | def test_api_revoke_users_group_permission(self): | |
1266 | RepoModel().grant_users_group_permission(repo=self.REPO, |
|
1266 | RepoModel().grant_users_group_permission(repo=self.REPO, | |
1267 | group_name=TEST_USERS_GROUP, |
|
1267 | group_name=TEST_USERS_GROUP, | |
1268 | perm='repository.read') |
|
1268 | perm='repository.read') | |
1269 | Session().commit() |
|
1269 | Session().commit() | |
1270 | id_, params = _build_data(self.apikey, 'revoke_users_group_permission', |
|
1270 | id_, params = _build_data(self.apikey, 'revoke_users_group_permission', | |
1271 | repoid=self.REPO, |
|
1271 | repoid=self.REPO, | |
1272 | usersgroupid=TEST_USERS_GROUP,) |
|
1272 | usersgroupid=TEST_USERS_GROUP,) | |
1273 | response = api_call(self, params) |
|
1273 | response = api_call(self, params) | |
1274 |
|
1274 | |||
1275 | expected = { |
|
1275 | expected = { | |
1276 |
'msg': 'Revoked perm for user |
|
1276 | 'msg': 'Revoked perm for user group: `%s` in repo: `%s`' % ( | |
1277 | TEST_USERS_GROUP, self.REPO |
|
1277 | TEST_USERS_GROUP, self.REPO | |
1278 | ), |
|
1278 | ), | |
1279 | 'success': True |
|
1279 | 'success': True | |
1280 | } |
|
1280 | } | |
1281 | self._compare_ok(id_, expected, given=response.body) |
|
1281 | self._compare_ok(id_, expected, given=response.body) | |
1282 |
|
1282 | |||
1283 | @mock.patch.object(RepoModel, 'revoke_users_group_permission', crash) |
|
1283 | @mock.patch.object(RepoModel, 'revoke_users_group_permission', crash) | |
1284 | def test_api_revoke_users_group_permission_exception_when_adding(self): |
|
1284 | def test_api_revoke_users_group_permission_exception_when_adding(self): | |
1285 |
|
1285 | |||
1286 | id_, params = _build_data(self.apikey, 'revoke_users_group_permission', |
|
1286 | id_, params = _build_data(self.apikey, 'revoke_users_group_permission', | |
1287 | repoid=self.REPO, |
|
1287 | repoid=self.REPO, | |
1288 | usersgroupid=TEST_USERS_GROUP,) |
|
1288 | usersgroupid=TEST_USERS_GROUP,) | |
1289 | response = api_call(self, params) |
|
1289 | response = api_call(self, params) | |
1290 |
|
1290 | |||
1291 |
expected = 'failed to edit permission for user |
|
1291 | expected = 'failed to edit permission for user group: `%s` in repo: `%s`' % ( | |
1292 | TEST_USERS_GROUP, self.REPO |
|
1292 | TEST_USERS_GROUP, self.REPO | |
1293 | ) |
|
1293 | ) | |
1294 | self._compare_error(id_, expected, given=response.body) |
|
1294 | self._compare_error(id_, expected, given=response.body) |
@@ -1,224 +1,224 b'' | |||||
1 | from rhodecode.tests import * |
|
1 | from rhodecode.tests import * | |
2 | from rhodecode.model.db import UsersGroup, UsersGroupToPerm, Permission |
|
2 | from rhodecode.model.db import UsersGroup, UsersGroupToPerm, Permission | |
3 |
|
3 | |||
4 | TEST_USERS_GROUP = 'admins_test' |
|
4 | TEST_USERS_GROUP = 'admins_test' | |
5 |
|
5 | |||
6 |
|
6 | |||
7 | class TestAdminUsersGroupsController(TestController): |
|
7 | class TestAdminUsersGroupsController(TestController): | |
8 |
|
8 | |||
9 | def test_index(self): |
|
9 | def test_index(self): | |
10 | response = self.app.get(url('users_groups')) |
|
10 | response = self.app.get(url('users_groups')) | |
11 | # Test response... |
|
11 | # Test response... | |
12 |
|
12 | |||
13 | def test_index_as_xml(self): |
|
13 | def test_index_as_xml(self): | |
14 | response = self.app.get(url('formatted_users_groups', format='xml')) |
|
14 | response = self.app.get(url('formatted_users_groups', format='xml')) | |
15 |
|
15 | |||
16 | def test_create(self): |
|
16 | def test_create(self): | |
17 | self.log_user() |
|
17 | self.log_user() | |
18 | users_group_name = TEST_USERS_GROUP |
|
18 | users_group_name = TEST_USERS_GROUP | |
19 | response = self.app.post(url('users_groups'), |
|
19 | response = self.app.post(url('users_groups'), | |
20 | {'users_group_name': users_group_name, |
|
20 | {'users_group_name': users_group_name, | |
21 | 'active':True}) |
|
21 | 'active':True}) | |
22 | response.follow() |
|
22 | response.follow() | |
23 |
|
23 | |||
24 | self.checkSessionFlash(response, |
|
24 | self.checkSessionFlash(response, | |
25 |
'created user |
|
25 | 'created user group %s' % TEST_USERS_GROUP) | |
26 |
|
26 | |||
27 | def test_new(self): |
|
27 | def test_new(self): | |
28 | response = self.app.get(url('new_users_group')) |
|
28 | response = self.app.get(url('new_users_group')) | |
29 |
|
29 | |||
30 | def test_new_as_xml(self): |
|
30 | def test_new_as_xml(self): | |
31 | response = self.app.get(url('formatted_new_users_group', format='xml')) |
|
31 | response = self.app.get(url('formatted_new_users_group', format='xml')) | |
32 |
|
32 | |||
33 | def test_update(self): |
|
33 | def test_update(self): | |
34 | response = self.app.put(url('users_group', id=1)) |
|
34 | response = self.app.put(url('users_group', id=1)) | |
35 |
|
35 | |||
36 | def test_update_browser_fakeout(self): |
|
36 | def test_update_browser_fakeout(self): | |
37 | response = self.app.post(url('users_group', id=1), |
|
37 | response = self.app.post(url('users_group', id=1), | |
38 | params=dict(_method='put')) |
|
38 | params=dict(_method='put')) | |
39 |
|
39 | |||
40 | def test_delete(self): |
|
40 | def test_delete(self): | |
41 | self.log_user() |
|
41 | self.log_user() | |
42 | users_group_name = TEST_USERS_GROUP + 'another' |
|
42 | users_group_name = TEST_USERS_GROUP + 'another' | |
43 | response = self.app.post(url('users_groups'), |
|
43 | response = self.app.post(url('users_groups'), | |
44 | {'users_group_name':users_group_name, |
|
44 | {'users_group_name':users_group_name, | |
45 | 'active':True}) |
|
45 | 'active':True}) | |
46 | response.follow() |
|
46 | response.follow() | |
47 |
|
47 | |||
48 | self.checkSessionFlash(response, |
|
48 | self.checkSessionFlash(response, | |
49 |
'created user |
|
49 | 'created user group %s' % users_group_name) | |
50 |
|
50 | |||
51 | gr = self.Session.query(UsersGroup)\ |
|
51 | gr = self.Session.query(UsersGroup)\ | |
52 | .filter(UsersGroup.users_group_name == |
|
52 | .filter(UsersGroup.users_group_name == | |
53 | users_group_name).one() |
|
53 | users_group_name).one() | |
54 |
|
54 | |||
55 | response = self.app.delete(url('users_group', id=gr.users_group_id)) |
|
55 | response = self.app.delete(url('users_group', id=gr.users_group_id)) | |
56 |
|
56 | |||
57 | gr = self.Session.query(UsersGroup)\ |
|
57 | gr = self.Session.query(UsersGroup)\ | |
58 | .filter(UsersGroup.users_group_name == |
|
58 | .filter(UsersGroup.users_group_name == | |
59 | users_group_name).scalar() |
|
59 | users_group_name).scalar() | |
60 |
|
60 | |||
61 | self.assertEqual(gr, None) |
|
61 | self.assertEqual(gr, None) | |
62 |
|
62 | |||
63 | def test_enable_repository_read_on_group(self): |
|
63 | def test_enable_repository_read_on_group(self): | |
64 | self.log_user() |
|
64 | self.log_user() | |
65 | users_group_name = TEST_USERS_GROUP + 'another2' |
|
65 | users_group_name = TEST_USERS_GROUP + 'another2' | |
66 | response = self.app.post(url('users_groups'), |
|
66 | response = self.app.post(url('users_groups'), | |
67 | {'users_group_name': users_group_name, |
|
67 | {'users_group_name': users_group_name, | |
68 | 'active': True}) |
|
68 | 'active': True}) | |
69 | response.follow() |
|
69 | response.follow() | |
70 |
|
70 | |||
71 | ug = UsersGroup.get_by_group_name(users_group_name) |
|
71 | ug = UsersGroup.get_by_group_name(users_group_name) | |
72 | self.checkSessionFlash(response, |
|
72 | self.checkSessionFlash(response, | |
73 |
'created user |
|
73 | 'created user group %s' % users_group_name) | |
74 | ## ENABLE REPO CREATE ON A GROUP |
|
74 | ## ENABLE REPO CREATE ON A GROUP | |
75 | response = self.app.put(url('users_group_perm', id=ug.users_group_id), |
|
75 | response = self.app.put(url('users_group_perm', id=ug.users_group_id), | |
76 | {'create_repo_perm': True}) |
|
76 | {'create_repo_perm': True}) | |
77 |
|
77 | |||
78 | response.follow() |
|
78 | response.follow() | |
79 | ug = UsersGroup.get_by_group_name(users_group_name) |
|
79 | ug = UsersGroup.get_by_group_name(users_group_name) | |
80 | p = Permission.get_by_key('hg.create.repository') |
|
80 | p = Permission.get_by_key('hg.create.repository') | |
81 | p2 = Permission.get_by_key('hg.fork.none') |
|
81 | p2 = Permission.get_by_key('hg.fork.none') | |
82 | # check if user has this perms, they should be here since |
|
82 | # check if user has this perms, they should be here since | |
83 | # defaults are on |
|
83 | # defaults are on | |
84 | perms = UsersGroupToPerm.query()\ |
|
84 | perms = UsersGroupToPerm.query()\ | |
85 | .filter(UsersGroupToPerm.users_group == ug).all() |
|
85 | .filter(UsersGroupToPerm.users_group == ug).all() | |
86 |
|
86 | |||
87 | self.assertEqual( |
|
87 | self.assertEqual( | |
88 | [[x.users_group_id, x.permission_id, ] for x in perms], |
|
88 | [[x.users_group_id, x.permission_id, ] for x in perms], | |
89 | [[ug.users_group_id, p.permission_id], |
|
89 | [[ug.users_group_id, p.permission_id], | |
90 | [ug.users_group_id, p2.permission_id]] |
|
90 | [ug.users_group_id, p2.permission_id]] | |
91 | ) |
|
91 | ) | |
92 |
|
92 | |||
93 | ## DISABLE REPO CREATE ON A GROUP |
|
93 | ## DISABLE REPO CREATE ON A GROUP | |
94 | response = self.app.put(url('users_group_perm', id=ug.users_group_id), |
|
94 | response = self.app.put(url('users_group_perm', id=ug.users_group_id), | |
95 | {}) |
|
95 | {}) | |
96 |
|
96 | |||
97 | response.follow() |
|
97 | response.follow() | |
98 | ug = UsersGroup.get_by_group_name(users_group_name) |
|
98 | ug = UsersGroup.get_by_group_name(users_group_name) | |
99 | p = Permission.get_by_key('hg.create.none') |
|
99 | p = Permission.get_by_key('hg.create.none') | |
100 | p2 = Permission.get_by_key('hg.fork.none') |
|
100 | p2 = Permission.get_by_key('hg.fork.none') | |
101 | # check if user has this perms, they should be here since |
|
101 | # check if user has this perms, they should be here since | |
102 | # defaults are on |
|
102 | # defaults are on | |
103 | perms = UsersGroupToPerm.query()\ |
|
103 | perms = UsersGroupToPerm.query()\ | |
104 | .filter(UsersGroupToPerm.users_group == ug).all() |
|
104 | .filter(UsersGroupToPerm.users_group == ug).all() | |
105 |
|
105 | |||
106 | self.assertEqual( |
|
106 | self.assertEqual( | |
107 | sorted([[x.users_group_id, x.permission_id, ] for x in perms]), |
|
107 | sorted([[x.users_group_id, x.permission_id, ] for x in perms]), | |
108 | sorted([[ug.users_group_id, p.permission_id], |
|
108 | sorted([[ug.users_group_id, p.permission_id], | |
109 | [ug.users_group_id, p2.permission_id]]) |
|
109 | [ug.users_group_id, p2.permission_id]]) | |
110 | ) |
|
110 | ) | |
111 |
|
111 | |||
112 | # DELETE ! |
|
112 | # DELETE ! | |
113 | ug = UsersGroup.get_by_group_name(users_group_name) |
|
113 | ug = UsersGroup.get_by_group_name(users_group_name) | |
114 | ugid = ug.users_group_id |
|
114 | ugid = ug.users_group_id | |
115 | response = self.app.delete(url('users_group', id=ug.users_group_id)) |
|
115 | response = self.app.delete(url('users_group', id=ug.users_group_id)) | |
116 | response = response.follow() |
|
116 | response = response.follow() | |
117 | gr = self.Session.query(UsersGroup)\ |
|
117 | gr = self.Session.query(UsersGroup)\ | |
118 | .filter(UsersGroup.users_group_name == |
|
118 | .filter(UsersGroup.users_group_name == | |
119 | users_group_name).scalar() |
|
119 | users_group_name).scalar() | |
120 |
|
120 | |||
121 | self.assertEqual(gr, None) |
|
121 | self.assertEqual(gr, None) | |
122 | p = Permission.get_by_key('hg.create.repository') |
|
122 | p = Permission.get_by_key('hg.create.repository') | |
123 | perms = UsersGroupToPerm.query()\ |
|
123 | perms = UsersGroupToPerm.query()\ | |
124 | .filter(UsersGroupToPerm.users_group_id == ugid).all() |
|
124 | .filter(UsersGroupToPerm.users_group_id == ugid).all() | |
125 | perms = [[x.users_group_id, |
|
125 | perms = [[x.users_group_id, | |
126 | x.permission_id, ] for x in perms] |
|
126 | x.permission_id, ] for x in perms] | |
127 | self.assertEqual( |
|
127 | self.assertEqual( | |
128 | perms, |
|
128 | perms, | |
129 | [] |
|
129 | [] | |
130 | ) |
|
130 | ) | |
131 |
|
131 | |||
132 | def test_enable_repository_fork_on_group(self): |
|
132 | def test_enable_repository_fork_on_group(self): | |
133 | self.log_user() |
|
133 | self.log_user() | |
134 | users_group_name = TEST_USERS_GROUP + 'another2' |
|
134 | users_group_name = TEST_USERS_GROUP + 'another2' | |
135 | response = self.app.post(url('users_groups'), |
|
135 | response = self.app.post(url('users_groups'), | |
136 | {'users_group_name': users_group_name, |
|
136 | {'users_group_name': users_group_name, | |
137 | 'active': True}) |
|
137 | 'active': True}) | |
138 | response.follow() |
|
138 | response.follow() | |
139 |
|
139 | |||
140 | ug = UsersGroup.get_by_group_name(users_group_name) |
|
140 | ug = UsersGroup.get_by_group_name(users_group_name) | |
141 | self.checkSessionFlash(response, |
|
141 | self.checkSessionFlash(response, | |
142 |
'created user |
|
142 | 'created user group %s' % users_group_name) | |
143 | ## ENABLE REPO CREATE ON A GROUP |
|
143 | ## ENABLE REPO CREATE ON A GROUP | |
144 | response = self.app.put(url('users_group_perm', id=ug.users_group_id), |
|
144 | response = self.app.put(url('users_group_perm', id=ug.users_group_id), | |
145 | {'fork_repo_perm': True}) |
|
145 | {'fork_repo_perm': True}) | |
146 |
|
146 | |||
147 | response.follow() |
|
147 | response.follow() | |
148 | ug = UsersGroup.get_by_group_name(users_group_name) |
|
148 | ug = UsersGroup.get_by_group_name(users_group_name) | |
149 | p = Permission.get_by_key('hg.create.none') |
|
149 | p = Permission.get_by_key('hg.create.none') | |
150 | p2 = Permission.get_by_key('hg.fork.repository') |
|
150 | p2 = Permission.get_by_key('hg.fork.repository') | |
151 | # check if user has this perms, they should be here since |
|
151 | # check if user has this perms, they should be here since | |
152 | # defaults are on |
|
152 | # defaults are on | |
153 | perms = UsersGroupToPerm.query()\ |
|
153 | perms = UsersGroupToPerm.query()\ | |
154 | .filter(UsersGroupToPerm.users_group == ug).all() |
|
154 | .filter(UsersGroupToPerm.users_group == ug).all() | |
155 |
|
155 | |||
156 | self.assertEqual( |
|
156 | self.assertEqual( | |
157 | [[x.users_group_id, x.permission_id, ] for x in perms], |
|
157 | [[x.users_group_id, x.permission_id, ] for x in perms], | |
158 | [[ug.users_group_id, p.permission_id], |
|
158 | [[ug.users_group_id, p.permission_id], | |
159 | [ug.users_group_id, p2.permission_id]] |
|
159 | [ug.users_group_id, p2.permission_id]] | |
160 | ) |
|
160 | ) | |
161 |
|
161 | |||
162 | ## DISABLE REPO CREATE ON A GROUP |
|
162 | ## DISABLE REPO CREATE ON A GROUP | |
163 | response = self.app.put(url('users_group_perm', id=ug.users_group_id), |
|
163 | response = self.app.put(url('users_group_perm', id=ug.users_group_id), | |
164 | {}) |
|
164 | {}) | |
165 |
|
165 | |||
166 | response.follow() |
|
166 | response.follow() | |
167 | ug = UsersGroup.get_by_group_name(users_group_name) |
|
167 | ug = UsersGroup.get_by_group_name(users_group_name) | |
168 | p = Permission.get_by_key('hg.create.none') |
|
168 | p = Permission.get_by_key('hg.create.none') | |
169 | p2 = Permission.get_by_key('hg.fork.none') |
|
169 | p2 = Permission.get_by_key('hg.fork.none') | |
170 | # check if user has this perms, they should be here since |
|
170 | # check if user has this perms, they should be here since | |
171 | # defaults are on |
|
171 | # defaults are on | |
172 | perms = UsersGroupToPerm.query()\ |
|
172 | perms = UsersGroupToPerm.query()\ | |
173 | .filter(UsersGroupToPerm.users_group == ug).all() |
|
173 | .filter(UsersGroupToPerm.users_group == ug).all() | |
174 |
|
174 | |||
175 | self.assertEqual( |
|
175 | self.assertEqual( | |
176 | [[x.users_group_id, x.permission_id, ] for x in perms], |
|
176 | [[x.users_group_id, x.permission_id, ] for x in perms], | |
177 | [[ug.users_group_id, p.permission_id], |
|
177 | [[ug.users_group_id, p.permission_id], | |
178 | [ug.users_group_id, p2.permission_id]] |
|
178 | [ug.users_group_id, p2.permission_id]] | |
179 | ) |
|
179 | ) | |
180 |
|
180 | |||
181 | # DELETE ! |
|
181 | # DELETE ! | |
182 | ug = UsersGroup.get_by_group_name(users_group_name) |
|
182 | ug = UsersGroup.get_by_group_name(users_group_name) | |
183 | ugid = ug.users_group_id |
|
183 | ugid = ug.users_group_id | |
184 | response = self.app.delete(url('users_group', id=ug.users_group_id)) |
|
184 | response = self.app.delete(url('users_group', id=ug.users_group_id)) | |
185 | response = response.follow() |
|
185 | response = response.follow() | |
186 | gr = self.Session.query(UsersGroup)\ |
|
186 | gr = self.Session.query(UsersGroup)\ | |
187 | .filter(UsersGroup.users_group_name == |
|
187 | .filter(UsersGroup.users_group_name == | |
188 | users_group_name).scalar() |
|
188 | users_group_name).scalar() | |
189 |
|
189 | |||
190 | self.assertEqual(gr, None) |
|
190 | self.assertEqual(gr, None) | |
191 | p = Permission.get_by_key('hg.fork.repository') |
|
191 | p = Permission.get_by_key('hg.fork.repository') | |
192 | perms = UsersGroupToPerm.query()\ |
|
192 | perms = UsersGroupToPerm.query()\ | |
193 | .filter(UsersGroupToPerm.users_group_id == ugid).all() |
|
193 | .filter(UsersGroupToPerm.users_group_id == ugid).all() | |
194 | perms = [[x.users_group_id, |
|
194 | perms = [[x.users_group_id, | |
195 | x.permission_id, ] for x in perms] |
|
195 | x.permission_id, ] for x in perms] | |
196 | self.assertEqual( |
|
196 | self.assertEqual( | |
197 | perms, |
|
197 | perms, | |
198 | [] |
|
198 | [] | |
199 | ) |
|
199 | ) | |
200 |
|
200 | |||
201 | def test_delete_browser_fakeout(self): |
|
201 | def test_delete_browser_fakeout(self): | |
202 | response = self.app.post(url('users_group', id=1), |
|
202 | response = self.app.post(url('users_group', id=1), | |
203 | params=dict(_method='delete')) |
|
203 | params=dict(_method='delete')) | |
204 |
|
204 | |||
205 | def test_show(self): |
|
205 | def test_show(self): | |
206 | response = self.app.get(url('users_group', id=1)) |
|
206 | response = self.app.get(url('users_group', id=1)) | |
207 |
|
207 | |||
208 | def test_show_as_xml(self): |
|
208 | def test_show_as_xml(self): | |
209 | response = self.app.get(url('formatted_users_group', id=1, format='xml')) |
|
209 | response = self.app.get(url('formatted_users_group', id=1, format='xml')) | |
210 |
|
210 | |||
211 | def test_edit(self): |
|
211 | def test_edit(self): | |
212 | response = self.app.get(url('edit_users_group', id=1)) |
|
212 | response = self.app.get(url('edit_users_group', id=1)) | |
213 |
|
213 | |||
214 | def test_edit_as_xml(self): |
|
214 | def test_edit_as_xml(self): | |
215 | response = self.app.get(url('formatted_edit_users_group', id=1, format='xml')) |
|
215 | response = self.app.get(url('formatted_edit_users_group', id=1, format='xml')) | |
216 |
|
216 | |||
217 | def test_assign_members(self): |
|
217 | def test_assign_members(self): | |
218 | pass |
|
218 | pass | |
219 |
|
219 | |||
220 | def test_add_create_permission(self): |
|
220 | def test_add_create_permission(self): | |
221 | pass |
|
221 | pass | |
222 |
|
222 | |||
223 | def test_revoke_members(self): |
|
223 | def test_revoke_members(self): | |
224 | pass |
|
224 | pass |
@@ -1,472 +1,472 b'' | |||||
1 | import os |
|
1 | import os | |
2 | import unittest |
|
2 | import unittest | |
3 | from rhodecode.tests import * |
|
3 | from rhodecode.tests import * | |
4 | from rhodecode.tests.models.common import _make_group |
|
4 | from rhodecode.tests.models.common import _make_group | |
5 | from rhodecode.model.repos_group import ReposGroupModel |
|
5 | from rhodecode.model.repos_group import ReposGroupModel | |
6 | from rhodecode.model.repo import RepoModel |
|
6 | from rhodecode.model.repo import RepoModel | |
7 | from rhodecode.model.db import RepoGroup, User, UsersGroupRepoGroupToPerm |
|
7 | from rhodecode.model.db import RepoGroup, User, UsersGroupRepoGroupToPerm | |
8 | from rhodecode.model.user import UserModel |
|
8 | from rhodecode.model.user import UserModel | |
9 |
|
9 | |||
10 | from rhodecode.model.meta import Session |
|
10 | from rhodecode.model.meta import Session | |
11 | from rhodecode.model.users_group import UsersGroupModel |
|
11 | from rhodecode.model.users_group import UsersGroupModel | |
12 | from rhodecode.lib.auth import AuthUser |
|
12 | from rhodecode.lib.auth import AuthUser | |
13 | from rhodecode.tests.api.api_base import create_repo |
|
13 | from rhodecode.tests.api.api_base import create_repo | |
14 |
|
14 | |||
15 |
|
15 | |||
16 | class TestPermissions(unittest.TestCase): |
|
16 | class TestPermissions(unittest.TestCase): | |
17 | def __init__(self, methodName='runTest'): |
|
17 | def __init__(self, methodName='runTest'): | |
18 | super(TestPermissions, self).__init__(methodName=methodName) |
|
18 | super(TestPermissions, self).__init__(methodName=methodName) | |
19 |
|
19 | |||
20 | def setUp(self): |
|
20 | def setUp(self): | |
21 | self.u1 = UserModel().create_or_update( |
|
21 | self.u1 = UserModel().create_or_update( | |
22 | username=u'u1', password=u'qweqwe', |
|
22 | username=u'u1', password=u'qweqwe', | |
23 | email=u'u1@rhodecode.org', firstname=u'u1', lastname=u'u1' |
|
23 | email=u'u1@rhodecode.org', firstname=u'u1', lastname=u'u1' | |
24 | ) |
|
24 | ) | |
25 | self.u2 = UserModel().create_or_update( |
|
25 | self.u2 = UserModel().create_or_update( | |
26 | username=u'u2', password=u'qweqwe', |
|
26 | username=u'u2', password=u'qweqwe', | |
27 | email=u'u2@rhodecode.org', firstname=u'u2', lastname=u'u2' |
|
27 | email=u'u2@rhodecode.org', firstname=u'u2', lastname=u'u2' | |
28 | ) |
|
28 | ) | |
29 | self.u3 = UserModel().create_or_update( |
|
29 | self.u3 = UserModel().create_or_update( | |
30 | username=u'u3', password=u'qweqwe', |
|
30 | username=u'u3', password=u'qweqwe', | |
31 | email=u'u3@rhodecode.org', firstname=u'u3', lastname=u'u3' |
|
31 | email=u'u3@rhodecode.org', firstname=u'u3', lastname=u'u3' | |
32 | ) |
|
32 | ) | |
33 | self.anon = User.get_by_username('default') |
|
33 | self.anon = User.get_by_username('default') | |
34 | self.a1 = UserModel().create_or_update( |
|
34 | self.a1 = UserModel().create_or_update( | |
35 | username=u'a1', password=u'qweqwe', |
|
35 | username=u'a1', password=u'qweqwe', | |
36 | email=u'a1@rhodecode.org', firstname=u'a1', lastname=u'a1', admin=True |
|
36 | email=u'a1@rhodecode.org', firstname=u'a1', lastname=u'a1', admin=True | |
37 | ) |
|
37 | ) | |
38 | Session().commit() |
|
38 | Session().commit() | |
39 |
|
39 | |||
40 | def tearDown(self): |
|
40 | def tearDown(self): | |
41 | if hasattr(self, 'test_repo'): |
|
41 | if hasattr(self, 'test_repo'): | |
42 | RepoModel().delete(repo=self.test_repo) |
|
42 | RepoModel().delete(repo=self.test_repo) | |
43 |
|
43 | |||
44 | UserModel().delete(self.u1) |
|
44 | UserModel().delete(self.u1) | |
45 | UserModel().delete(self.u2) |
|
45 | UserModel().delete(self.u2) | |
46 | UserModel().delete(self.u3) |
|
46 | UserModel().delete(self.u3) | |
47 | UserModel().delete(self.a1) |
|
47 | UserModel().delete(self.a1) | |
48 | if hasattr(self, 'g1'): |
|
48 | if hasattr(self, 'g1'): | |
49 | ReposGroupModel().delete(self.g1.group_id) |
|
49 | ReposGroupModel().delete(self.g1.group_id) | |
50 | if hasattr(self, 'g2'): |
|
50 | if hasattr(self, 'g2'): | |
51 | ReposGroupModel().delete(self.g2.group_id) |
|
51 | ReposGroupModel().delete(self.g2.group_id) | |
52 |
|
52 | |||
53 | if hasattr(self, 'ug1'): |
|
53 | if hasattr(self, 'ug1'): | |
54 | UsersGroupModel().delete(self.ug1, force=True) |
|
54 | UsersGroupModel().delete(self.ug1, force=True) | |
55 |
|
55 | |||
56 | Session().commit() |
|
56 | Session().commit() | |
57 |
|
57 | |||
58 | def test_default_perms_set(self): |
|
58 | def test_default_perms_set(self): | |
59 | u1_auth = AuthUser(user_id=self.u1.user_id) |
|
59 | u1_auth = AuthUser(user_id=self.u1.user_id) | |
60 | perms = { |
|
60 | perms = { | |
61 | 'repositories_groups': {}, |
|
61 | 'repositories_groups': {}, | |
62 | 'global': set([u'hg.create.repository', u'repository.read', |
|
62 | 'global': set([u'hg.create.repository', u'repository.read', | |
63 | u'hg.register.manual_activate']), |
|
63 | u'hg.register.manual_activate']), | |
64 | 'repositories': {u'vcs_test_hg': u'repository.read'} |
|
64 | 'repositories': {u'vcs_test_hg': u'repository.read'} | |
65 | } |
|
65 | } | |
66 | self.assertEqual(u1_auth.permissions['repositories'][HG_REPO], |
|
66 | self.assertEqual(u1_auth.permissions['repositories'][HG_REPO], | |
67 | perms['repositories'][HG_REPO]) |
|
67 | perms['repositories'][HG_REPO]) | |
68 | new_perm = 'repository.write' |
|
68 | new_perm = 'repository.write' | |
69 | RepoModel().grant_user_permission(repo=HG_REPO, user=self.u1, |
|
69 | RepoModel().grant_user_permission(repo=HG_REPO, user=self.u1, | |
70 | perm=new_perm) |
|
70 | perm=new_perm) | |
71 | Session().commit() |
|
71 | Session().commit() | |
72 |
|
72 | |||
73 | u1_auth = AuthUser(user_id=self.u1.user_id) |
|
73 | u1_auth = AuthUser(user_id=self.u1.user_id) | |
74 | self.assertEqual(u1_auth.permissions['repositories'][HG_REPO], |
|
74 | self.assertEqual(u1_auth.permissions['repositories'][HG_REPO], | |
75 | new_perm) |
|
75 | new_perm) | |
76 |
|
76 | |||
77 | def test_default_admin_perms_set(self): |
|
77 | def test_default_admin_perms_set(self): | |
78 | a1_auth = AuthUser(user_id=self.a1.user_id) |
|
78 | a1_auth = AuthUser(user_id=self.a1.user_id) | |
79 | perms = { |
|
79 | perms = { | |
80 | 'repositories_groups': {}, |
|
80 | 'repositories_groups': {}, | |
81 | 'global': set([u'hg.admin']), |
|
81 | 'global': set([u'hg.admin']), | |
82 | 'repositories': {u'vcs_test_hg': u'repository.admin'} |
|
82 | 'repositories': {u'vcs_test_hg': u'repository.admin'} | |
83 | } |
|
83 | } | |
84 | self.assertEqual(a1_auth.permissions['repositories'][HG_REPO], |
|
84 | self.assertEqual(a1_auth.permissions['repositories'][HG_REPO], | |
85 | perms['repositories'][HG_REPO]) |
|
85 | perms['repositories'][HG_REPO]) | |
86 | new_perm = 'repository.write' |
|
86 | new_perm = 'repository.write' | |
87 | RepoModel().grant_user_permission(repo=HG_REPO, user=self.a1, |
|
87 | RepoModel().grant_user_permission(repo=HG_REPO, user=self.a1, | |
88 | perm=new_perm) |
|
88 | perm=new_perm) | |
89 | Session().commit() |
|
89 | Session().commit() | |
90 | # cannot really downgrade admins permissions !? they still get's set as |
|
90 | # cannot really downgrade admins permissions !? they still get's set as | |
91 | # admin ! |
|
91 | # admin ! | |
92 | u1_auth = AuthUser(user_id=self.a1.user_id) |
|
92 | u1_auth = AuthUser(user_id=self.a1.user_id) | |
93 | self.assertEqual(u1_auth.permissions['repositories'][HG_REPO], |
|
93 | self.assertEqual(u1_auth.permissions['repositories'][HG_REPO], | |
94 | perms['repositories'][HG_REPO]) |
|
94 | perms['repositories'][HG_REPO]) | |
95 |
|
95 | |||
96 | def test_default_group_perms(self): |
|
96 | def test_default_group_perms(self): | |
97 | self.g1 = _make_group('test1', skip_if_exists=True) |
|
97 | self.g1 = _make_group('test1', skip_if_exists=True) | |
98 | self.g2 = _make_group('test2', skip_if_exists=True) |
|
98 | self.g2 = _make_group('test2', skip_if_exists=True) | |
99 | u1_auth = AuthUser(user_id=self.u1.user_id) |
|
99 | u1_auth = AuthUser(user_id=self.u1.user_id) | |
100 | perms = { |
|
100 | perms = { | |
101 | 'repositories_groups': {u'test1': 'group.read', u'test2': 'group.read'}, |
|
101 | 'repositories_groups': {u'test1': 'group.read', u'test2': 'group.read'}, | |
102 | 'global': set([u'hg.create.repository', u'repository.read', u'hg.register.manual_activate']), |
|
102 | 'global': set([u'hg.create.repository', u'repository.read', u'hg.register.manual_activate']), | |
103 | 'repositories': {u'vcs_test_hg': u'repository.read'} |
|
103 | 'repositories': {u'vcs_test_hg': u'repository.read'} | |
104 | } |
|
104 | } | |
105 | self.assertEqual(u1_auth.permissions['repositories'][HG_REPO], |
|
105 | self.assertEqual(u1_auth.permissions['repositories'][HG_REPO], | |
106 | perms['repositories'][HG_REPO]) |
|
106 | perms['repositories'][HG_REPO]) | |
107 | self.assertEqual(u1_auth.permissions['repositories_groups'], |
|
107 | self.assertEqual(u1_auth.permissions['repositories_groups'], | |
108 | perms['repositories_groups']) |
|
108 | perms['repositories_groups']) | |
109 |
|
109 | |||
110 | def test_default_admin_group_perms(self): |
|
110 | def test_default_admin_group_perms(self): | |
111 | self.g1 = _make_group('test1', skip_if_exists=True) |
|
111 | self.g1 = _make_group('test1', skip_if_exists=True) | |
112 | self.g2 = _make_group('test2', skip_if_exists=True) |
|
112 | self.g2 = _make_group('test2', skip_if_exists=True) | |
113 | a1_auth = AuthUser(user_id=self.a1.user_id) |
|
113 | a1_auth = AuthUser(user_id=self.a1.user_id) | |
114 | perms = { |
|
114 | perms = { | |
115 | 'repositories_groups': {u'test1': 'group.admin', u'test2': 'group.admin'}, |
|
115 | 'repositories_groups': {u'test1': 'group.admin', u'test2': 'group.admin'}, | |
116 | 'global': set(['hg.admin']), |
|
116 | 'global': set(['hg.admin']), | |
117 | 'repositories': {u'vcs_test_hg': 'repository.admin'} |
|
117 | 'repositories': {u'vcs_test_hg': 'repository.admin'} | |
118 | } |
|
118 | } | |
119 |
|
119 | |||
120 | self.assertEqual(a1_auth.permissions['repositories'][HG_REPO], |
|
120 | self.assertEqual(a1_auth.permissions['repositories'][HG_REPO], | |
121 | perms['repositories'][HG_REPO]) |
|
121 | perms['repositories'][HG_REPO]) | |
122 | self.assertEqual(a1_auth.permissions['repositories_groups'], |
|
122 | self.assertEqual(a1_auth.permissions['repositories_groups'], | |
123 | perms['repositories_groups']) |
|
123 | perms['repositories_groups']) | |
124 |
|
124 | |||
125 | def test_propagated_permission_from_users_group_by_explicit_perms_exist(self): |
|
125 | def test_propagated_permission_from_users_group_by_explicit_perms_exist(self): | |
126 | # make group |
|
126 | # make group | |
127 | self.ug1 = UsersGroupModel().create('G1') |
|
127 | self.ug1 = UsersGroupModel().create('G1') | |
128 | # add user to group |
|
128 | # add user to group | |
129 |
|
129 | |||
130 | UsersGroupModel().add_user_to_group(self.ug1, self.u1) |
|
130 | UsersGroupModel().add_user_to_group(self.ug1, self.u1) | |
131 |
|
131 | |||
132 | # set permission to lower |
|
132 | # set permission to lower | |
133 | new_perm = 'repository.none' |
|
133 | new_perm = 'repository.none' | |
134 | RepoModel().grant_user_permission(repo=HG_REPO, user=self.u1, perm=new_perm) |
|
134 | RepoModel().grant_user_permission(repo=HG_REPO, user=self.u1, perm=new_perm) | |
135 | Session().commit() |
|
135 | Session().commit() | |
136 | u1_auth = AuthUser(user_id=self.u1.user_id) |
|
136 | u1_auth = AuthUser(user_id=self.u1.user_id) | |
137 | self.assertEqual(u1_auth.permissions['repositories'][HG_REPO], |
|
137 | self.assertEqual(u1_auth.permissions['repositories'][HG_REPO], | |
138 | new_perm) |
|
138 | new_perm) | |
139 |
|
139 | |||
140 | # grant perm for group this should not override permission from user |
|
140 | # grant perm for group this should not override permission from user | |
141 | # since it has explicitly set |
|
141 | # since it has explicitly set | |
142 | new_perm_gr = 'repository.write' |
|
142 | new_perm_gr = 'repository.write' | |
143 | RepoModel().grant_users_group_permission(repo=HG_REPO, |
|
143 | RepoModel().grant_users_group_permission(repo=HG_REPO, | |
144 | group_name=self.ug1, |
|
144 | group_name=self.ug1, | |
145 | perm=new_perm_gr) |
|
145 | perm=new_perm_gr) | |
146 | # check perms |
|
146 | # check perms | |
147 | u1_auth = AuthUser(user_id=self.u1.user_id) |
|
147 | u1_auth = AuthUser(user_id=self.u1.user_id) | |
148 | perms = { |
|
148 | perms = { | |
149 | 'repositories_groups': {}, |
|
149 | 'repositories_groups': {}, | |
150 | 'global': set([u'hg.create.repository', u'repository.read', |
|
150 | 'global': set([u'hg.create.repository', u'repository.read', | |
151 | u'hg.register.manual_activate']), |
|
151 | u'hg.register.manual_activate']), | |
152 | 'repositories': {u'vcs_test_hg': u'repository.read'} |
|
152 | 'repositories': {u'vcs_test_hg': u'repository.read'} | |
153 | } |
|
153 | } | |
154 | self.assertEqual(u1_auth.permissions['repositories'][HG_REPO], |
|
154 | self.assertEqual(u1_auth.permissions['repositories'][HG_REPO], | |
155 | new_perm) |
|
155 | new_perm) | |
156 | self.assertEqual(u1_auth.permissions['repositories_groups'], |
|
156 | self.assertEqual(u1_auth.permissions['repositories_groups'], | |
157 | perms['repositories_groups']) |
|
157 | perms['repositories_groups']) | |
158 |
|
158 | |||
159 | def test_propagated_permission_from_users_group(self): |
|
159 | def test_propagated_permission_from_users_group(self): | |
160 | # make group |
|
160 | # make group | |
161 | self.ug1 = UsersGroupModel().create('G1') |
|
161 | self.ug1 = UsersGroupModel().create('G1') | |
162 | # add user to group |
|
162 | # add user to group | |
163 |
|
163 | |||
164 | UsersGroupModel().add_user_to_group(self.ug1, self.u3) |
|
164 | UsersGroupModel().add_user_to_group(self.ug1, self.u3) | |
165 |
|
165 | |||
166 | # grant perm for group this should override default permission from user |
|
166 | # grant perm for group this should override default permission from user | |
167 | new_perm_gr = 'repository.write' |
|
167 | new_perm_gr = 'repository.write' | |
168 | RepoModel().grant_users_group_permission(repo=HG_REPO, |
|
168 | RepoModel().grant_users_group_permission(repo=HG_REPO, | |
169 | group_name=self.ug1, |
|
169 | group_name=self.ug1, | |
170 | perm=new_perm_gr) |
|
170 | perm=new_perm_gr) | |
171 | # check perms |
|
171 | # check perms | |
172 | u3_auth = AuthUser(user_id=self.u3.user_id) |
|
172 | u3_auth = AuthUser(user_id=self.u3.user_id) | |
173 | perms = { |
|
173 | perms = { | |
174 | 'repositories_groups': {}, |
|
174 | 'repositories_groups': {}, | |
175 | 'global': set([u'hg.create.repository', u'repository.read', |
|
175 | 'global': set([u'hg.create.repository', u'repository.read', | |
176 | u'hg.register.manual_activate']), |
|
176 | u'hg.register.manual_activate']), | |
177 | 'repositories': {u'vcs_test_hg': u'repository.read'} |
|
177 | 'repositories': {u'vcs_test_hg': u'repository.read'} | |
178 | } |
|
178 | } | |
179 | self.assertEqual(u3_auth.permissions['repositories'][HG_REPO], |
|
179 | self.assertEqual(u3_auth.permissions['repositories'][HG_REPO], | |
180 | new_perm_gr) |
|
180 | new_perm_gr) | |
181 | self.assertEqual(u3_auth.permissions['repositories_groups'], |
|
181 | self.assertEqual(u3_auth.permissions['repositories_groups'], | |
182 | perms['repositories_groups']) |
|
182 | perms['repositories_groups']) | |
183 |
|
183 | |||
184 | def test_propagated_permission_from_users_group_lower_weight(self): |
|
184 | def test_propagated_permission_from_users_group_lower_weight(self): | |
185 | # make group |
|
185 | # make group | |
186 | self.ug1 = UsersGroupModel().create('G1') |
|
186 | self.ug1 = UsersGroupModel().create('G1') | |
187 | # add user to group |
|
187 | # add user to group | |
188 | UsersGroupModel().add_user_to_group(self.ug1, self.u1) |
|
188 | UsersGroupModel().add_user_to_group(self.ug1, self.u1) | |
189 |
|
189 | |||
190 | # set permission to lower |
|
190 | # set permission to lower | |
191 | new_perm_h = 'repository.write' |
|
191 | new_perm_h = 'repository.write' | |
192 | RepoModel().grant_user_permission(repo=HG_REPO, user=self.u1, |
|
192 | RepoModel().grant_user_permission(repo=HG_REPO, user=self.u1, | |
193 | perm=new_perm_h) |
|
193 | perm=new_perm_h) | |
194 | Session().commit() |
|
194 | Session().commit() | |
195 | u1_auth = AuthUser(user_id=self.u1.user_id) |
|
195 | u1_auth = AuthUser(user_id=self.u1.user_id) | |
196 | self.assertEqual(u1_auth.permissions['repositories'][HG_REPO], |
|
196 | self.assertEqual(u1_auth.permissions['repositories'][HG_REPO], | |
197 | new_perm_h) |
|
197 | new_perm_h) | |
198 |
|
198 | |||
199 | # grant perm for group this should NOT override permission from user |
|
199 | # grant perm for group this should NOT override permission from user | |
200 | # since it's lower than granted |
|
200 | # since it's lower than granted | |
201 | new_perm_l = 'repository.read' |
|
201 | new_perm_l = 'repository.read' | |
202 | RepoModel().grant_users_group_permission(repo=HG_REPO, |
|
202 | RepoModel().grant_users_group_permission(repo=HG_REPO, | |
203 | group_name=self.ug1, |
|
203 | group_name=self.ug1, | |
204 | perm=new_perm_l) |
|
204 | perm=new_perm_l) | |
205 | # check perms |
|
205 | # check perms | |
206 | u1_auth = AuthUser(user_id=self.u1.user_id) |
|
206 | u1_auth = AuthUser(user_id=self.u1.user_id) | |
207 | perms = { |
|
207 | perms = { | |
208 | 'repositories_groups': {}, |
|
208 | 'repositories_groups': {}, | |
209 | 'global': set([u'hg.create.repository', u'repository.read', |
|
209 | 'global': set([u'hg.create.repository', u'repository.read', | |
210 | u'hg.register.manual_activate']), |
|
210 | u'hg.register.manual_activate']), | |
211 | 'repositories': {u'vcs_test_hg': u'repository.write'} |
|
211 | 'repositories': {u'vcs_test_hg': u'repository.write'} | |
212 | } |
|
212 | } | |
213 | self.assertEqual(u1_auth.permissions['repositories'][HG_REPO], |
|
213 | self.assertEqual(u1_auth.permissions['repositories'][HG_REPO], | |
214 | new_perm_h) |
|
214 | new_perm_h) | |
215 | self.assertEqual(u1_auth.permissions['repositories_groups'], |
|
215 | self.assertEqual(u1_auth.permissions['repositories_groups'], | |
216 | perms['repositories_groups']) |
|
216 | perms['repositories_groups']) | |
217 |
|
217 | |||
218 | def test_repo_in_group_permissions(self): |
|
218 | def test_repo_in_group_permissions(self): | |
219 | self.g1 = _make_group('group1', skip_if_exists=True) |
|
219 | self.g1 = _make_group('group1', skip_if_exists=True) | |
220 | self.g2 = _make_group('group2', skip_if_exists=True) |
|
220 | self.g2 = _make_group('group2', skip_if_exists=True) | |
221 | Session().commit() |
|
221 | Session().commit() | |
222 | # both perms should be read ! |
|
222 | # both perms should be read ! | |
223 | u1_auth = AuthUser(user_id=self.u1.user_id) |
|
223 | u1_auth = AuthUser(user_id=self.u1.user_id) | |
224 | self.assertEqual(u1_auth.permissions['repositories_groups'], |
|
224 | self.assertEqual(u1_auth.permissions['repositories_groups'], | |
225 | {u'group1': u'group.read', u'group2': u'group.read'}) |
|
225 | {u'group1': u'group.read', u'group2': u'group.read'}) | |
226 |
|
226 | |||
227 | a1_auth = AuthUser(user_id=self.anon.user_id) |
|
227 | a1_auth = AuthUser(user_id=self.anon.user_id) | |
228 | self.assertEqual(a1_auth.permissions['repositories_groups'], |
|
228 | self.assertEqual(a1_auth.permissions['repositories_groups'], | |
229 | {u'group1': u'group.read', u'group2': u'group.read'}) |
|
229 | {u'group1': u'group.read', u'group2': u'group.read'}) | |
230 |
|
230 | |||
231 | #Change perms to none for both groups |
|
231 | #Change perms to none for both groups | |
232 | ReposGroupModel().grant_user_permission(repos_group=self.g1, |
|
232 | ReposGroupModel().grant_user_permission(repos_group=self.g1, | |
233 | user=self.anon, |
|
233 | user=self.anon, | |
234 | perm='group.none') |
|
234 | perm='group.none') | |
235 | ReposGroupModel().grant_user_permission(repos_group=self.g2, |
|
235 | ReposGroupModel().grant_user_permission(repos_group=self.g2, | |
236 | user=self.anon, |
|
236 | user=self.anon, | |
237 | perm='group.none') |
|
237 | perm='group.none') | |
238 |
|
238 | |||
239 | u1_auth = AuthUser(user_id=self.u1.user_id) |
|
239 | u1_auth = AuthUser(user_id=self.u1.user_id) | |
240 | self.assertEqual(u1_auth.permissions['repositories_groups'], |
|
240 | self.assertEqual(u1_auth.permissions['repositories_groups'], | |
241 | {u'group1': u'group.none', u'group2': u'group.none'}) |
|
241 | {u'group1': u'group.none', u'group2': u'group.none'}) | |
242 |
|
242 | |||
243 | a1_auth = AuthUser(user_id=self.anon.user_id) |
|
243 | a1_auth = AuthUser(user_id=self.anon.user_id) | |
244 | self.assertEqual(a1_auth.permissions['repositories_groups'], |
|
244 | self.assertEqual(a1_auth.permissions['repositories_groups'], | |
245 | {u'group1': u'group.none', u'group2': u'group.none'}) |
|
245 | {u'group1': u'group.none', u'group2': u'group.none'}) | |
246 |
|
246 | |||
247 | # add repo to group |
|
247 | # add repo to group | |
248 | name = RepoGroup.url_sep().join([self.g1.group_name, 'test_perm']) |
|
248 | name = RepoGroup.url_sep().join([self.g1.group_name, 'test_perm']) | |
249 | self.test_repo = RepoModel().create_repo( |
|
249 | self.test_repo = RepoModel().create_repo( | |
250 | repo_name=name, |
|
250 | repo_name=name, | |
251 | repo_type='hg', |
|
251 | repo_type='hg', | |
252 | description='', |
|
252 | description='', | |
253 | repos_group=self.g1, |
|
253 | repos_group=self.g1, | |
254 | owner=self.u1, |
|
254 | owner=self.u1, | |
255 | ) |
|
255 | ) | |
256 | Session().commit() |
|
256 | Session().commit() | |
257 |
|
257 | |||
258 | u1_auth = AuthUser(user_id=self.u1.user_id) |
|
258 | u1_auth = AuthUser(user_id=self.u1.user_id) | |
259 | self.assertEqual(u1_auth.permissions['repositories_groups'], |
|
259 | self.assertEqual(u1_auth.permissions['repositories_groups'], | |
260 | {u'group1': u'group.none', u'group2': u'group.none'}) |
|
260 | {u'group1': u'group.none', u'group2': u'group.none'}) | |
261 |
|
261 | |||
262 | a1_auth = AuthUser(user_id=self.anon.user_id) |
|
262 | a1_auth = AuthUser(user_id=self.anon.user_id) | |
263 | self.assertEqual(a1_auth.permissions['repositories_groups'], |
|
263 | self.assertEqual(a1_auth.permissions['repositories_groups'], | |
264 | {u'group1': u'group.none', u'group2': u'group.none'}) |
|
264 | {u'group1': u'group.none', u'group2': u'group.none'}) | |
265 |
|
265 | |||
266 | #grant permission for u2 ! |
|
266 | #grant permission for u2 ! | |
267 | ReposGroupModel().grant_user_permission(repos_group=self.g1, |
|
267 | ReposGroupModel().grant_user_permission(repos_group=self.g1, | |
268 | user=self.u2, |
|
268 | user=self.u2, | |
269 | perm='group.read') |
|
269 | perm='group.read') | |
270 | ReposGroupModel().grant_user_permission(repos_group=self.g2, |
|
270 | ReposGroupModel().grant_user_permission(repos_group=self.g2, | |
271 | user=self.u2, |
|
271 | user=self.u2, | |
272 | perm='group.read') |
|
272 | perm='group.read') | |
273 | Session().commit() |
|
273 | Session().commit() | |
274 | self.assertNotEqual(self.u1, self.u2) |
|
274 | self.assertNotEqual(self.u1, self.u2) | |
275 | #u1 and anon should have not change perms while u2 should ! |
|
275 | #u1 and anon should have not change perms while u2 should ! | |
276 | u1_auth = AuthUser(user_id=self.u1.user_id) |
|
276 | u1_auth = AuthUser(user_id=self.u1.user_id) | |
277 | self.assertEqual(u1_auth.permissions['repositories_groups'], |
|
277 | self.assertEqual(u1_auth.permissions['repositories_groups'], | |
278 | {u'group1': u'group.none', u'group2': u'group.none'}) |
|
278 | {u'group1': u'group.none', u'group2': u'group.none'}) | |
279 |
|
279 | |||
280 | u2_auth = AuthUser(user_id=self.u2.user_id) |
|
280 | u2_auth = AuthUser(user_id=self.u2.user_id) | |
281 | self.assertEqual(u2_auth.permissions['repositories_groups'], |
|
281 | self.assertEqual(u2_auth.permissions['repositories_groups'], | |
282 | {u'group1': u'group.read', u'group2': u'group.read'}) |
|
282 | {u'group1': u'group.read', u'group2': u'group.read'}) | |
283 |
|
283 | |||
284 | a1_auth = AuthUser(user_id=self.anon.user_id) |
|
284 | a1_auth = AuthUser(user_id=self.anon.user_id) | |
285 | self.assertEqual(a1_auth.permissions['repositories_groups'], |
|
285 | self.assertEqual(a1_auth.permissions['repositories_groups'], | |
286 | {u'group1': u'group.none', u'group2': u'group.none'}) |
|
286 | {u'group1': u'group.none', u'group2': u'group.none'}) | |
287 |
|
287 | |||
288 | def test_repo_group_user_as_user_group_member(self): |
|
288 | def test_repo_group_user_as_user_group_member(self): | |
289 | # create Group1 |
|
289 | # create Group1 | |
290 | self.g1 = _make_group('group1', skip_if_exists=True) |
|
290 | self.g1 = _make_group('group1', skip_if_exists=True) | |
291 | Session().commit() |
|
291 | Session().commit() | |
292 | a1_auth = AuthUser(user_id=self.anon.user_id) |
|
292 | a1_auth = AuthUser(user_id=self.anon.user_id) | |
293 |
|
293 | |||
294 | self.assertEqual(a1_auth.permissions['repositories_groups'], |
|
294 | self.assertEqual(a1_auth.permissions['repositories_groups'], | |
295 | {u'group1': u'group.read'}) |
|
295 | {u'group1': u'group.read'}) | |
296 |
|
296 | |||
297 | # set default permission to none |
|
297 | # set default permission to none | |
298 | ReposGroupModel().grant_user_permission(repos_group=self.g1, |
|
298 | ReposGroupModel().grant_user_permission(repos_group=self.g1, | |
299 | user=self.anon, |
|
299 | user=self.anon, | |
300 | perm='group.none') |
|
300 | perm='group.none') | |
301 | # make group |
|
301 | # make group | |
302 | self.ug1 = UsersGroupModel().create('G1') |
|
302 | self.ug1 = UsersGroupModel().create('G1') | |
303 | # add user to group |
|
303 | # add user to group | |
304 | UsersGroupModel().add_user_to_group(self.ug1, self.u1) |
|
304 | UsersGroupModel().add_user_to_group(self.ug1, self.u1) | |
305 | Session().commit() |
|
305 | Session().commit() | |
306 |
|
306 | |||
307 | # check if user is in the group |
|
307 | # check if user is in the group | |
308 | membrs = [x.user_id for x in UsersGroupModel().get(self.ug1.users_group_id).members] |
|
308 | membrs = [x.user_id for x in UsersGroupModel().get(self.ug1.users_group_id).members] | |
309 | self.assertEqual(membrs, [self.u1.user_id]) |
|
309 | self.assertEqual(membrs, [self.u1.user_id]) | |
310 | # add some user to that group |
|
310 | # add some user to that group | |
311 |
|
311 | |||
312 | # check his permissions |
|
312 | # check his permissions | |
313 | a1_auth = AuthUser(user_id=self.anon.user_id) |
|
313 | a1_auth = AuthUser(user_id=self.anon.user_id) | |
314 | self.assertEqual(a1_auth.permissions['repositories_groups'], |
|
314 | self.assertEqual(a1_auth.permissions['repositories_groups'], | |
315 | {u'group1': u'group.none'}) |
|
315 | {u'group1': u'group.none'}) | |
316 |
|
316 | |||
317 | u1_auth = AuthUser(user_id=self.u1.user_id) |
|
317 | u1_auth = AuthUser(user_id=self.u1.user_id) | |
318 | self.assertEqual(u1_auth.permissions['repositories_groups'], |
|
318 | self.assertEqual(u1_auth.permissions['repositories_groups'], | |
319 | {u'group1': u'group.none'}) |
|
319 | {u'group1': u'group.none'}) | |
320 |
|
320 | |||
321 | # grant ug1 read permissions for |
|
321 | # grant ug1 read permissions for | |
322 | ReposGroupModel().grant_users_group_permission(repos_group=self.g1, |
|
322 | ReposGroupModel().grant_users_group_permission(repos_group=self.g1, | |
323 | group_name=self.ug1, |
|
323 | group_name=self.ug1, | |
324 | perm='group.read') |
|
324 | perm='group.read') | |
325 | Session().commit() |
|
325 | Session().commit() | |
326 | # check if the |
|
326 | # check if the | |
327 | obj = Session().query(UsersGroupRepoGroupToPerm)\ |
|
327 | obj = Session().query(UsersGroupRepoGroupToPerm)\ | |
328 | .filter(UsersGroupRepoGroupToPerm.group == self.g1)\ |
|
328 | .filter(UsersGroupRepoGroupToPerm.group == self.g1)\ | |
329 | .filter(UsersGroupRepoGroupToPerm.users_group == self.ug1)\ |
|
329 | .filter(UsersGroupRepoGroupToPerm.users_group == self.ug1)\ | |
330 | .scalar() |
|
330 | .scalar() | |
331 | self.assertEqual(obj.permission.permission_name, 'group.read') |
|
331 | self.assertEqual(obj.permission.permission_name, 'group.read') | |
332 |
|
332 | |||
333 | a1_auth = AuthUser(user_id=self.anon.user_id) |
|
333 | a1_auth = AuthUser(user_id=self.anon.user_id) | |
334 |
|
334 | |||
335 | self.assertEqual(a1_auth.permissions['repositories_groups'], |
|
335 | self.assertEqual(a1_auth.permissions['repositories_groups'], | |
336 | {u'group1': u'group.none'}) |
|
336 | {u'group1': u'group.none'}) | |
337 |
|
337 | |||
338 | u1_auth = AuthUser(user_id=self.u1.user_id) |
|
338 | u1_auth = AuthUser(user_id=self.u1.user_id) | |
339 | self.assertEqual(u1_auth.permissions['repositories_groups'], |
|
339 | self.assertEqual(u1_auth.permissions['repositories_groups'], | |
340 | {u'group1': u'group.read'}) |
|
340 | {u'group1': u'group.read'}) | |
341 |
|
341 | |||
342 | def test_inherited_permissions_from_default_on_user_enabled(self): |
|
342 | def test_inherited_permissions_from_default_on_user_enabled(self): | |
343 | user_model = UserModel() |
|
343 | user_model = UserModel() | |
344 | # enable fork and create on default user |
|
344 | # enable fork and create on default user | |
345 | usr = 'default' |
|
345 | usr = 'default' | |
346 | user_model.revoke_perm(usr, 'hg.create.none') |
|
346 | user_model.revoke_perm(usr, 'hg.create.none') | |
347 | user_model.grant_perm(usr, 'hg.create.repository') |
|
347 | user_model.grant_perm(usr, 'hg.create.repository') | |
348 | user_model.revoke_perm(usr, 'hg.fork.none') |
|
348 | user_model.revoke_perm(usr, 'hg.fork.none') | |
349 | user_model.grant_perm(usr, 'hg.fork.repository') |
|
349 | user_model.grant_perm(usr, 'hg.fork.repository') | |
350 | # make sure inherit flag is turned on |
|
350 | # make sure inherit flag is turned on | |
351 | self.u1.inherit_default_permissions = True |
|
351 | self.u1.inherit_default_permissions = True | |
352 | Session().commit() |
|
352 | Session().commit() | |
353 | u1_auth = AuthUser(user_id=self.u1.user_id) |
|
353 | u1_auth = AuthUser(user_id=self.u1.user_id) | |
354 | # this user will have inherited permissions from default user |
|
354 | # this user will have inherited permissions from default user | |
355 | self.assertEqual(u1_auth.permissions['global'], |
|
355 | self.assertEqual(u1_auth.permissions['global'], | |
356 | set(['hg.create.repository', 'hg.fork.repository', |
|
356 | set(['hg.create.repository', 'hg.fork.repository', | |
357 | 'hg.register.manual_activate', |
|
357 | 'hg.register.manual_activate', | |
358 | 'repository.read', 'group.read'])) |
|
358 | 'repository.read', 'group.read'])) | |
359 |
|
359 | |||
360 | def test_inherited_permissions_from_default_on_user_disabled(self): |
|
360 | def test_inherited_permissions_from_default_on_user_disabled(self): | |
361 | user_model = UserModel() |
|
361 | user_model = UserModel() | |
362 | # disable fork and create on default user |
|
362 | # disable fork and create on default user | |
363 | usr = 'default' |
|
363 | usr = 'default' | |
364 | user_model.revoke_perm(usr, 'hg.create.repository') |
|
364 | user_model.revoke_perm(usr, 'hg.create.repository') | |
365 | user_model.grant_perm(usr, 'hg.create.none') |
|
365 | user_model.grant_perm(usr, 'hg.create.none') | |
366 | user_model.revoke_perm(usr, 'hg.fork.repository') |
|
366 | user_model.revoke_perm(usr, 'hg.fork.repository') | |
367 | user_model.grant_perm(usr, 'hg.fork.none') |
|
367 | user_model.grant_perm(usr, 'hg.fork.none') | |
368 | # make sure inherit flag is turned on |
|
368 | # make sure inherit flag is turned on | |
369 | self.u1.inherit_default_permissions = True |
|
369 | self.u1.inherit_default_permissions = True | |
370 | Session().commit() |
|
370 | Session().commit() | |
371 | u1_auth = AuthUser(user_id=self.u1.user_id) |
|
371 | u1_auth = AuthUser(user_id=self.u1.user_id) | |
372 | # this user will have inherited permissions from default user |
|
372 | # this user will have inherited permissions from default user | |
373 | self.assertEqual(u1_auth.permissions['global'], |
|
373 | self.assertEqual(u1_auth.permissions['global'], | |
374 | set(['hg.create.none', 'hg.fork.none', |
|
374 | set(['hg.create.none', 'hg.fork.none', | |
375 | 'hg.register.manual_activate', |
|
375 | 'hg.register.manual_activate', | |
376 | 'repository.read', 'group.read'])) |
|
376 | 'repository.read', 'group.read'])) | |
377 |
|
377 | |||
378 | def test_non_inherited_permissions_from_default_on_user_enabled(self): |
|
378 | def test_non_inherited_permissions_from_default_on_user_enabled(self): | |
379 | user_model = UserModel() |
|
379 | user_model = UserModel() | |
380 | # enable fork and create on default user |
|
380 | # enable fork and create on default user | |
381 | usr = 'default' |
|
381 | usr = 'default' | |
382 | user_model.revoke_perm(usr, 'hg.create.none') |
|
382 | user_model.revoke_perm(usr, 'hg.create.none') | |
383 | user_model.grant_perm(usr, 'hg.create.repository') |
|
383 | user_model.grant_perm(usr, 'hg.create.repository') | |
384 | user_model.revoke_perm(usr, 'hg.fork.none') |
|
384 | user_model.revoke_perm(usr, 'hg.fork.none') | |
385 | user_model.grant_perm(usr, 'hg.fork.repository') |
|
385 | user_model.grant_perm(usr, 'hg.fork.repository') | |
386 |
|
386 | |||
387 | #disable global perms on specific user |
|
387 | #disable global perms on specific user | |
388 | user_model.revoke_perm(self.u1, 'hg.create.repository') |
|
388 | user_model.revoke_perm(self.u1, 'hg.create.repository') | |
389 | user_model.grant_perm(self.u1, 'hg.create.none') |
|
389 | user_model.grant_perm(self.u1, 'hg.create.none') | |
390 | user_model.revoke_perm(self.u1, 'hg.fork.repository') |
|
390 | user_model.revoke_perm(self.u1, 'hg.fork.repository') | |
391 | user_model.grant_perm(self.u1, 'hg.fork.none') |
|
391 | user_model.grant_perm(self.u1, 'hg.fork.none') | |
392 |
|
392 | |||
393 | # make sure inherit flag is turned off |
|
393 | # make sure inherit flag is turned off | |
394 | self.u1.inherit_default_permissions = False |
|
394 | self.u1.inherit_default_permissions = False | |
395 | Session().commit() |
|
395 | Session().commit() | |
396 | u1_auth = AuthUser(user_id=self.u1.user_id) |
|
396 | u1_auth = AuthUser(user_id=self.u1.user_id) | |
397 | # this user will have non inherited permissions from he's |
|
397 | # this user will have non inherited permissions from he's | |
398 | # explicitly set permissions |
|
398 | # explicitly set permissions | |
399 | self.assertEqual(u1_auth.permissions['global'], |
|
399 | self.assertEqual(u1_auth.permissions['global'], | |
400 | set(['hg.create.none', 'hg.fork.none', |
|
400 | set(['hg.create.none', 'hg.fork.none', | |
401 | 'hg.register.manual_activate', |
|
401 | 'hg.register.manual_activate', | |
402 | 'repository.read', 'group.read'])) |
|
402 | 'repository.read', 'group.read'])) | |
403 |
|
403 | |||
404 | def test_non_inherited_permissions_from_default_on_user_disabled(self): |
|
404 | def test_non_inherited_permissions_from_default_on_user_disabled(self): | |
405 | user_model = UserModel() |
|
405 | user_model = UserModel() | |
406 | # disable fork and create on default user |
|
406 | # disable fork and create on default user | |
407 | usr = 'default' |
|
407 | usr = 'default' | |
408 | user_model.revoke_perm(usr, 'hg.create.repository') |
|
408 | user_model.revoke_perm(usr, 'hg.create.repository') | |
409 | user_model.grant_perm(usr, 'hg.create.none') |
|
409 | user_model.grant_perm(usr, 'hg.create.none') | |
410 | user_model.revoke_perm(usr, 'hg.fork.repository') |
|
410 | user_model.revoke_perm(usr, 'hg.fork.repository') | |
411 | user_model.grant_perm(usr, 'hg.fork.none') |
|
411 | user_model.grant_perm(usr, 'hg.fork.none') | |
412 |
|
412 | |||
413 | #enable global perms on specific user |
|
413 | #enable global perms on specific user | |
414 | user_model.revoke_perm(self.u1, 'hg.create.none') |
|
414 | user_model.revoke_perm(self.u1, 'hg.create.none') | |
415 | user_model.grant_perm(self.u1, 'hg.create.repository') |
|
415 | user_model.grant_perm(self.u1, 'hg.create.repository') | |
416 | user_model.revoke_perm(self.u1, 'hg.fork.none') |
|
416 | user_model.revoke_perm(self.u1, 'hg.fork.none') | |
417 | user_model.grant_perm(self.u1, 'hg.fork.repository') |
|
417 | user_model.grant_perm(self.u1, 'hg.fork.repository') | |
418 |
|
418 | |||
419 | # make sure inherit flag is turned off |
|
419 | # make sure inherit flag is turned off | |
420 | self.u1.inherit_default_permissions = False |
|
420 | self.u1.inherit_default_permissions = False | |
421 | Session().commit() |
|
421 | Session().commit() | |
422 | u1_auth = AuthUser(user_id=self.u1.user_id) |
|
422 | u1_auth = AuthUser(user_id=self.u1.user_id) | |
423 | # this user will have non inherited permissions from he's |
|
423 | # this user will have non inherited permissions from he's | |
424 | # explicitly set permissions |
|
424 | # explicitly set permissions | |
425 | self.assertEqual(u1_auth.permissions['global'], |
|
425 | self.assertEqual(u1_auth.permissions['global'], | |
426 | set(['hg.create.repository', 'hg.fork.repository', |
|
426 | set(['hg.create.repository', 'hg.fork.repository', | |
427 | 'hg.register.manual_activate', |
|
427 | 'hg.register.manual_activate', | |
428 | 'repository.read', 'group.read'])) |
|
428 | 'repository.read', 'group.read'])) | |
429 |
|
429 | |||
430 | def test_owner_permissions_doesnot_get_overwritten_by_group(self): |
|
430 | def test_owner_permissions_doesnot_get_overwritten_by_group(self): | |
431 | #create repo as USER, |
|
431 | #create repo as USER, | |
432 | self.test_repo = repo = RepoModel().create_repo(repo_name='myownrepo', |
|
432 | self.test_repo = repo = RepoModel().create_repo(repo_name='myownrepo', | |
433 | repo_type='hg', |
|
433 | repo_type='hg', | |
434 | description='desc', |
|
434 | description='desc', | |
435 | owner=self.u1) |
|
435 | owner=self.u1) | |
436 |
|
436 | |||
437 | Session().commit() |
|
437 | Session().commit() | |
438 | #he has permissions of admin as owner |
|
438 | #he has permissions of admin as owner | |
439 | u1_auth = AuthUser(user_id=self.u1.user_id) |
|
439 | u1_auth = AuthUser(user_id=self.u1.user_id) | |
440 | self.assertEqual(u1_auth.permissions['repositories']['myownrepo'], |
|
440 | self.assertEqual(u1_auth.permissions['repositories']['myownrepo'], | |
441 | 'repository.admin') |
|
441 | 'repository.admin') | |
442 |
#set his permission as user |
|
442 | #set his permission as user group, he should still be admin | |
443 | self.ug1 = UsersGroupModel().create('G1') |
|
443 | self.ug1 = UsersGroupModel().create('G1') | |
444 | # add user to group |
|
444 | # add user to group | |
445 | UsersGroupModel().add_user_to_group(self.ug1, self.u1) |
|
445 | UsersGroupModel().add_user_to_group(self.ug1, self.u1) | |
446 | RepoModel().grant_users_group_permission(repo, group_name=self.ug1, |
|
446 | RepoModel().grant_users_group_permission(repo, group_name=self.ug1, | |
447 | perm='repository.none') |
|
447 | perm='repository.none') | |
448 |
|
448 | |||
449 | Session().commit() |
|
449 | Session().commit() | |
450 | u1_auth = AuthUser(user_id=self.u1.user_id) |
|
450 | u1_auth = AuthUser(user_id=self.u1.user_id) | |
451 | self.assertEqual(u1_auth.permissions['repositories']['myownrepo'], |
|
451 | self.assertEqual(u1_auth.permissions['repositories']['myownrepo'], | |
452 | 'repository.admin') |
|
452 | 'repository.admin') | |
453 |
|
453 | |||
454 | def test_owner_permissions_doesnot_get_overwritten_by_others(self): |
|
454 | def test_owner_permissions_doesnot_get_overwritten_by_others(self): | |
455 | #create repo as USER, |
|
455 | #create repo as USER, | |
456 | self.test_repo = repo = RepoModel().create_repo(repo_name='myownrepo', |
|
456 | self.test_repo = repo = RepoModel().create_repo(repo_name='myownrepo', | |
457 | repo_type='hg', |
|
457 | repo_type='hg', | |
458 | description='desc', |
|
458 | description='desc', | |
459 | owner=self.u1) |
|
459 | owner=self.u1) | |
460 |
|
460 | |||
461 | Session().commit() |
|
461 | Session().commit() | |
462 | #he has permissions of admin as owner |
|
462 | #he has permissions of admin as owner | |
463 | u1_auth = AuthUser(user_id=self.u1.user_id) |
|
463 | u1_auth = AuthUser(user_id=self.u1.user_id) | |
464 | self.assertEqual(u1_auth.permissions['repositories']['myownrepo'], |
|
464 | self.assertEqual(u1_auth.permissions['repositories']['myownrepo'], | |
465 | 'repository.admin') |
|
465 | 'repository.admin') | |
466 | #set his permission as user, he should still be admin |
|
466 | #set his permission as user, he should still be admin | |
467 | RepoModel().grant_user_permission(repo, user=self.u1, |
|
467 | RepoModel().grant_user_permission(repo, user=self.u1, | |
468 | perm='repository.none') |
|
468 | perm='repository.none') | |
469 | Session().commit() |
|
469 | Session().commit() | |
470 | u1_auth = AuthUser(user_id=self.u1.user_id) |
|
470 | u1_auth = AuthUser(user_id=self.u1.user_id) | |
471 | self.assertEqual(u1_auth.permissions['repositories']['myownrepo'], |
|
471 | self.assertEqual(u1_auth.permissions['repositories']['myownrepo'], | |
472 | 'repository.admin') |
|
472 | 'repository.admin') |
@@ -1,124 +1,124 b'' | |||||
1 | import unittest |
|
1 | import unittest | |
2 | from rhodecode.tests import * |
|
2 | from rhodecode.tests import * | |
3 |
|
3 | |||
4 | from rhodecode.model.db import User, UsersGroup, UsersGroupMember, UserEmailMap,\ |
|
4 | from rhodecode.model.db import User, UsersGroup, UsersGroupMember, UserEmailMap,\ | |
5 | Permission |
|
5 | Permission | |
6 | from rhodecode.model.user import UserModel |
|
6 | from rhodecode.model.user import UserModel | |
7 |
|
7 | |||
8 | from rhodecode.model.meta import Session |
|
8 | from rhodecode.model.meta import Session | |
9 | from rhodecode.model.users_group import UsersGroupModel |
|
9 | from rhodecode.model.users_group import UsersGroupModel | |
10 |
|
10 | |||
11 |
|
11 | |||
12 | class TestUser(unittest.TestCase): |
|
12 | class TestUser(unittest.TestCase): | |
13 | def __init__(self, methodName='runTest'): |
|
13 | def __init__(self, methodName='runTest'): | |
14 | Session.remove() |
|
14 | Session.remove() | |
15 | super(TestUser, self).__init__(methodName=methodName) |
|
15 | super(TestUser, self).__init__(methodName=methodName) | |
16 |
|
16 | |||
17 | def test_create_and_remove(self): |
|
17 | def test_create_and_remove(self): | |
18 | usr = UserModel().create_or_update(username=u'test_user', |
|
18 | usr = UserModel().create_or_update(username=u'test_user', | |
19 | password=u'qweqwe', |
|
19 | password=u'qweqwe', | |
20 | email=u'u232@rhodecode.org', |
|
20 | email=u'u232@rhodecode.org', | |
21 | firstname=u'u1', lastname=u'u1') |
|
21 | firstname=u'u1', lastname=u'u1') | |
22 | Session().commit() |
|
22 | Session().commit() | |
23 | self.assertEqual(User.get_by_username(u'test_user'), usr) |
|
23 | self.assertEqual(User.get_by_username(u'test_user'), usr) | |
24 |
|
24 | |||
25 |
# make user |
|
25 | # make user group | |
26 | users_group = UsersGroupModel().create('some_example_group') |
|
26 | users_group = UsersGroupModel().create('some_example_group') | |
27 | Session().commit() |
|
27 | Session().commit() | |
28 |
|
28 | |||
29 | UsersGroupModel().add_user_to_group(users_group, usr) |
|
29 | UsersGroupModel().add_user_to_group(users_group, usr) | |
30 | Session().commit() |
|
30 | Session().commit() | |
31 |
|
31 | |||
32 | self.assertEqual(UsersGroup.get(users_group.users_group_id), users_group) |
|
32 | self.assertEqual(UsersGroup.get(users_group.users_group_id), users_group) | |
33 | self.assertEqual(UsersGroupMember.query().count(), 1) |
|
33 | self.assertEqual(UsersGroupMember.query().count(), 1) | |
34 | UserModel().delete(usr.user_id) |
|
34 | UserModel().delete(usr.user_id) | |
35 | Session().commit() |
|
35 | Session().commit() | |
36 |
|
36 | |||
37 | self.assertEqual(UsersGroupMember.query().all(), []) |
|
37 | self.assertEqual(UsersGroupMember.query().all(), []) | |
38 |
|
38 | |||
39 | def test_additonal_email_as_main(self): |
|
39 | def test_additonal_email_as_main(self): | |
40 | usr = UserModel().create_or_update(username=u'test_user', |
|
40 | usr = UserModel().create_or_update(username=u'test_user', | |
41 | password=u'qweqwe', |
|
41 | password=u'qweqwe', | |
42 | email=u'main_email@rhodecode.org', |
|
42 | email=u'main_email@rhodecode.org', | |
43 | firstname=u'u1', lastname=u'u1') |
|
43 | firstname=u'u1', lastname=u'u1') | |
44 | Session().commit() |
|
44 | Session().commit() | |
45 |
|
45 | |||
46 | def do(): |
|
46 | def do(): | |
47 | m = UserEmailMap() |
|
47 | m = UserEmailMap() | |
48 | m.email = u'main_email@rhodecode.org' |
|
48 | m.email = u'main_email@rhodecode.org' | |
49 | m.user = usr |
|
49 | m.user = usr | |
50 | Session().add(m) |
|
50 | Session().add(m) | |
51 | Session().commit() |
|
51 | Session().commit() | |
52 | self.assertRaises(AttributeError, do) |
|
52 | self.assertRaises(AttributeError, do) | |
53 |
|
53 | |||
54 | UserModel().delete(usr.user_id) |
|
54 | UserModel().delete(usr.user_id) | |
55 | Session().commit() |
|
55 | Session().commit() | |
56 |
|
56 | |||
57 | def test_extra_email_map(self): |
|
57 | def test_extra_email_map(self): | |
58 | usr = UserModel().create_or_update(username=u'test_user', |
|
58 | usr = UserModel().create_or_update(username=u'test_user', | |
59 | password=u'qweqwe', |
|
59 | password=u'qweqwe', | |
60 | email=u'main_email@rhodecode.org', |
|
60 | email=u'main_email@rhodecode.org', | |
61 | firstname=u'u1', lastname=u'u1') |
|
61 | firstname=u'u1', lastname=u'u1') | |
62 | Session().commit() |
|
62 | Session().commit() | |
63 |
|
63 | |||
64 | m = UserEmailMap() |
|
64 | m = UserEmailMap() | |
65 | m.email = u'main_email2@rhodecode.org' |
|
65 | m.email = u'main_email2@rhodecode.org' | |
66 | m.user = usr |
|
66 | m.user = usr | |
67 | Session().add(m) |
|
67 | Session().add(m) | |
68 | Session().commit() |
|
68 | Session().commit() | |
69 |
|
69 | |||
70 | u = User.get_by_email(email='main_email@rhodecode.org') |
|
70 | u = User.get_by_email(email='main_email@rhodecode.org') | |
71 | self.assertEqual(usr.user_id, u.user_id) |
|
71 | self.assertEqual(usr.user_id, u.user_id) | |
72 | self.assertEqual(usr.username, u.username) |
|
72 | self.assertEqual(usr.username, u.username) | |
73 |
|
73 | |||
74 | u = User.get_by_email(email='main_email2@rhodecode.org') |
|
74 | u = User.get_by_email(email='main_email2@rhodecode.org') | |
75 | self.assertEqual(usr.user_id, u.user_id) |
|
75 | self.assertEqual(usr.user_id, u.user_id) | |
76 | self.assertEqual(usr.username, u.username) |
|
76 | self.assertEqual(usr.username, u.username) | |
77 | u = User.get_by_email(email='main_email3@rhodecode.org') |
|
77 | u = User.get_by_email(email='main_email3@rhodecode.org') | |
78 | self.assertEqual(None, u) |
|
78 | self.assertEqual(None, u) | |
79 |
|
79 | |||
80 | UserModel().delete(usr.user_id) |
|
80 | UserModel().delete(usr.user_id) | |
81 | Session().commit() |
|
81 | Session().commit() | |
82 |
|
82 | |||
83 |
|
83 | |||
84 | class TestUsers(unittest.TestCase): |
|
84 | class TestUsers(unittest.TestCase): | |
85 |
|
85 | |||
86 | def __init__(self, methodName='runTest'): |
|
86 | def __init__(self, methodName='runTest'): | |
87 | super(TestUsers, self).__init__(methodName=methodName) |
|
87 | super(TestUsers, self).__init__(methodName=methodName) | |
88 |
|
88 | |||
89 | def setUp(self): |
|
89 | def setUp(self): | |
90 | self.u1 = UserModel().create_or_update(username=u'u1', |
|
90 | self.u1 = UserModel().create_or_update(username=u'u1', | |
91 | password=u'qweqwe', |
|
91 | password=u'qweqwe', | |
92 | email=u'u1@rhodecode.org', |
|
92 | email=u'u1@rhodecode.org', | |
93 | firstname=u'u1', lastname=u'u1') |
|
93 | firstname=u'u1', lastname=u'u1') | |
94 |
|
94 | |||
95 | def tearDown(self): |
|
95 | def tearDown(self): | |
96 | perm = Permission.query().all() |
|
96 | perm = Permission.query().all() | |
97 | for p in perm: |
|
97 | for p in perm: | |
98 | UserModel().revoke_perm(self.u1, p) |
|
98 | UserModel().revoke_perm(self.u1, p) | |
99 |
|
99 | |||
100 | UserModel().delete(self.u1) |
|
100 | UserModel().delete(self.u1) | |
101 | Session().commit() |
|
101 | Session().commit() | |
102 |
|
102 | |||
103 | def test_add_perm(self): |
|
103 | def test_add_perm(self): | |
104 | perm = Permission.query().all()[0] |
|
104 | perm = Permission.query().all()[0] | |
105 | UserModel().grant_perm(self.u1, perm) |
|
105 | UserModel().grant_perm(self.u1, perm) | |
106 | Session().commit() |
|
106 | Session().commit() | |
107 | self.assertEqual(UserModel().has_perm(self.u1, perm), True) |
|
107 | self.assertEqual(UserModel().has_perm(self.u1, perm), True) | |
108 |
|
108 | |||
109 | def test_has_perm(self): |
|
109 | def test_has_perm(self): | |
110 | perm = Permission.query().all() |
|
110 | perm = Permission.query().all() | |
111 | for p in perm: |
|
111 | for p in perm: | |
112 | has_p = UserModel().has_perm(self.u1, p) |
|
112 | has_p = UserModel().has_perm(self.u1, p) | |
113 | self.assertEqual(False, has_p) |
|
113 | self.assertEqual(False, has_p) | |
114 |
|
114 | |||
115 | def test_revoke_perm(self): |
|
115 | def test_revoke_perm(self): | |
116 | perm = Permission.query().all()[0] |
|
116 | perm = Permission.query().all()[0] | |
117 | UserModel().grant_perm(self.u1, perm) |
|
117 | UserModel().grant_perm(self.u1, perm) | |
118 | Session().commit() |
|
118 | Session().commit() | |
119 | self.assertEqual(UserModel().has_perm(self.u1, perm), True) |
|
119 | self.assertEqual(UserModel().has_perm(self.u1, perm), True) | |
120 |
|
120 | |||
121 | #revoke |
|
121 | #revoke | |
122 | UserModel().revoke_perm(self.u1, perm) |
|
122 | UserModel().revoke_perm(self.u1, perm) | |
123 | Session().commit() |
|
123 | Session().commit() | |
124 | self.assertEqual(UserModel().has_perm(self.u1, perm), False) |
|
124 | self.assertEqual(UserModel().has_perm(self.u1, perm), False) |
General Comments 0
You need to be logged in to leave comments.
Login now