Files @ 7e5f8c12a3fc
Branch filter:

Location: kallithea/rhodecode/model/user.py - annotation

Bradley M. Kuhn
First step in two-part process to rename directories to kallithea.
This first step is to change all references in the files where they refer
to the old directory name.
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
56c2850a5b5f
a671db5bdd58
a671db5bdd58
a671db5bdd58
a671db5bdd58
6832ef664673
7e536d1af60d
7e536d1af60d
7e536d1af60d
7e536d1af60d
6832ef664673
7e536d1af60d
a671db5bdd58
ffd45b185016
7e5f8c12a3fc
ffd45b185016
ffd45b185016
ffd45b185016
ffd45b185016
ffd45b185016
ffd45b185016
ffd45b185016
ffd45b185016
ffd45b185016
ffd45b185016
73c99f45ef2a
7e536d1af60d
7e536d1af60d
31e6eb2fb4b2
56c2850a5b5f
56c2850a5b5f
9225597688f4
ffd45b185016
9225597688f4
7e5f8c12a3fc
7e5f8c12a3fc
7e5f8c12a3fc
7e5f8c12a3fc
ffd45b185016
7e5f8c12a3fc
2e7f21429316
7e5f8c12a3fc
1bb0fcdec895
56c2850a5b5f
56c2850a5b5f
7e536d1af60d
d534aff5e82a
89b9037d68b7
17893d61792a
7d1fc253549e
9dae92a65e40
7e536d1af60d
7e536d1af60d
7e536d1af60d
7e536d1af60d
7e536d1af60d
7e536d1af60d
b63adad7c4af
d3ac7491a5c8
b63adad7c4af
9dae92a65e40
73c99f45ef2a
1377a9d4bdb9
1377a9d4bdb9
1377a9d4bdb9
ffd45b185016
ffd45b185016
7e536d1af60d
7e536d1af60d
7e536d1af60d
7e536d1af60d
7e536d1af60d
17893d61792a
17893d61792a
17893d61792a
9dae92a65e40
60249224be04
6eb5bb24a948
509923dac48d
509923dac48d
727d2a45ec10
3b136af34329
7e5f8c12a3fc
3b136af34329
92da990f9eaf
3b136af34329
3b136af34329
3b136af34329
3b136af34329
3b136af34329
92da990f9eaf
7e5f8c12a3fc
7e536d1af60d
7e536d1af60d
7e536d1af60d
4419551b2915
4419551b2915
6ce3387bf0ce
6ce3387bf0ce
7e536d1af60d
7e536d1af60d
716911af91e1
7e536d1af60d
cce2d984b001
509923dac48d
2ccb32ddcfd7
10b4e34841a4
7e536d1af60d
7e536d1af60d
7e536d1af60d
388843a3a3c0
ffd45b185016
ffd45b185016
1d904d972c47
1d904d972c47
cf51bbfb120e
1d904d972c47
1d904d972c47
1d904d972c47
1d904d972c47
388843a3a3c0
1d904d972c47
1d904d972c47
1d904d972c47
ffd45b185016
ffd45b185016
18121c5425b8
1d904d972c47
509923dac48d
727d2a45ec10
07e56179633e
7e5f8c12a3fc
7e5f8c12a3fc
92da990f9eaf
3b136af34329
3b136af34329
3b136af34329
3b136af34329
3b136af34329
92da990f9eaf
07e56179633e
a76e9bacbedc
1d904d972c47
1d904d972c47
a76e9bacbedc
1d904d972c47
388843a3a3c0
1d904d972c47
a76e9bacbedc
1d904d972c47
388843a3a3c0
07e56179633e
1d904d972c47
1d904d972c47
1d904d972c47
1d904d972c47
1d904d972c47
ffd45b185016
ffd45b185016
388843a3a3c0
1d904d972c47
ffd45b185016
ffd45b185016
ffd45b185016
ffd45b185016
ffd45b185016
ffd45b185016
ffd45b185016
ffd45b185016
ffd45b185016
ffd45b185016
ffd45b185016
ffd45b185016
1d904d972c47
cce2d984b001
cce2d984b001
509923dac48d
1d904d972c47
1d904d972c47
1d904d972c47
1d904d972c47
07e56179633e
7e536d1af60d
7e5f8c12a3fc
31e6eb2fb4b2
7e536d1af60d
72542dc597be
ffd45b185016
ffd45b185016
72542dc597be
7e536d1af60d
7e536d1af60d
31e6eb2fb4b2
31e6eb2fb4b2
31e6eb2fb4b2
ec6354949623
ecc566f8b69f
31e6eb2fb4b2
31e6eb2fb4b2
31e6eb2fb4b2
31e6eb2fb4b2
18121c5425b8
31e6eb2fb4b2
4ae17f819ee8
31e6eb2fb4b2
31e6eb2fb4b2
31e6eb2fb4b2
31e6eb2fb4b2
ecc566f8b69f
10b4e34841a4
7e536d1af60d
7e536d1af60d
7e536d1af60d
b2b93614a7cd
7e5f8c12a3fc
7e536d1af60d
9dae92a65e40
ffd45b185016
7e536d1af60d
ffd45b185016
ffd45b185016
1bb0fcdec895
7e536d1af60d
b2b93614a7cd
b2b93614a7cd
6ce3387bf0ce
b5b34d71b23b
7e536d1af60d
ffd45b185016
ffd45b185016
6ce3387bf0ce
6ce3387bf0ce
716911af91e1
716911af91e1
10b4e34841a4
7e536d1af60d
7e536d1af60d
7e536d1af60d
001c7e2ae986
7e5f8c12a3fc
001c7e2ae986
001c7e2ae986
ffd45b185016
001c7e2ae986
001c7e2ae986
001c7e2ae986
001c7e2ae986
001c7e2ae986
001c7e2ae986
001c7e2ae986
001c7e2ae986
001c7e2ae986
001c7e2ae986
001c7e2ae986
001c7e2ae986
10b4e34841a4
001c7e2ae986
001c7e2ae986
001c7e2ae986
509923dac48d
509923dac48d
727d2a45ec10
d3ac7491a5c8
cf51bbfb120e
7e536d1af60d
ffd45b185016
7e536d1af60d
fa637dc3e029
273ce1a99c3f
273ce1a99c3f
1bb0fcdec895
fa637dc3e029
273ce1a99c3f
fa637dc3e029
fa637dc3e029
fa637dc3e029
273ce1a99c3f
7e536d1af60d
cce2d984b001
7e5f8c12a3fc
509923dac48d
10b4e34841a4
7e536d1af60d
7e536d1af60d
7e536d1af60d
5875955def39
7e5f8c12a3fc
7e5f8c12a3fc
5c310b7b01ce
5c310b7b01ce
5c310b7b01ce
5c310b7b01ce
5c310b7b01ce
5c310b7b01ce
5c310b7b01ce
5c310b7b01ce
5c310b7b01ce
5c310b7b01ce
5c310b7b01ce
5c310b7b01ce
5c310b7b01ce
ec6354949623
5c310b7b01ce
5c310b7b01ce
5c310b7b01ce
10b4e34841a4
5c310b7b01ce
5c310b7b01ce
5c310b7b01ce
5c310b7b01ce
5875955def39
7e536d1af60d
7e5f8c12a3fc
7e5f8c12a3fc
5c310b7b01ce
92da990f9eaf
5c310b7b01ce
92da990f9eaf
92da990f9eaf
92da990f9eaf
92da990f9eaf
92da990f9eaf
92da990f9eaf
92da990f9eaf
92da990f9eaf
92da990f9eaf
92da990f9eaf
5c310b7b01ce
92da990f9eaf
5c310b7b01ce
5c310b7b01ce
18121c5425b8
5c310b7b01ce
5c310b7b01ce
10b4e34841a4
5c310b7b01ce
5c310b7b01ce
92da990f9eaf
92da990f9eaf
92da990f9eaf
92da990f9eaf
5c310b7b01ce
5c310b7b01ce
dd532af216d9
ffd45b185016
dd532af216d9
6eb5bb24a948
6eb5bb24a948
6832ef664673
dd532af216d9
6832ef664673
6eb5bb24a948
6eb5bb24a948
6eb5bb24a948
ffd45b185016
dd532af216d9
ffd45b185016
ffd45b185016
ff6a8196ebfe
6eb5bb24a948
ffd45b185016
ffd45b185016
ffd45b185016
ffd45b185016
6eb5bb24a948
ffd45b185016
ffd45b185016
6eb5bb24a948
9353189b7675
a76e9bacbedc
ffd45b185016
ffd45b185016
ffd45b185016
9353189b7675
9353189b7675
6eb5bb24a948
10b4e34841a4
6eb5bb24a948
6eb5bb24a948
9353189b7675
6eb5bb24a948
9353189b7675
ff6a8196ebfe
8ecc6b8229a5
d2d35cf2b351
d3ac7491a5c8
8ecc6b8229a5
a87aa385f21c
8ecc6b8229a5
8ecc6b8229a5
8ecc6b8229a5
87f0800abc7b
87f0800abc7b
8ecc6b8229a5
87f0800abc7b
87f0800abc7b
87f0800abc7b
d3ac7491a5c8
d3ac7491a5c8
d4b6c8541bd9
d4b6c8541bd9
d4b6c8541bd9
d4b6c8541bd9
d4b6c8541bd9
d4b6c8541bd9
d4b6c8541bd9
8ecc6b8229a5
a87aa385f21c
8ecc6b8229a5
8ecc6b8229a5
ffd45b185016
8ecc6b8229a5
8ecc6b8229a5
87f0800abc7b
87f0800abc7b
cf51bbfb120e
87f0800abc7b
87f0800abc7b
87f0800abc7b
d3ac7491a5c8
d3ac7491a5c8
cf51bbfb120e
d4b6c8541bd9
d4b6c8541bd9
d4b6c8541bd9
d4b6c8541bd9
a87aa385f21c
a87aa385f21c
b0fef8a77568
b0fef8a77568
b0fef8a77568
b0fef8a77568
b0fef8a77568
b0fef8a77568
b0fef8a77568
b0fef8a77568
7e5f8c12a3fc
9225597688f4
9225597688f4
d3ac7491a5c8
9225597688f4
b0fef8a77568
b0fef8a77568
9225597688f4
b0fef8a77568
b0fef8a77568
b0fef8a77568
b0fef8a77568
b0fef8a77568
b0fef8a77568
b0fef8a77568
b0fef8a77568
b0fef8a77568
b0fef8a77568
d3ac7491a5c8
b0fef8a77568
b0fef8a77568
8eab81115660
9b92cf5a0cca
9b92cf5a0cca
9b92cf5a0cca
9b92cf5a0cca
9b92cf5a0cca
9b92cf5a0cca
9b92cf5a0cca
9b92cf5a0cca
7e5f8c12a3fc
9b92cf5a0cca
9b92cf5a0cca
9b92cf5a0cca
9b92cf5a0cca
9b92cf5a0cca
9b92cf5a0cca
9b92cf5a0cca
9b92cf5a0cca
9b92cf5a0cca
9b92cf5a0cca
9b92cf5a0cca
9b92cf5a0cca
9b92cf5a0cca
9b92cf5a0cca
9b92cf5a0cca
9b92cf5a0cca
9b92cf5a0cca
9b92cf5a0cca
9b92cf5a0cca
9b92cf5a0cca
9b92cf5a0cca
# -*- coding: utf-8 -*-
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
"""
kallithea.model.user
~~~~~~~~~~~~~~~~~~~~

users model for RhodeCode

:created_on: Apr 9, 2010
:author: marcink
:copyright: (c) 2013 RhodeCode GmbH.
:license: GPLv3, see LICENSE for more details.
"""


