Statistics
| Branch: | Tag: | Revision:

root / invitations / invitations.py @ 4af67649

History | View | Annotate | Download (12.5 kB)

1 f1bb3880 Georgios Gousios
# vim: set fileencoding=utf-8 :
2 48130e66 Georgios Gousios
# Copyright 2011 GRNET S.A. All rights reserved.
3 48130e66 Georgios Gousios
#
4 48130e66 Georgios Gousios
# Redistribution and use in source and binary forms, with or without
5 48130e66 Georgios Gousios
# modification, are permitted provided that the following conditions
6 48130e66 Georgios Gousios
# are met:
7 48130e66 Georgios Gousios
#
8 48130e66 Georgios Gousios
#   1. Redistributions of source code must retain the above copyright
9 48130e66 Georgios Gousios
#      notice, this list of conditions and the following disclaimer.
10 48130e66 Georgios Gousios
#
11 48130e66 Georgios Gousios
#  2. Redistributions in binary form must reproduce the above copyright
12 48130e66 Georgios Gousios
#     notice, this list of conditions and the following disclaimer in the
13 48130e66 Georgios Gousios
#     documentation and/or other materials provided with the distribution.
14 48130e66 Georgios Gousios
#
15 48130e66 Georgios Gousios
# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
16 48130e66 Georgios Gousios
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 48130e66 Georgios Gousios
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 48130e66 Georgios Gousios
# ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
19 48130e66 Georgios Gousios
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 48130e66 Georgios Gousios
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 48130e66 Georgios Gousios
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 48130e66 Georgios Gousios
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 48130e66 Georgios Gousios
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 48130e66 Georgios Gousios
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 48130e66 Georgios Gousios
# SUCH DAMAGE.
26 48130e66 Georgios Gousios
#
27 48130e66 Georgios Gousios
# The views and conclusions contained in the software and documentation are
28 48130e66 Georgios Gousios
# those of the authors and should not be interpreted as representing official
29 48130e66 Georgios Gousios
# policies, either expressed or implied, of GRNET S.A.
30 48130e66 Georgios Gousios
31 48130e66 Georgios Gousios
32 e6d6603a Georgios Gousios
from datetime import timedelta
33 0fbab7db Vangelis Koukis
import datetime
34 e6d6603a Georgios Gousios
import base64
35 3b09ff22 Georgios Gousios
import urllib
36 4f8e7c6d Georgios Gousios
import re
37 e6d6603a Georgios Gousios
38 03e70572 Georgios Gousios
from django.conf import settings
39 566cd8b2 Georgios Gousios
from django.core.exceptions import ValidationError
40 03e70572 Georgios Gousios
from django.db import transaction
41 0230cd3a Vangelis Koukis
from django.http import HttpResponse, HttpResponseRedirect, \
42 0230cd3a Vangelis Koukis
    HttpResponseBadRequest, HttpResponseServerError
43 a640b50d Georgios Gousios
from django.template.context import RequestContext
44 2a0eee64 Georgios Gousios
from django.template.loader import render_to_string
45 566cd8b2 Georgios Gousios
from django.core.validators import validate_email
46 a640b50d Georgios Gousios
from django.views.decorators.csrf import csrf_protect
47 b6b88056 Kostas Papadimitriou
from django.utils.translation import ugettext as _
48 566cd8b2 Georgios Gousios
49 670a350a Georgios Gousios
from synnefo.logic.email_send import send_async, send
50 03e70572 Georgios Gousios
from synnefo.api.common import method_not_allowed
51 03e70572 Georgios Gousios
from synnefo.db.models import Invitations, SynnefoUser
52 d028ab18 Georgios Gousios
from synnefo.logic import users, log
53 e6d6603a Georgios Gousios
54 e6d6603a Georgios Gousios
from Crypto.Cipher import AES
55 03e70572 Georgios Gousios
56 d028ab18 Georgios Gousios
_logger = log.get_logger("synnefo.invitations")
57 f1bb3880 Georgios Gousios
58 0230cd3a Vangelis Koukis
59 e6d6603a Georgios Gousios
def process_form(request):
60 a640b50d Georgios Gousios
    errors = []
