Statistics
| Branch: | Tag: | Revision:

root / invitations / invitations.py @ bd1548a7

History | View | Annotate | Download (7.3 kB)

1 f1bb3880 Georgios Gousios
# vim: set fileencoding=utf-8 :
2 e6d6603a Georgios Gousios
from datetime import timedelta
3 e6d6603a Georgios Gousios
import base64
4 3b09ff22 Georgios Gousios
import time
5 3b09ff22 Georgios Gousios
import urllib
6 e6d6603a Georgios Gousios
7 03e70572 Georgios Gousios
from django.conf import settings
8 566cd8b2 Georgios Gousios
from django.core.exceptions import ValidationError
9 03e70572 Georgios Gousios
from django.db import transaction
10 03e70572 Georgios Gousios
from django.http import HttpResponse, HttpResponseRedirect
11 a640b50d Georgios Gousios
from django.template.context import RequestContext
12 2a0eee64 Georgios Gousios
from django.template.loader import render_to_string
13 566cd8b2 Georgios Gousios
from django.core.validators import validate_email
14 a640b50d Georgios Gousios
from django.views.decorators.csrf import csrf_protect
15 f1bb3880 Georgios Gousios
from synnefo.logic.email import send_async
16 566cd8b2 Georgios Gousios
17 03e70572 Georgios Gousios
from synnefo.api.common import method_not_allowed
18 03e70572 Georgios Gousios
from synnefo.db.models import Invitations, SynnefoUser
19 03e70572 Georgios Gousios
from synnefo.logic import users
20 e6d6603a Georgios Gousios
21 e6d6603a Georgios Gousios
from Crypto.Cipher import AES
22 03e70572 Georgios Gousios
23 f1bb3880 Georgios Gousios
24 e6d6603a Georgios Gousios
def process_form(request):
25 a640b50d Georgios Gousios
    errors = []
26 566cd8b2 Georgios Gousios
    valid_inv = filter(lambda x: x.startswith("name_"), request.POST.keys())
27 566cd8b2 Georgios Gousios
28 566cd8b2 Georgios Gousios
    for inv in valid_inv:
29 566cd8b2 Georgios Gousios
        (name, inv_id) = inv.split('_')
30 566cd8b2 Georgios Gousios
31 566cd8b2 Georgios Gousios
        try:
32 566cd8b2 Georgios Gousios
            email = request.POST['email_' + inv_id]
33 566cd8b2 Georgios Gousios
            name = request.POST[inv]
34 566cd8b2 Georgios Gousios
35 566cd8b2 Georgios Gousios
            validate_name(name)
36 a640b50d Georgios Gousios
            validate_email(email)
37 a640b50d Georgios Gousios
38 e6d6603a Georgios Gousios
            inv = add_invitation(request.user, name, email)
39 3b09ff22 Georgios Gousios
            send_invitation(inv)
40 a640b50d Georgios Gousios
41 566cd8b2 Georgios Gousios
        except Exception as e:
42 f1bb3880 Georgios Gousios
            try :
43 f1bb3880 Georgios Gousios
                errors += ["Invitation to %s <%s> not sent. Reason: %s"%(name, email, e.messages[0])]
44 f1bb3880 Georgios Gousios
            except:
45 f1bb3880 Georgios Gousios
                errors += ["Invitation to %s <%s> not sent. Reason: %s"%(name, email, e.message)]
46 a640b50d Georgios Gousios
47 a640b50d Georgios Gousios
    respose = None
48 a640b50d Georgios Gousios
    if errors:
49 a640b50d Georgios Gousios
        data = render_to_string('invitations.html',
50 a640b50d Georgios Gousios
                                {'invitations': invitations_for_user(request),
51 a640b50d Georgios Gousios
                                 'errors': errors},
52 a640b50d Georgios Gousios
                                context_instance=RequestContext(request))
53 a640b50d Georgios Gousios
        response =  HttpResponse(data)
54 a640b50d Georgios Gousios
    else:
55 a640b50d Georgios Gousios
        response = HttpResponseRedirect("/invitations/")
56 566cd8b2 Georgios Gousios
57 566cd8b2 Georgios Gousios
    return response
58 566cd8b2 Georgios Gousios
59 f1bb3880 Georgios Gousios
60 566cd8b2 Georgios Gousios
def validate_name(name):
61 566cd8b2 Georgios Gousios
    if name is None or name.strip() == '' :
62 a640b50d Georgios Gousios
        raise ValidationError("Name is empty")
