1 # This file is part of Indico.
2 # Copyright (C) 2002 - 2015 European Organization for Nuclear Research (CERN).
4 # Indico is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License as
6 # published by the Free Software Foundation; either version 3 of the
7 # License, or (at your option) any later version.
9 # Indico is distributed in the hope that it will be useful, but
10 # WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 # General Public License for more details.
14 # You should have received a copy of the GNU General Public License
15 # along with Indico; if not, see <http://www.gnu.org/licenses/>.
17 from functools
import wraps
19 from indico
.core
.db
import db
20 from indico
.util
.decorators
import smart_decorator
22 from MaKaC
.common
.cache
import GenericCache
26 """Iterates over an ACL in the most efficient order.
28 This first yields users, then local groups, and eventually
29 multipass groups as a remote group check is much more expensive
30 than checking if two users are the same (``==``) or if a user is
31 in a local group (SQL query).
33 :param acl: any iterable containing users/groups
35 return sorted(acl
, key
=lambda x
: (x
.is_group
, not getattr(x
, 'is_local', None)))
38 def retrieve_principals(iterable
, allow_groups
=True, legacy
=True):
39 """Retrieves principal objects from ``(type, info)`` tuples.
41 See :func:`retrieve_principal` for details.
44 return filter(None, [retrieve_principal(x
, allow_groups
=allow_groups
, legacy
=legacy
) for x
in iterable
])
47 def retrieve_principal(principal
, allow_groups
=True, legacy
=True):
48 """Retrieves principal object from a `(type, id)` tuple.
50 Valid principal types are 'Avatar', 'User' and 'Group'.
52 :param principal: The principal (a tuple/list)
53 :param allow_groups: If group principals are allowed
54 :param legacy: If legacy wrappers or new objects should be returned.
56 from indico
.modules
.groups
import GroupProxy
57 from indico
.modules
.groups
.legacy
import LocalGroupWrapper
, LDAPGroupWrapper
58 from indico
.modules
.users
import User
60 type_
, id_
= principal
61 if type_
in {'Avatar', 'User'}:
62 user
= User
.get(int(id_
))
65 return user
.as_avatar
if legacy
else user
66 elif type_
== 'Group' and allow_groups
:
67 if isinstance(id_
, (int, basestring
)): # legacy group
68 group
= LocalGroupWrapper(id_
) if unicode(id_
).isdigit() else LDAPGroupWrapper(id_
)
69 return group
if legacy
else group
.group
71 provider
, name_or_id
= id_
72 group
= GroupProxy(name_or_id
, provider
)
73 return group
.as_legacy_group
if legacy
else group
75 raise ValueError('Unexpected type: {}'.format(type_
))
78 def principal_from_fossil(fossil
, allow_pending
=False, allow_groups
=True, legacy
=True):
79 """Gets a GroupWrapper or AvatarUserWrapper from a fossil"""
80 from indico
.modules
.groups
import GroupProxy
81 from indico
.modules
.users
import User
83 type_
= fossil
['_type']
86 if isinstance(id_
, int) or id_
.isdigit():
88 user
= User
.get(int(id_
))
90 data
= GenericCache('pending_identities').get(id_
)
92 raise ValueError("Cannot find user '{}' in cache".format(id_
))
94 data
= {k
: '' if v
is None else v
for (k
, v
) in data
.items()}
96 # check if there is not already a pending user with that e-mail
97 user
= User
.find_first(email
=data
['email'], is_pending
=True)
99 user
= User(first_name
=data
.get('first_name') or '', last_name
=data
.get('last_name') or '',
101 address
=data
.get('address', ''), phone
=data
.get('phone', ''),
102 affiliation
=data
.get('affiliation', ''), is_pending
=True)
106 raise ValueError("Id '{}' is not a number and allow_pending=False".format(id_
))
108 raise ValueError('User does not exist: {}'.format(id_
))
109 return user
.as_avatar
if legacy
else user
110 elif not allow_groups
:
111 raise ValueError('Unexpected fossil type: {}'.format(type_
))
112 elif type_
in {'LocalGroupWrapper', 'LocalGroup'}:
113 group
= GroupProxy(int(id_
))
114 if group
.group
is None:
115 raise ValueError('Local group does not exist: {}'.format(id_
))
116 return group
.as_legacy_group
if legacy
else group
117 elif type_
in {'LDAPGroupWrapper', 'MultipassGroup'}:
118 provider
= fossil
['provider']
119 group
= GroupProxy(id_
, provider
)
120 if group
.group
is None:
121 raise ValueError('Multipass group does not exist: {}:{}'.format(provider
, id_
))
122 return group
.as_legacy_group
if legacy
else group
124 raise ValueError('Unexpected fossil type: {}'.format(type_
))
128 def unify_user_args(fn
, legacy
=False):
129 """Decorator that unifies new/legacy user arguments.
131 Any argument of the decorated function that contains either a
132 :class:`AvatarUserWrapper` or a :class:`.User` will be converted
133 to the object type specified by the `legacy` argument.
135 :param legacy: If True, all arguments containing users will receive
136 an :class:`AvatarUserWrapper`. Otherwise, they will
137 receive a :class:`.User`.
139 from indico
.modules
.users
import User
143 return arg
.as_avatar
if isinstance(arg
, User
) else arg
146 from indico
.modules
.users
.legacy
import AvatarUserWrapper
147 return arg
.user
if isinstance(arg
, AvatarUserWrapper
) else arg
150 def wrapper(*args
, **kwargs
):
151 args
= map(_convert
, args
)
152 kwargs
= {k
: _convert(v
) for k
, v
in kwargs
.iteritems()}
153 return fn(*args
, **kwargs
)