61 566cd8b2 Georgios Gousios
    valid_inv = filter(lambda x: x.startswith("name_"), request.POST.keys())
62 ecb4680f Georgios Gousios
    invitation = None
63 566cd8b2 Georgios Gousios
64 566cd8b2 Georgios Gousios
    for inv in valid_inv:
65 566cd8b2 Georgios Gousios
        (name, inv_id) = inv.split('_')
66 566cd8b2 Georgios Gousios
67 05310288 Georgios Gousios
        email = ""
68 05310288 Georgios Gousios
        name = ""
69 566cd8b2 Georgios Gousios
        try:
70 566cd8b2 Georgios Gousios
            email = request.POST['email_' + inv_id]
71 566cd8b2 Georgios Gousios
            name = request.POST[inv]
72 566cd8b2 Georgios Gousios
73 566cd8b2 Georgios Gousios
            validate_name(name)
74 a640b50d Georgios Gousios
            validate_email(email)
75 a640b50d Georgios Gousios
76 ecb4680f Georgios Gousios
            invitation = add_invitation(request.user, name, email)
77 ecb4680f Georgios Gousios
            send_invitation(invitation)
78 a640b50d Georgios Gousios
79 d028ab18 Georgios Gousios
        except (InvitationException, ValidationError) as e:
80 d028ab18 Georgios Gousios
            errors += ["Invitation to %s <%s> not sent. Reason: %s" %
81 b6b88056 Kostas Papadimitriou
                       (name, email, e.messages[0])]
82 566cd8b2 Georgios Gousios
        except Exception as e:
83 ecb4680f Georgios Gousios
            remove_invitation(invitation)
84 d028ab18 Georgios Gousios
            _logger.exception(e)
85 0230cd3a Vangelis Koukis
            errors += ["Invitation to %s <%s> could not be sent. An unexpected"
86 0230cd3a Vangelis Koukis
                       " error occurred. Please try again later." %
87 0230cd3a Vangelis Koukis
                       (name, email)]
88 a640b50d Georgios Gousios
89 0230cd3a Vangelis Koukis
    response = None
90 a640b50d Georgios Gousios
    if errors:
91 a640b50d Georgios Gousios
        data = render_to_string('invitations.html',
92 c00e4507 Vangelis Koukis
                                {'invitations':
93 c00e4507 Vangelis Koukis
                                     invitations_for_user(request),
94 c00e4507 Vangelis Koukis
                                 'errors':
95 c00e4507 Vangelis Koukis
                                     errors,
96 c00e4507 Vangelis Koukis
                                 'invitations_left':
97 c00e4507 Vangelis Koukis
                                     get_invitations_left(request.user)},
98 a640b50d Georgios Gousios
                                context_instance=RequestContext(request))
99 c00e4507 Vangelis Koukis
        response = HttpResponse(data)
100 0230cd3a Vangelis Koukis
        _logger.warn("Error adding invitation %s -> %s: %s" %
101 0230cd3a Vangelis Koukis
                     (request.user.uniq, email, errors))
102 a640b50d Georgios Gousios
    else:
103 848e6d10 Kostas Papadimitriou
        # form submitted
104 848e6d10 Kostas Papadimitriou
        data = render_to_string('invitations.html',
105 c00e4507 Vangelis Koukis
                                {'invitations':
106 c00e4507 Vangelis Koukis
                                    invitations_for_user(request),
107 c00e4507 Vangelis Koukis
                                 'invitations_left':
108 c00e4507 Vangelis Koukis
                                    get_invitations_left(request.user)},
109 848e6d10 Kostas Papadimitriou
                                context_instance=RequestContext(request))
110 848e6d10 Kostas Papadimitriou
        response = HttpResponse(data)
111 0230cd3a Vangelis Koukis
        _logger.info("Added invitation %s -> %s" % (request.user.uniq, email))
112 566cd8b2 Georgios Gousios
113 566cd8b2 Georgios Gousios
    return response