63 a640b50d Georgios Gousios
64 a640b50d Georgios Gousios
    if name.find(' ') is -1:
65 a640b50d Georgios Gousios
        raise ValidationError("Name must contain at least one space")
66 03e70572 Georgios Gousios
67 566cd8b2 Georgios Gousios
    return True
68 566cd8b2 Georgios Gousios
69 f1bb3880 Georgios Gousios
70 566cd8b2 Georgios Gousios
def invitations_for_user(request):
71 566cd8b2 Georgios Gousios
    invitations = []
72 566cd8b2 Georgios Gousios
73 566cd8b2 Georgios Gousios
    for inv in Invitations.objects.filter(source = request.user):
74 e6d6603a Georgios Gousios
        invitation = {}
75 566cd8b2 Georgios Gousios
76 e6d6603a Georgios Gousios
        invitation['sourcename'] = inv.source.realname
77 e6d6603a Georgios Gousios
        invitation['source'] = inv.source.uniq
78 e6d6603a Georgios Gousios
        invitation['targetname'] = inv.target.realname
79 e6d6603a Georgios Gousios
        invitation['target'] = inv.target.uniq
80 e6d6603a Georgios Gousios
        invitation['accepted'] = inv.accepted
81 e6d6603a Georgios Gousios
        invitation['sent'] = inv.created
82 566cd8b2 Georgios Gousios
83 e6d6603a Georgios Gousios
        invitations.append(invitation)
84 566cd8b2 Georgios Gousios
85 e6d6603a Georgios Gousios
    return invitations
86 03e70572 Georgios Gousios
87 f1bb3880 Georgios Gousios
88 a640b50d Georgios Gousios
@csrf_protect
89 03e70572 Georgios Gousios
def inv_demux(request):
90 3b09ff22 Georgios Gousios
91 03e70572 Georgios Gousios
    if request.method == 'GET':
92 566cd8b2 Georgios Gousios
        data = render_to_string('invitations.html',
93 a640b50d Georgios Gousios
                                {'invitations': invitations_for_user(request)},
94 a640b50d Georgios Gousios
                                context_instance=RequestContext(request))
95 03e70572 Georgios Gousios
        return  HttpResponse(data)
96 03e70572 Georgios Gousios
    elif request.method == 'POST':
97 e6d6603a Georgios Gousios
        return process_form(request)
98 03e70572 Georgios Gousios
    else:
99 03e70572 Georgios Gousios
        method_not_allowed(request)
100 03e70572 Georgios Gousios
101 3b09ff22 Georgios Gousios
def login(request):
102 3b09ff22 Georgios Gousios
103 3b09ff22 Georgios Gousios
    if not request.method == 'GET':
104 3b09ff22 Georgios Gousios
        method_not_allowed(request)
105 3b09ff22 Georgios Gousios
106 3b09ff22 Georgios Gousios
    key = request.GET['key']
107 3b09ff22 Georgios Gousios
108 3b09ff22 Georgios Gousios
    if key is None:
109 914502af Georgios Gousios
        return render_login_error("10", "Required key is missing")
110 3b09ff22 Georgios Gousios
111 3b09ff22 Georgios Gousios
    PADDING = '{'
112 3b09ff22 Georgios Gousios
113 914502af Georgios Gousios
    try :
114 914502af Georgios Gousios
        DecodeAES = lambda c, e: c.decrypt(base64.b64decode(e)).rstrip(PADDING)
115 914502af Georgios Gousios
        cipher = AES.new(settings.INVITATION_ENCR_KEY)
116 914502af Georgios Gousios
        decoded = DecodeAES(cipher, key)
117 914502af Georgios Gousios
    except Exception:
118 914502af Georgios Gousios
        return render_login_error("20", "Required key is invalid")
119 3b09ff22 Georgios Gousios
120 3b09ff22 Georgios Gousios
    users = SynnefoUser.objects.filter(auth_token = decoded)
121 3b09ff22 Georgios Gousios
122 3b09ff22 Georgios Gousios
    if users.count() is 0:
123 914502af Georgios Gousios
        return render_login_error("20", "Required key is invalid")
124 3b09ff22 Georgios Gousios
125 3b09ff22 Georgios Gousios
    user = users[0]
126 3b09ff22 Georgios Gousios
    invitations = Invitations.objects.filter(target = user)
127 3b09ff22 Georgios Gousios
128 3b09ff22 Georgios Gousios
    if invitations.count() is 0:
129 914502af Georgios Gousios
        return render_login_error("30", "Non-existent invitation")
130 f1bb3880 Georgios Gousios
131 3b09ff22 Georgios Gousios
    inv = invitations[0]
132 3b09ff22 Georgios Gousios
133 3b09ff22 Georgios Gousios
    valid = timedelta(days = settings.INVITATION_VALID_DAYS)
134 3b09ff22 Georgios Gousios
    valid_until = inv.created + valid
135 3b09ff22 Georgios Gousios
136 3b09ff22 Georgios Gousios
    if (time.time() -
137 3b09ff22 Georgios Gousios
        time.mktime(inv.created.timetuple()) -
138 3b09ff22 Georgios Gousios
        settings.INVITATION_VALID_DAYS * 3600) > 0:
139 914502af Georgios Gousios
        return render_login_error("40",
140 914502af Georgios Gousios
                                  "Invitation expired (was valid until %s)"%
141 914502af Georgios Gousios
                                  valid_until.strftime('%A, %d %B %Y'))
142 914502af Georgios Gousios
    #if inv.accepted == False:
143 914502af Georgios Gousios
    #    return render_login_error("60", "Invitation already accepted")
144 3b09ff22 Georgios Gousios
145 3b09ff22 Georgios Gousios
    inv.accepted = True
146 3b09ff22 Georgios Gousios
    inv.save()
147 3b09ff22 Georgios Gousios
148 914502af Georgios Gousios
    data = dict()
149 914502af Georgios Gousios
    data['user'] = user.realname
150 914502af Georgios Gousios
    data['url'] = settings.APP_INSTALL_URL
151 914502af Georgios Gousios
152 914502af Georgios Gousios
    welcome = render_to_string('welcome.html', {'data': data})
153 914502af Georgios Gousios
154 914502af Georgios Gousios
    response = HttpResponse(welcome)
155 3b09ff22 Georgios Gousios
156 3b09ff22 Georgios Gousios
    response.set_cookie('X-Auth-Token', value=user.auth_token,
157 3b09ff22 Georgios Gousios
                        expires = valid_until.strftime('%a, %d-%b-%Y %H:%M:%S %Z'),
158 3b09ff22 Georgios Gousios
                        path='/')
159 3b09ff22 Georgios Gousios
    response['X-Auth-Token'] = user.auth_token
160 914502af Georgios Gousios
    return response
161 914502af Georgios Gousios
162 914502af Georgios Gousios
163 914502af Georgios Gousios
def render_login_error(code, text):
164 914502af Georgios Gousios
    error = dict()
165 914502af Georgios Gousios
    error['id'] = code
166 914502af Georgios Gousios
    error['text'] = text
167 914502af Georgios Gousios
168 914502af Georgios Gousios
    data = render_to_string('error.html', {'error': error})
169 914502af Georgios Gousios
170 914502af Georgios Gousios
    response = HttpResponse(data)
171 3b09ff22 Georgios Gousios
    return response
172 3b09ff22 Georgios Gousios
173 3b09ff22 Georgios Gousios
174 3b09ff22 Georgios Gousios
def send_invitation(invitation):
175 e6d6603a Georgios Gousios
    email = {}
176 e6d6603a Georgios Gousios
    email['invitee'] = invitation.target.realname
177 e6d6603a Georgios Gousios
    email['inviter'] = invitation.source.realname
178 e6d6603a Georgios Gousios
179 e6d6603a Georgios Gousios
    valid = timedelta(days = settings.INVITATION_VALID_DAYS)
180 e6d6603a Georgios Gousios
    valid_until = invitation.created + valid
181 e6d6603a Georgios Gousios
    email['valid_until'] = valid_until.strftime('%A, %d %B %Y')
182 e6d6603a Georgios Gousios
183 e6d6603a Georgios Gousios
    PADDING = '{'
184 e6d6603a Georgios Gousios
    pad = lambda s: s + (32 - len(s) % 32) * PADDING
185 e6d6603a Georgios Gousios
    EncodeAES = lambda c, s: base64.b64encode(c.encrypt(pad(s)))
186 e6d6603a Georgios Gousios
187 e6d6603a Georgios Gousios
    cipher = AES.new(settings.INVITATION_ENCR_KEY)
188 e6d6603a Georgios Gousios
    encoded = EncodeAES(cipher, invitation.target.auth_token)
189 e6d6603a Georgios Gousios
190 3b09ff22 Georgios Gousios
    url_safe = urllib.urlencode({'key': encoded})