import logging
import traceback
from pylons import url
from pylons.i18n.translation import _

from sqlalchemy.exc import DatabaseError


from kallithea.lib.utils2 import safe_unicode, generate_api_key, get_current_rhodecode_user
from kallithea.lib.caching_query import FromCache
from kallithea.model import BaseModel
from kallithea.model.db import User, UserToPerm, Notification, \
    UserEmailMap, UserIpMap
from kallithea.lib.exceptions import DefaultUserException, \
    UserOwnsReposException
from kallithea.model.meta import Session


log = logging.getLogger(__name__)


class UserModel(BaseModel):
    cls = User

    def get(self, user_id, cache=False):
        user = self.sa.query(User)
        if cache:
            user = user.options(FromCache("sql_cache_short",
                                          "get_user_%s" % user_id))
        return user.get(user_id)

    def get_user(self, user):
        return self._get_user(user)

    def get_by_username(self, username, cache=False, case_insensitive=False):

        if case_insensitive:
            user = self.sa.query(User).filter(User.username.ilike(username))
        else:
            user = self.sa.query(User)\
                .filter(User.username == username)
        if cache:
            user = user.options(FromCache("sql_cache_short",
                                          "get_user_%s" % username))
        return user.scalar()

    def get_by_email(self, email, cache=False, case_insensitive=False):
        return User.get_by_email(email, case_insensitive, cache)

    def get_by_api_key(self, api_key, cache=False):
        return User.get_by_api_key(api_key, cache)

    def create(self, form_data, cur_user=None):
        if not cur_user:
            cur_user = getattr(get_current_rhodecode_user(), 'username', None)

        from kallithea.lib.hooks import log_create_user, check_allowed_create_user
        _fd = form_data
        user_data = {
            'username': _fd['username'], 'password': _fd['password'],
            'email': _fd['email'], 'firstname': _fd['firstname'], 'lastname': _fd['lastname'],
            'active': _fd['active'], 'admin': False
        }
        # raises UserCreationError if it's not allowed
        check_allowed_create_user(user_data, cur_user)
        from kallithea.lib.auth import get_crypt_password
        try:
            new_user = User()
            for k, v in form_data.items():
                if k == 'password':
                    v = get_crypt_password(v)
                if k == 'firstname':
                    k = 'name'
                setattr(new_user, k, v)

            new_user.api_key = generate_api_key(form_data['username'])
            self.sa.add(new_user)

            log_create_user(new_user.get_dict(), cur_user)
            return new_user
        except Exception:
            log.error(traceback.format_exc())
            raise

    def create_or_update(self, username, password, email, firstname='',
                         lastname='', active=True, admin=False,
                         extern_type=None, extern_name=None, cur_user=None):
        """
        Creates a new instance if not found, or updates current one

        :param username:
        :param password:
        :param email:
        :param active:
        :param firstname:
        :param lastname:
        :param active:
        :param admin:
        :param extern_name:
        :param extern_type:
        :param cur_user:
        """
        if not cur_user:
            cur_user = getattr(get_current_rhodecode_user(), 'username', None)

        from kallithea.lib.auth import get_crypt_password, check_password
        from kallithea.lib.hooks import log_create_user, check_allowed_create_user
        user_data = {
            'username': username, 'password': password,
            'email': email, 'firstname': firstname, 'lastname': lastname,
            'active': active, 'admin': admin
        }
        # raises UserCreationError if it's not allowed
        check_allowed_create_user(user_data, cur_user)

        log.debug('Checking for %s account in RhodeCode database' % username)
        user = User.get_by_username(username, case_insensitive=True)
        if user is None:
            log.debug('creating new user %s' % username)
            new_user = User()
            edit = False
        else:
            log.debug('updating user %s' % username)
            new_user = user
            edit = True

        try:
            new_user.username = username
            new_user.admin = admin
            new_user.email = email
            new_user.active = active
            new_user.extern_name = safe_unicode(extern_name) if extern_name else None
            new_user.extern_type = safe_unicode(extern_type) if extern_type else None
            new_user.name = firstname
            new_user.lastname = lastname

            if not edit:
                new_user.api_key = generate_api_key(username)

            # set password only if creating an user or password is changed
            password_change = new_user.password and not check_password(password,
                                                            new_user.password)
            if not edit or password_change:
                reason = 'new password' if edit else 'new user'
                log.debug('Updating password reason=>%s' % (reason,))
                new_user.password = get_crypt_password(password) if password else None

            self.sa.add(new_user)

            if not edit:
                log_create_user(new_user.get_dict(), cur_user)
            return new_user
        except (DatabaseError,):
            log.error(traceback.format_exc())
            raise

    def create_registration(self, form_data):
        from kallithea.model.notification import NotificationModel

        try:
            form_data['admin'] = False
            form_data['extern_name'] = 'rhodecode'
            form_data['extern_type'] = 'rhodecode'
            new_user = self.create(form_data)

            self.sa.add(new_user)
            self.sa.flush()

            # notification to admins
            subject = _('New user registration')
            body = ('New user registration\n'
                    '---------------------\n'
                    '- Username: %s\n'
                    '- Full Name: %s\n'
                    '- Email: %s\n')
            body = body % (new_user.username, new_user.full_name, new_user.email)
            edit_url = url('edit_user', id=new_user.user_id, qualified=True)
            kw = {'registered_user_url': edit_url}
            NotificationModel().create(created_by=new_user, subject=subject,
                                       body=body, recipients=None,
                                       type_=Notification.TYPE_REGISTRATION,
                                       email_kwargs=kw)

        except Exception:
            log.error(traceback.format_exc())
            raise

    def update(self, user_id, form_data, skip_attrs=[]):
        from kallithea.lib.auth import get_crypt_password
        try:
            user = self.get(user_id, cache=False)
            if user.username == User.DEFAULT_USER:
                raise DefaultUserException(
                                _("You can't Edit this user since it's "
                                  "crucial for entire application"))

            for k, v in form_data.items():
                if k in skip_attrs:
                    continue
                if k == 'new_password' and v:
                    user.password = get_crypt_password(v)
                else:
                    # old legacy thing orm models store firstname as name,
                    # need proper refactor to username
                    if k == 'firstname':
                        k = 'name'
                    setattr(user, k, v)
            self.sa.add(user)
        except Exception:
            log.error(traceback.format_exc())
            raise

    def update_user(self, user, **kwargs):
        from kallithea.lib.auth import get_crypt_password
        try:
            user = self._get_user(user)
            if user.username == User.DEFAULT_USER:
                raise DefaultUserException(
                    _("You can't Edit this user since it's"
                      " crucial for entire application")
                )

            for k, v in kwargs.items():
                if k == 'password' and v:
                    v = get_crypt_password(v)

                setattr(user, k, v)
            self.sa.add(user)
            return user
        except Exception:
            log.error(traceback.format_exc())
            raise

    def delete(self, user, cur_user=None):
        if not cur_user:
            cur_user = getattr(get_current_rhodecode_user(), 'username', None)
        user = self._get_user(user)

        try:
            if user.username == User.DEFAULT_USER:
                raise DefaultUserException(
                    _(u"You can't remove this user since it's"
                      " crucial for entire application")
                )
            if user.repositories:
                repos = [x.repo_name for x in user.repositories]
                raise UserOwnsReposException(
                    _(u'user "%s" still owns %s repositories and cannot be '
                      'removed. Switch owners or remove those repositories. %s')
                    % (user.username, len(repos), ', '.join(repos))
                )
            self.sa.delete(user)

            from kallithea.lib.hooks import log_delete_user
            log_delete_user(user.get_dict(), cur_user)
        except Exception:
            log.error(traceback.format_exc())
            raise

    def reset_password_link(self, data):
        from kallithea.lib.celerylib import tasks, run_task
        from kallithea.model.notification import EmailNotificationModel
        user_email = data['email']
        try:
            user = User.get_by_email(user_email)
            if user:
                log.debug('password reset user found %s' % user)
                link = url('reset_password_confirmation', key=user.api_key,
                           qualified=True)
                reg_type = EmailNotificationModel.TYPE_PASSWORD_RESET
                body = EmailNotificationModel().get_email_tmpl(reg_type,
                                                    **{'user': user.short_contact,
                                                       'reset_url': link})
                log.debug('sending email')
                run_task(tasks.send_email, user_email,
                         _("Password reset link"), body, body)
                log.info('send new password mail to %s' % user_email)
            else:
                log.debug("password reset email %s not found" % user_email)
        except Exception:
            log.error(traceback.format_exc())
            return False

        return True

    def reset_password(self, data):
        from kallithea.lib.celerylib import tasks, run_task
        from kallithea.lib import auth
        user_email = data['email']
        pre_db = True
        try:
            user = User.get_by_email(user_email)
            new_passwd = auth.PasswordGenerator().gen_password(8,
                            auth.PasswordGenerator.ALPHABETS_BIG_SMALL)
            if user:
                user.password = auth.get_crypt_password(new_passwd)
                Session().add(user)
                Session().commit()
                log.info('change password for %s' % user_email)
            if new_passwd is None:
                raise Exception('unable to generate new password')

            pre_db = False
            run_task(tasks.send_email, user_email,
                     _('Your new password'),
                     _('Your new RhodeCode password:%s') % (new_passwd,))
            log.info('send new password mail to %s' % user_email)

        except Exception:
            log.error('Failed to update user password')
            log.error(traceback.format_exc())
            if pre_db:
                # we rollback only if local db stuff fails. If it goes into
                # run_task, we're pass rollback state this wouldn't work then
                Session().rollback()

        return True

    def fill_data(self, auth_user, user_id=None, api_key=None, username=None):
        """
        Fetches auth_user by user_id,or api_key if present.
        Fills auth_user attributes with those taken from database.
        Additionally set's is_authenitated if lookup fails
        present in database

        :param auth_user: instance of user to set attributes
        :param user_id: user id to fetch by
        :param api_key: api key to fetch by
        :param username: username to fetch by
        """
        if user_id is None and api_key is None and username is None:
            raise Exception('You need to pass user_id, api_key or username')

        try:
            dbuser = None
            if user_id:
                dbuser = self.get(user_id)
            elif api_key:
                dbuser = self.get_by_api_key(api_key)
            elif username:
                dbuser = self.get_by_username(username)

            if dbuser is not None and dbuser.active:
                log.debug('filling %s data' % dbuser)
                for k, v in dbuser.get_dict().iteritems():
                    if k not in ['api_keys', 'permissions']:
                        setattr(auth_user, k, v)
            else:
                return False

        except Exception:
            log.error(traceback.format_exc())
            auth_user.is_authenticated = False
            return False

        return True

    def has_perm(self, user, perm):
        perm = self._get_perm(perm)
        user = self._get_user(user)

        return UserToPerm.query().filter(UserToPerm.user == user)\
            .filter(UserToPerm.permission == perm).scalar() is not None

    def grant_perm(self, user, perm):
        """
        Grant user global permissions

        :param user:
        :param perm:
        """
        user = self._get_user(user)
        perm = self._get_perm(perm)
        # if this permission is already granted skip it
        _perm = UserToPerm.query()\
            .filter(UserToPerm.user == user)\
            .filter(UserToPerm.permission == perm)\
            .scalar()
        if _perm:
            return
        new = UserToPerm()
        new.user = user
        new.permission = perm
        self.sa.add(new)
        return new

    def revoke_perm(self, user, perm):
        """
        Revoke users global permissions

        :param user:
        :param perm:
        """
        user = self._get_user(user)
        perm = self._get_perm(perm)

        obj = UserToPerm.query()\
                .filter(UserToPerm.user == user)\
                .filter(UserToPerm.permission == perm)\
                .scalar()
        if obj:
            self.sa.delete(obj)

    def add_extra_email(self, user, email):
        """
        Adds email address to UserEmailMap

        :param user:
        :param email:
        """
        from kallithea.model import forms
        form = forms.UserExtraEmailForm()()
        data = form.to_python(dict(email=email))
        user = self._get_user(user)

        obj = UserEmailMap()
        obj.user = user
        obj.email = data['email']
        self.sa.add(obj)
        return obj

    def delete_extra_email(self, user, email_id):
        """
        Removes email address from UserEmailMap

        :param user:
        :param email_id:
        """
        user = self._get_user(user)
        obj = UserEmailMap.query().get(email_id)
        if obj:
            self.sa.delete(obj)

    def add_extra_ip(self, user, ip):
        """
        Adds ip address to UserIpMap

        :param user:
        :param ip:
        """
        from kallithea.model import forms
        form = forms.UserExtraIpForm()()
        data = form.to_python(dict(ip=ip))
        user = self._get_user(user)

        obj = UserIpMap()
        obj.user = user
        obj.ip_addr = data['ip']
        self.sa.add(obj)
        return obj

    def delete_extra_ip(self, user, ip_id):
        """
        Removes ip address from UserIpMap

        :param user:
        :param ip_id:
        """
        user = self._get_user(user)
        obj = UserIpMap.query().get(ip_id)
        if obj:
            self.sa.delete(obj)