114 566cd8b2 Georgios Gousios
115 f1bb3880 Georgios Gousios
116 566cd8b2 Georgios Gousios
def validate_name(name):
117 68a77896 Georgios Gousios
    if name is None or name.strip() == '':
118 a640b50d Georgios Gousios
        raise ValidationError("Name is empty")
119 a640b50d Georgios Gousios
120 a640b50d Georgios Gousios
    if name.find(' ') is -1:
121 b6b88056 Kostas Papadimitriou
        raise ValidationError(_("Name must contain at least one space"))
122 03e70572 Georgios Gousios
123 566cd8b2 Georgios Gousios
    return True
124 566cd8b2 Georgios Gousios
125 f1bb3880 Georgios Gousios
126 566cd8b2 Georgios Gousios
def invitations_for_user(request):
127 566cd8b2 Georgios Gousios
    invitations = []
128 566cd8b2 Georgios Gousios
129 d5912f54 Kostas Papadimitriou
    for inv in Invitations.objects.filter(source=request.user).order_by("-id"):
130 e6d6603a Georgios Gousios
        invitation = {}
131 566cd8b2 Georgios Gousios
132 e6d6603a Georgios Gousios
        invitation['sourcename'] = inv.source.realname
133 e6d6603a Georgios Gousios
        invitation['source'] = inv.source.uniq
134 e6d6603a Georgios Gousios
        invitation['targetname'] = inv.target.realname
135 e6d6603a Georgios Gousios
        invitation['target'] = inv.target.uniq
136 e6d6603a Georgios Gousios
        invitation['accepted'] = inv.accepted
137 e6d6603a Georgios Gousios
        invitation['sent'] = inv.created
138 4f8e7c6d Georgios Gousios
        invitation['id'] = inv.id
139 566cd8b2 Georgios Gousios
140 e6d6603a Georgios Gousios
        invitations.append(invitation)
141 566cd8b2 Georgios Gousios
142 e6d6603a Georgios Gousios
    return invitations
143 03e70572 Georgios Gousios
144 f1bb3880 Georgios Gousios
145 a640b50d Georgios Gousios
@csrf_protect
146 03e70572 Georgios Gousios
def inv_demux(request):
147 3b09ff22 Georgios Gousios
148 03e70572 Georgios Gousios
    if request.method == 'GET':
149 566cd8b2 Georgios Gousios
        data = render_to_string('invitations.html',
150 c00e4507 Vangelis Koukis
                                {'invitations':
151 c00e4507 Vangelis Koukis
                                     invitations_for_user(request),
152 c00e4507 Vangelis Koukis
                                 'invitations_left':
153 c00e4507 Vangelis Koukis
                                     get_invitations_left(request.user)},
154 a640b50d Georgios Gousios
                                context_instance=RequestContext(request))
155 c00e4507 Vangelis Koukis
        return HttpResponse(data)
156 03e70572 Georgios Gousios
    elif request.method == 'POST':
157 e6d6603a Georgios Gousios
        return process_form(request)
158 03e70572 Georgios Gousios
    else:
159 03e70572 Georgios Gousios
        method_not_allowed(request)
160 03e70572 Georgios Gousios
161 33e00f02 Georgios Gousios
162 3b09ff22 Georgios Gousios
def login(request):
163 3b09ff22 Georgios Gousios
164 3b09ff22 Georgios Gousios
    if not request.method == 'GET':
165 3b09ff22 Georgios Gousios
        method_not_allowed(request)
166 3b09ff22 Georgios Gousios
167 4af67649 Giorgos Verigakis
    key = request.GET.get('key', None)
168 3b09ff22 Georgios Gousios
169 3b09ff22 Georgios Gousios
    if key is None:
170 914502af Georgios Gousios
        return render_login_error("10", "Required key is missing")
171 3b09ff22 Georgios Gousios
172 3b09ff22 Georgios Gousios
    PADDING = '{'
173 3b09ff22 Georgios Gousios
174 68a77896 Georgios Gousios
    try:
175 914502af Georgios Gousios
        DecodeAES = lambda c, e: c.decrypt(base64.b64decode(e)).rstrip(PADDING)
176 914502af Georgios Gousios
        cipher = AES.new(settings.INVITATION_ENCR_KEY)
177 914502af Georgios Gousios
        decoded = DecodeAES(cipher, key)
178 914502af Georgios Gousios
    except Exception:
179 914502af Georgios Gousios
        return render_login_error("20", "Required key is invalid")
180 3b09ff22 Georgios Gousios
181 c00e4507 Vangelis Koukis
    users = SynnefoUser.objects.filter(auth_token=decoded)
182 3b09ff22 Georgios Gousios
183 3b09ff22 Georgios Gousios
    if users.count() is 0:
184 914502af Georgios Gousios
        return render_login_error("20", "Required key is invalid")
185 3b09ff22 Georgios Gousios
186 3b09ff22 Georgios Gousios
    user = users[0]
187 c00e4507 Vangelis Koukis
    invitations = Invitations.objects.filter(target=user)
188 3b09ff22 Georgios Gousios
189 3b09ff22 Georgios Gousios
    if invitations.count() is 0:
190 914502af Georgios Gousios
        return render_login_error("30", "Non-existent invitation")
191 f1bb3880 Georgios Gousios
192 3b09ff22 Georgios Gousios
    inv = invitations[0]
193 3b09ff22 Georgios Gousios
194 0fbab7db Vangelis Koukis
    valid = timedelta(days=settings.INVITATION_VALID_DAYS)
195 3b09ff22 Georgios Gousios
    valid_until = inv.created + valid
196 0fbab7db Vangelis Koukis
    now = datetime.datetime.now()
197 3b09ff22 Georgios Gousios
198 0fbab7db Vangelis Koukis
    if now > valid_until:
199 914502af Georgios Gousios
        return render_login_error("40",
200 0fbab7db Vangelis Koukis
                                  "Invitation has expired (was valid until " \
201 0fbab7db Vangelis Koukis
                                  "%s, now is %s" %
202 0fbab7db Vangelis Koukis
                                  (valid_until.strftime('%A, %d %B %Y'),
203 0fbab7db Vangelis Koukis
                                   now.strftime('%A, %d %B %Y')))
204 0fbab7db Vangelis Koukis
205 73d6073f Georgios Gousios
    # Since the invitation is valid, renew the user's auth token. This also
206 73d6073f Georgios Gousios
    # takes care of cases where the user re-uses the invitation to
207 73d6073f Georgios Gousios
    # login when the original token has expired
208 c00e4507 Vangelis Koukis
    from synnefo.logic import users   # redefine 'users'
209 73d6073f Georgios Gousios
    users.set_auth_token_expires(user, valid_until)
210 73d6073f Georgios Gousios
211 914502af Georgios Gousios
    #if inv.accepted == False:
212 914502af Georgios Gousios
    #    return render_login_error("60", "Invitation already accepted")
213 3b09ff22 Georgios Gousios
214 3b09ff22 Georgios Gousios
    inv.accepted = True
215 3b09ff22 Georgios Gousios
    inv.save()
216 3b09ff22 Georgios Gousios
217 c00e4507 Vangelis Koukis
    _logger.info("Invited user %s logged in", inv.target.uniq)
218 25c36228 Georgios Gousios
219 914502af Georgios Gousios
    data = dict()
220 914502af Georgios Gousios
    data['user'] = user.realname
221 914502af Georgios Gousios
    data['url'] = settings.APP_INSTALL_URL
222 914502af Georgios Gousios
223 914502af Georgios Gousios
    welcome = render_to_string('welcome.html', {'data': data})
224 914502af Georgios Gousios
225 914502af Georgios Gousios
    response = HttpResponse(welcome)
226 3b09ff22 Georgios Gousios
227 c00e4507 Vangelis Koukis
    response.set_cookie('X-Auth-Token',
228 c00e4507 Vangelis Koukis
                        value=user.auth_token,
229 c00e4507 Vangelis Koukis
                        expires=valid_until.strftime('%a, %d-%b-%Y %H:%M:%S %Z'),
230 3b09ff22 Georgios Gousios
                        path='/')