191 3b09ff22 Georgios Gousios
192 3b09ff22 Georgios Gousios
    email['url'] = settings.APP_INSTALL_URL + "/invitations/login?" + url_safe
193 e6d6603a Georgios Gousios
194 e6d6603a Georgios Gousios
    data = render_to_string('invitation.txt', {'email': email})
195 3b09ff22 Georgios Gousios
196 3b09ff22 Georgios Gousios
    print data
197 3b09ff22 Georgios Gousios
198 f1bb3880 Georgios Gousios
    send_async(
199 f1bb3880 Georgios Gousios
        frm = "%s <%s>"%(invitation.source.realname,invitation.source.uniq),
200 f1bb3880 Georgios Gousios
        to = "%s <%s>"%(invitation.target.realname,invitation.target.uniq),
201 f1bb3880 Georgios Gousios
        subject = u'Πρόσκληση για την υπηρεσία Ωκεανός',
202 f1bb3880 Georgios Gousios
        body = data
203 f1bb3880 Georgios Gousios
    )
204 f1bb3880 Georgios Gousios
205 e6d6603a Georgios Gousios
206 03e70572 Georgios Gousios
@transaction.commit_on_success
207 03e70572 Georgios Gousios
def add_invitation(source, name, email):
208 03e70572 Georgios Gousios
    """
209 03e70572 Georgios Gousios
        Adds an invitation, if the source user has not gone over his/her
210 03e70572 Georgios Gousios
        invitation count or the target user has not been invited already
211 03e70572 Georgios Gousios
    """
212 03e70572 Georgios Gousios
    num_inv = Invitations.objects.filter(source = source).count()
213 03e70572 Georgios Gousios
214 03e70572 Georgios Gousios
    if num_inv >= settings.MAX_INVITATIONS:
215 a640b50d Georgios Gousios
        raise TooManyInvitations("User invitation limit (%d) exhausted" % settings.MAX_INVITATIONS)
216 03e70572 Georgios Gousios
217 f1bb3880 Georgios Gousios
    target = SynnefoUser.objects.filter(uniq = email)
218 03e70572 Georgios Gousios
219 03e70572 Georgios Gousios
    if target.count() is not 0:
220 f1bb3880 Georgios Gousios
        raise AlreadyInvited("User with email %s already invited" % (email))
221 03e70572 Georgios Gousios
222 53e6717b Georgios Gousios
    users.register_user(name, email)
223 53e6717b Georgios Gousios
224 53e6717b Georgios Gousios
    target = SynnefoUser.objects.filter(uniq = email)
225 53e6717b Georgios Gousios
226 53e6717b Georgios Gousios
    r = list(target[:1])
227 53e6717b Georgios Gousios
    if not r:
228 bd1548a7 Georgios Gousios
        raise Exception("Invited user cannot be added")
229 03e70572 Georgios Gousios
230 03e70572 Georgios Gousios
    inv = Invitations()
231 03e70572 Georgios Gousios
    inv.source = source
232 53e6717b Georgios Gousios
    inv.target = target[0]
233 03e70572 Georgios Gousios
    inv.save()
234 e6d6603a Georgios Gousios
    return inv
235 03e70572 Georgios Gousios
236 f1bb3880 Georgios Gousios
237 03e70572 Georgios Gousios
@transaction.commit_on_success
238 03e70572 Georgios Gousios
def invitation_accepted(invitation):
239 03e70572 Georgios Gousios
    """
240 03e70572 Georgios Gousios
        Mark an invitation as accepted
241 03e70572 Georgios Gousios
    """
242 03e70572 Georgios Gousios
    invitation.accepted = True
243 03e70572 Georgios Gousios
    invitation.save()
244 03e70572 Georgios Gousios
245 03e70572 Georgios Gousios
246 a640b50d Georgios Gousios
class TooManyInvitations(Exception):
247 f1bb3880 Georgios Gousios
    messages = []
248 a640b50d Georgios Gousios
249 a640b50d Georgios Gousios
    def __init__(self, msg):
250 a640b50d Georgios Gousios
        self.messages.append(msg)
251 03e70572 Georgios Gousios
252 03e70572 Georgios Gousios
253 a640b50d Georgios Gousios
class AlreadyInvited(Exception):
254 a640b50d Georgios Gousios
    messages = []
255 03e70572 Georgios Gousios
256 03e70572 Georgios Gousios
    def __init__(self, msg):
257 a640b50d Georgios Gousios
        self.messages.append(msg)