231 3b09ff22 Georgios Gousios
    response['X-Auth-Token'] = user.auth_token
232 914502af Georgios Gousios
    return response
233 914502af Georgios Gousios
234 914502af Georgios Gousios
235 914502af Georgios Gousios
def render_login_error(code, text):
236 914502af Georgios Gousios
    error = dict()
237 914502af Georgios Gousios
    error['id'] = code
238 914502af Georgios Gousios
    error['text'] = text
239 914502af Georgios Gousios
240 914502af Georgios Gousios
    data = render_to_string('error.html', {'error': error})
241 914502af Georgios Gousios
242 914502af Georgios Gousios
    response = HttpResponse(data)
243 3b09ff22 Georgios Gousios
    return response
244 3b09ff22 Georgios Gousios
245 3b09ff22 Georgios Gousios
246 3b09ff22 Georgios Gousios
def send_invitation(invitation):
247 e6d6603a Georgios Gousios
    email = {}
248 e6d6603a Georgios Gousios
    email['invitee'] = invitation.target.realname
249 e6d6603a Georgios Gousios
    email['inviter'] = invitation.source.realname
250 e6d6603a Georgios Gousios
251 c00e4507 Vangelis Koukis
    valid = timedelta(days=settings.INVITATION_VALID_DAYS)
252 e6d6603a Georgios Gousios
    valid_until = invitation.created + valid
253 e6d6603a Georgios Gousios
    email['valid_until'] = valid_until.strftime('%A, %d %B %Y')
254 e8fe75a8 Georgios Gousios
    email['url'] = enconde_inv_url(invitation)
255 e6d6603a Georgios Gousios
256 e6d6603a Georgios Gousios
    data = render_to_string('invitation.txt', {'email': email})
257 3b09ff22 Georgios Gousios
258 844ff4db Georgios Gousios
    _logger.debug("Invitation URL: %s" % email['url'])
259 844ff4db Georgios Gousios
260 670a350a Georgios Gousios
    # send_async(
261 670a350a Georgios Gousios
    #    frm = "%s"%(settings.DEFAULT_FROM_EMAIL),
262 670a350a Georgios Gousios
    #    to = "%s <%s>"%(invitation.target.realname,invitation.target.uniq),
263 670a350a Georgios Gousios
    #    subject = _('Invitation to ~okeanos IaaS service'),
264 670a350a Georgios Gousios
    #    body = data
265 670a350a Georgios Gousios
    #)
266 c00e4507 Vangelis Koukis
    send(recipient="%s <%s>" % (invitation.target.realname,
267 c00e4507 Vangelis Koukis
                                invitation.target.uniq),
268 c00e4507 Vangelis Koukis
         subject=_('Invitation to ~okeanos IaaS service'),
269 c00e4507 Vangelis Koukis
         body=data)
270 f1bb3880 Georgios Gousios
271 670a350a Georgios Gousios
272 e8fe75a8 Georgios Gousios
def enconde_inv_url(invitation):
273 e8fe75a8 Georgios Gousios
    PADDING = '{'
274 e8fe75a8 Georgios Gousios
    pad = lambda s: s + (32 - len(s) % 32) * PADDING
275 e8fe75a8 Georgios Gousios
    EncodeAES = lambda c, s: base64.b64encode(c.encrypt(pad(s)))
276 e8fe75a8 Georgios Gousios
277 e8fe75a8 Georgios Gousios
    cipher = AES.new(settings.INVITATION_ENCR_KEY)
278 e8fe75a8 Georgios Gousios
    encoded = EncodeAES(cipher, invitation.target.auth_token)
279 e8fe75a8 Georgios Gousios
280 e8fe75a8 Georgios Gousios
    url_safe = urllib.urlencode({'key': encoded})
281 e8fe75a8 Georgios Gousios
    url = settings.APP_INSTALL_URL + "/invitations/login?" + url_safe
282 e8fe75a8 Georgios Gousios
283 e8fe75a8 Georgios Gousios
    return url
284 4f8e7c6d Georgios Gousios
285 4f8e7c6d Georgios Gousios
286 4f8e7c6d Georgios Gousios
def resend(request):
287 4f8e7c6d Georgios Gousios
    """
288 4f8e7c6d Georgios Gousios
    Resend an invitation that has been already sent
289 4f8e7c6d Georgios Gousios
    """
290 4f8e7c6d Georgios Gousios
291 4f8e7c6d Georgios Gousios
    if not request.method == 'POST':
292 4f8e7c6d Georgios Gousios
        return method_not_allowed(request)
293 4f8e7c6d Georgios Gousios
294 4f8e7c6d Georgios Gousios
    invid = request.POST["invid"]
295 4f8e7c6d Georgios Gousios
296 4f8e7c6d Georgios Gousios
    matcher = re.compile('^[0-9]+$')
297 4f8e7c6d Georgios Gousios
298 4f8e7c6d Georgios Gousios
    # XXX: Assumes numeric DB keys
299 4f8e7c6d Georgios Gousios
    if not matcher.match(invid):
300 4f8e7c6d Georgios Gousios
        return HttpResponseBadRequest("Invalid content for parameter [invid]")
301 4f8e7c6d Georgios Gousios
302 4f8e7c6d Georgios Gousios
    try:
303 c00e4507 Vangelis Koukis
        inv = Invitations.objects.get(id=invid)
304 4f8e7c6d Georgios Gousios
    except Exception:
305 4f8e7c6d Georgios Gousios
        return HttpResponseBadRequest("Invitation to resend does not exist")
306 4f8e7c6d Georgios Gousios
307 4f8e7c6d Georgios Gousios
    if not request.user == inv.source:
308 4f8e7c6d Georgios Gousios
        return HttpResponseBadRequest("Invitation does not belong to user")
309 4f8e7c6d Georgios Gousios
310 4f8e7c6d Georgios Gousios
    try:
311 4f8e7c6d Georgios Gousios
        send_invitation(inv)
312 4ac7f421 Georgios Gousios
    except Exception as e:
313 4ac7f421 Georgios Gousios
        _logger.exception(e)
314 4f8e7c6d Georgios Gousios
        return HttpResponseServerError("Error sending invitation email")
315 4f8e7c6d Georgios Gousios
316 4f8e7c6d Georgios Gousios
    return HttpResponse("Invitation has been resent")
317 e8fe75a8 Georgios Gousios
318 c00e4507 Vangelis Koukis
319 9f8ad4c5 Georgios Gousios
def get_invitee_level(source):
320 9f8ad4c5 Georgios Gousios
    return get_user_inv_level(source) + 1
321 9f8ad4c5 Georgios Gousios
322 9f8ad4c5 Georgios Gousios
323 9f8ad4c5 Georgios Gousios
def get_user_inv_level(u):
324 c00e4507 Vangelis Koukis
    inv = Invitations.objects.filter(target=u)
325 9f8ad4c5 Georgios Gousios
326 cf8482f2 Giorgos Verigakis
    if not inv:
327 9f8ad4c5 Georgios Gousios
        raise Exception("User without invitation", u)
328 9f8ad4c5 Georgios Gousios
329 9f8ad4c5 Georgios Gousios
    return inv[0].level
330 9f8ad4c5 Georgios Gousios
331 9f8ad4c5 Georgios Gousios
332 03e70572 Georgios Gousios
@transaction.commit_on_success
333 03e70572 Georgios Gousios
def add_invitation(source, name, email):
334 03e70572 Georgios Gousios
    """
335 03e70572 Georgios Gousios
        Adds an invitation, if the source user has not gone over his/her
336 33e00f02 Georgios Gousios
        invitation limit or the target user has not been invited already
337 03e70572 Georgios Gousios
    """
338 c00e4507 Vangelis Koukis
    num_inv = Invitations.objects.filter(source=source).count()
339 03e70572 Georgios Gousios
340 33e00f02 Georgios Gousios
    if num_inv >= source.max_invitations:
341 d652580d Georgios Gousios
        raise TooManyInvitations("User invitation limit (%d) exhausted" %
342 33e00f02 Georgios Gousios
                                 source.max_invitations)
343 03e70572 Georgios Gousios
344 c00e4507 Vangelis Koukis
    target = SynnefoUser.objects.filter(uniq=email)
345 03e70572 Georgios Gousios
346 03e70572 Georgios Gousios
    if target.count() is not 0:
347 f1bb3880 Georgios Gousios
        raise AlreadyInvited("User with email %s already invited" % (email))
348 03e70572 Georgios Gousios
349 53e6717b Georgios Gousios
    users.register_user(name, email)
350 53e6717b Georgios Gousios
351 c00e4507 Vangelis Koukis
    target = SynnefoUser.objects.filter(uniq=email)
352 53e6717b Georgios Gousios
353 53e6717b Georgios Gousios
    r = list(target[:1])
354 53e6717b Georgios Gousios
    if not r:
355 bd1548a7 Georgios Gousios
        raise Exception("Invited user cannot be added")
356 03e70572 Georgios Gousios
357 9f8ad4c5 Georgios Gousios
    u = target[0]
358 9f8ad4c5 Georgios Gousios
    invitee_level = get_invitee_level(source)
359 9f8ad4c5 Georgios Gousios
360 9f8ad4c5 Georgios Gousios
    u.max_invitations = settings.INVITATIONS_PER_LEVEL[invitee_level]
361 9f8ad4c5 Georgios Gousios
    u.save()
362 9f8ad4c5 Georgios Gousios
363 03e70572 Georgios Gousios
    inv = Invitations()
364 03e70572 Georgios Gousios
    inv.source = source
365 9f8ad4c5 Georgios Gousios
    inv.target = u
366 9f8ad4c5 Georgios Gousios
    inv.level = invitee_level
367 03e70572 Georgios Gousios
    inv.save()
368 e6d6603a Georgios Gousios
    return inv
369 03e70572 Georgios Gousios
370 c00e4507 Vangelis Koukis
371 8f50f91c Kostas Papadimitriou
def get_invitations_left(user):
372 8f50f91c Kostas Papadimitriou
    """
373 8f50f91c Kostas Papadimitriou
    Get user invitations left
374 8f50f91c Kostas Papadimitriou
    """
375 c00e4507 Vangelis Koukis
    num_inv = Invitations.objects.filter(source=user).count()
376 8f50f91c Kostas Papadimitriou
    return user.max_invitations - num_inv
377 8f50f91c Kostas Papadimitriou
378 c00e4507 Vangelis Koukis
379 847a3ecf Georgios Gousios
def remove_invitation(invitation):
380 847a3ecf Georgios Gousios
    """
381 847a3ecf Georgios Gousios
    Removes an invitation and the invited user
382 847a3ecf Georgios Gousios
    """
383 847a3ecf Georgios Gousios
    if invitation is not None:
384 ee60bb36 Georgios Gousios
        if isinstance(invitation, Invitations):
385 ee60bb36 Georgios Gousios
            if invitation.target is not None:
386 ee60bb36 Georgios Gousios
                invitation.target.delete()
387 ee60bb36 Georgios Gousios
            invitation.delete()
388 847a3ecf Georgios Gousios
389 c00e4507 Vangelis Koukis
390 d028ab18 Georgios Gousios
class InvitationException(Exception):
391 a640b50d Georgios Gousios
    def __init__(self, msg):
392 d53bbf68 Georgios Gousios
        self.messages = [msg]
393 03e70572 Georgios Gousios
394 c00e4507 Vangelis Koukis
395 d53bbf68 Georgios Gousios
class TooManyInvitations(InvitationException):
396 d53bbf68 Georgios Gousios
    pass
397 03e70572 Georgios Gousios
398 c00e4507 Vangelis Koukis
399 d028ab18 Georgios Gousios
class AlreadyInvited(InvitationException):
400 d53bbf68 Georgios Gousios
    pass