]> git.ipfire.org Git - ipfire.org.git/blame - src/web/people.py
people: Try to store address better in LDAP
[ipfire.org.git] / src / web / people.py
CommitLineData
2cd9af74
MT
1#!/usr/bin/python
2
bdaf6b46 3import datetime
e96e445b 4import ldap
2cd9af74 5import logging
0d1fb712 6import sshpubkeys
2cd9af74
MT
7import tornado.web
8
0099c2a7
MT
9from .. import countries
10
9b8ff27d 11from . import auth
124a8404 12from . import base
786e9ca8
MT
13from . import ui_modules
14
9b8ff27d 15class IndexHandler(auth.CacheMixin, base.BaseHandler):
786e9ca8
MT
16 @tornado.web.authenticated
17 def get(self):
18 self.render("people/index.html")
19
2cd9af74 20
c4f1a618 21class AvatarHandler(base.BaseHandler):
0cddf220 22 def get(self, uid):
2cd9af74
MT
23 # Get the desired size of the avatar file
24 size = self.get_argument("size", 0)
25
26 try:
27 size = int(size)
28 except (TypeError, ValueError):
29 size = None
30
0cddf220 31 logging.debug("Querying for avatar of %s" % uid)
2cd9af74 32
f6ed3d4d 33 # Fetch user account
0cddf220 34 account = self.backend.accounts.get_by_uid(uid)
f6ed3d4d 35 if not account:
0cddf220 36 raise tornado.web.HTTPError(404, "Could not find account %s" % uid)
2cd9af74 37
f6ed3d4d
MT
38 # Allow downstream to cache this for 60 minutes
39 self.set_expires(3600)
2cd9af74 40
f6ed3d4d
MT
41 # Resize avatar
42 avatar = account.get_avatar(size)
2cd9af74 43
f6ed3d4d
MT
44 # If there is no avatar, we serve a default image
45 if not avatar:
0cddf220
MT
46 logging.debug("No avatar uploaded for %s" % account)
47
3f9f12f0 48 return self.redirect(self.static_url("img/default-avatar.jpg"))
2cd9af74 49
f6ed3d4d 50 # Set headers about content
0cddf220 51 self.set_header("Content-Disposition", "inline; filename=\"%s.jpg\"" % account.uid)
2cd9af74
MT
52 self.set_header("Content-Type", "image/jpeg")
53
f6ed3d4d 54 # Deliver payload
2cd9af74 55 self.finish(avatar)
786e9ca8
MT
56
57
9b8ff27d 58class CallsHandler(auth.CacheMixin, base.BaseHandler):
bdaf6b46
MT
59 @tornado.web.authenticated
60 def get(self, uid, date=None):
61 account = self.backend.accounts.get_by_uid(uid)
62 if not account:
63 raise tornado.web.HTTPError(404, "Could not find account %s" % uid)
64
65 if date:
44b4640b
MT
66 try:
67 date = datetime.datetime.strptime(date, "%Y-%m-%d").date()
68 except ValueError:
69 raise tornado.web.HTTPError(400, "Invalid date: %s" % date)
bdaf6b46
MT
70 else:
71 date = datetime.date.today()
72
73 self.render("people/calls.html", account=account, date=date)
74
75
9b8ff27d 76class CallHandler(auth.CacheMixin, base.BaseHandler):
68ece434
MT
77 @tornado.web.authenticated
78 def get(self, uid, uuid):
d09d554b
MT
79 account = self.backend.accounts.get_by_uid(uid)
80 if not account:
81 raise tornado.web.HTTPError(404, "Could not find account %s" % uid)
82
68ece434
MT
83 call = self.backend.talk.freeswitch.get_call_by_uuid(uuid)
84 if not call:
85 raise tornado.web.HTTPError(404, "Could not find call %s" % uuid)
86
87 # XXX limit
88
d09d554b 89 self.render("people/call.html", account=account, call=call)
68ece434
MT
90
91
9b8ff27d 92class ConferencesHandler(auth.CacheMixin, base.BaseHandler):
30aeccdb
MT
93 @tornado.web.authenticated
94 def get(self):
95 self.render("people/conferences.html", conferences=self.backend.talk.conferences)
96
97
9b8ff27d 98class SearchHandler(auth.CacheMixin, base.BaseHandler):
786e9ca8
MT
99 @tornado.web.authenticated
100 def get(self):
101 q = self.get_argument("q")
102
103 # Perform the search
51907e45 104 accounts = self.backend.accounts.search(q)
786e9ca8
MT
105
106 # Redirect when only one result was found
107 if len(accounts) == 1:
108 self.redirect("/users/%s" % accounts[0].uid)
109 return
110
111 self.render("people/search.html", q=q, accounts=accounts)
112
f4672785 113
9b8ff27d 114class SSHKeysIndexHandler(auth.CacheMixin, base.BaseHandler):
f4672785
MT
115 @tornado.web.authenticated
116 def get(self, uid):
117 account = self.backend.accounts.get_by_uid(uid)
118 if not account:
119 raise tornado.web.HTTPError(404, "Could not find account %s" % uid)
120
121 self.render("people/ssh-keys/index.html", account=account)
122
55b67ca4 123
9b8ff27d 124class SSHKeysDownloadHandler(auth.CacheMixin, base.BaseHandler):
55b67ca4 125 @tornado.web.authenticated
44b75370 126 def get(self, uid, hash_sha256):
55b67ca4
MT
127 account = self.backend.accounts.get_by_uid(uid)
128 if not account:
129 raise tornado.web.HTTPError(404, "Could not find account %s" % uid)
130
131 # Get SSH key
44b75370 132 key = account.get_ssh_key_by_hash_sha256(hash_sha256)
55b67ca4 133 if not key:
44b75370 134 raise tornado.web.HTTPError(404, "Could not find key: %s" % hash_sha256)
55b67ca4
MT
135
136 # Set HTTP Headers
137 self.add_header("Content-Type", "text/plain")
138
139 self.finish(key.keydata)
140
0d1fb712 141
9b8ff27d 142class SSHKeysUploadHandler(auth.CacheMixin, base.BaseHandler):
0d1fb712
MT
143 @tornado.web.authenticated
144 def get(self, uid):
145 account = self.backend.accounts.get_by_uid(uid)
146 if not account:
147 raise tornado.web.HTTPError(404, "Could not find account %s" % uid)
148
149 # Check for permissions
150 if not account.can_be_managed_by(self.current_user):
151 raise tornado.web.HTTPError(403, "%s cannot manage %s" % (self.current_user, account))
152
153 self.render("people/ssh-keys/upload.html", account=account)
154
155 @tornado.web.authenticated
156 def post(self, uid):
157 account = self.backend.accounts.get_by_uid(uid)
158 if not account:
159 raise tornado.web.HTTPError(404, "Could not find account %s" % uid)
160
161 # Check for permissions
162 if not account.can_be_managed_by(self.current_user):
163 raise tornado.web.HTTPError(403, "%s cannot manage %s" % (self.current_user, account))
164
165 key = self.get_argument("key")
166
167 # Verify password
168 password = self.get_argument("password")
169 if not account.check_password(password):
170 raise tornado.web.HTTPError(403, "Incorrect password for %s" % account)
171
172 # Try to add new SSH key
173 try:
174 account.add_ssh_key(key)
175
176 except sshpubkeys.InvalidKeyException as e:
177 self.render("people/ssh-keys/error-invalid-key.html", account=account, exception=e)
178 return
179
180 self.redirect("/users/%s/ssh-keys" % account.uid)
181
182
9b8ff27d 183class SSHKeysDeleteHandler(auth.CacheMixin, base.BaseHandler):
0d1fb712 184 @tornado.web.authenticated
44b75370 185 def get(self, uid, hash_sha256):
0d1fb712
MT
186 account = self.backend.accounts.get_by_uid(uid)
187 if not account:
188 raise tornado.web.HTTPError(404, "Could not find account %s" % uid)
189
190 # Get SSH key
44b75370 191 key = account.get_ssh_key_by_hash_sha256(hash_sha256)
0d1fb712 192 if not key:
44b75370 193 raise tornado.web.HTTPError(404, "Could not find key: %s" % hash_sha256)
0d1fb712
MT
194
195 self.render("people/ssh-keys/delete.html", account=account, key=key)
196
197 @tornado.web.authenticated
44b75370 198 def post(self, uid, hash_sha256):
0d1fb712
MT
199 account = self.backend.accounts.get_by_uid(uid)
200 if not account:
201 raise tornado.web.HTTPError(404, "Could not find account %s" % uid)
202
203 # Get SSH key
44b75370 204 key = account.get_ssh_key_by_hash_sha256(hash_sha256)
0d1fb712 205 if not key:
44b75370 206 raise tornado.web.HTTPError(404, "Could not find key: %s" % hash_sha256)
0d1fb712
MT
207
208 # Verify password
209 password = self.get_argument("password")
210 if not account.check_password(password):
211 raise tornado.web.HTTPError(403, "Incorrect password for %s" % account)
212
213 # Delete the key
214 account.delete_ssh_key(key.keydata)
215
216 self.redirect("/users/%s/ssh-keys" % account.uid)
217
786e9ca8 218
9b8ff27d 219class SIPHandler(auth.CacheMixin, base.BaseHandler):
e0daee8f
MT
220 @tornado.web.authenticated
221 def get(self, uid):
222 account = self.backend.accounts.get_by_uid(uid)
223 if not account:
224 raise tornado.web.HTTPError(404, "Could not find account %s" % uid)
225
226 # Check for permissions
227 if not account.can_be_managed_by(self.current_user):
228 raise tornado.web.HTTPError(403, "%s cannot manage %s" % (self.current_user, account))
229
230 self.render("people/sip.html", account=account)
231
232
9b8ff27d 233class UsersHandler(auth.CacheMixin, base.BaseHandler):
786e9ca8
MT
234 @tornado.web.authenticated
235 def get(self):
71a3109c
MT
236 # Only staff can see other users
237 if not self.current_user.is_staff():
238 raise tornado.web.HTTPError(403)
239
786e9ca8
MT
240 self.render("people/users.html")
241
242
9b8ff27d 243class UserHandler(auth.CacheMixin, base.BaseHandler):
786e9ca8
MT
244 @tornado.web.authenticated
245 def get(self, uid):
246 account = self.backend.accounts.get_by_uid(uid)
247 if not account:
248 raise tornado.web.HTTPError(404, "Could not find account %s" % uid)
249
250 self.render("people/user.html", account=account)
251
252
9b8ff27d 253class UserEditHandler(auth.CacheMixin, base.BaseHandler):
e96e445b
MT
254 @tornado.web.authenticated
255 def get(self, uid):
256 account = self.backend.accounts.get_by_uid(uid)
257 if not account:
258 raise tornado.web.HTTPError(404, "Could not find account %s" % uid)
259
260 # Check for permissions
261 if not account.can_be_managed_by(self.current_user):
262 raise tornado.web.HTTPError(403, "%s cannot manage %s" % (self.current_user, account))
263
0099c2a7 264 self.render("people/user-edit.html", account=account, countries=countries.get_all())
e96e445b
MT
265
266 @tornado.web.authenticated
267 def post(self, uid):
268 account = self.backend.accounts.get_by_uid(uid)
269 if not account:
270 raise tornado.web.HTTPError(404, "Could not find account %s" % uid)
271
272 # Check for permissions
273 if not account.can_be_managed_by(self.current_user):
274 raise tornado.web.HTTPError(403, "%s cannot manage %s" % (self.current_user, account))
275
276 # Unfortunately this cannot be wrapped into a transaction
277 try:
0099c2a7
MT
278 account.first_name = self.get_argument("first_name")
279 account.last_name = self.get_argument("last_name")
280 account.street = self.get_argument("street", None)
281 account.city = self.get_argument("city", None)
282 account.postal_code = self.get_argument("postal_code", None)
283 account.country_code = self.get_argument("country_code", None)
e96e445b 284
5cc10421
MT
285 # Avatar
286 try:
287 filename, data, mimetype = self.get_file("avatar")
288
289 if not mimetype.startswith("image/"):
290 raise tornado.web.HTTPError(400, "Avatar is not an image file: %s" % mimetype)
291
292 account.upload_avatar(data)
9bbf48b8 293 except TypeError:
5cc10421
MT
294 pass
295
e96e445b
MT
296 # Email
297 account.mail_routing_address = self.get_argument("mail_routing_address", None)
298
299 # Telephone
300 account.phone_numbers = self.get_argument("phone_numbers", "").splitlines()
301 account.sip_routing_address = self.get_argument("sip_routing_address", None)
302 except ldap.STRONG_AUTH_REQUIRED as e:
303 raise tornado.web.HTTPError(403, "%s" % e) from e
304
305 # Redirect back to user page
306 self.redirect("/users/%s" % account.uid)
307
308
9b8ff27d 309class UserPasswdHandler(auth.CacheMixin, base.BaseHandler):
3ea97943
MT
310 @tornado.web.authenticated
311 def get(self, uid):
312 account = self.backend.accounts.get_by_uid(uid)
313 if not account:
314 raise tornado.web.HTTPError(404, "Could not find account %s" % uid)
315
316 # Check for permissions
317 if not account.can_be_managed_by(self.current_user):
318 raise tornado.web.HTTPError(403, "%s cannot manage %s" % (self.current_user, account))
319
320 self.render("people/passwd.html", account=account)
321
322 @tornado.web.authenticated
323 def post(self, uid):
324 account = self.backend.accounts.get_by_uid(uid)
325 if not account:
326 raise tornado.web.HTTPError(404, "Could not find account %s" % uid)
327
328 # Check for permissions
329 if not account.can_be_managed_by(self.current_user):
330 raise tornado.web.HTTPError(403, "%s cannot manage %s" % (self.current_user, account))
331
332 # Get current password
333 password = self.get_argument("password")
334
335 # Get new password
336 password1 = self.get_argument("password1")
337 password2 = self.get_argument("password2")
338
339 # Passwords must match
340 if not password1 == password2:
341 raise tornado.web.HTTPError(400, "Passwords do not match")
342
343 # XXX Check password complexity
344
345 # Check if old password matches
346 if not account.check_password(password):
347 raise tornado.web.HTTPError(403, "Incorrect password for %s" % account)
348
349 # Save new password
350 account.passwd(password1)
351
352 # Redirect back to user's page
353 self.redirect("/users/%s" % account.uid)
354
355
786e9ca8
MT
356class AccountsListModule(ui_modules.UIModule):
357 def render(self, accounts=None):
358 if accounts is None:
51907e45 359 accounts = self.backend.accounts
786e9ca8
MT
360
361 return self.render_string("people/modules/accounts-list.html", accounts=accounts)
362
363
364class CDRModule(ui_modules.UIModule):
bdaf6b46
MT
365 def render(self, account, date=None, limit=None):
366 cdr = account.get_cdr(date=date, limit=limit)
786e9ca8 367
89e47299
MT
368 return self.render_string("people/modules/cdr.html",
369 account=account, cdr=list(cdr))
786e9ca8
MT
370
371
372class ChannelsModule(ui_modules.UIModule):
373 def render(self, account):
1f38be5a
MT
374 return self.render_string("people/modules/channels.html",
375 account=account, channels=account.sip_channels)
786e9ca8
MT
376
377
68ece434
MT
378class MOSModule(ui_modules.UIModule):
379 def render(self, call):
380 return self.render_string("people/modules/mos.html", call=call)
381
382
b5e2077f
MT
383class PasswordModule(ui_modules.UIModule):
384 def render(self, account):
385 return self.render_string("people/modules/password.html", account=account)
386
387 def javascript_files(self):
388 return "js/zxcvbn.js"
389
390 def embedded_javascript(self):
391 return self.render_string("people/modules/password.js")
392
393
786e9ca8
MT
394class RegistrationsModule(ui_modules.UIModule):
395 def render(self, account):
396 return self.render_string("people/modules/registrations.html", account=account)
7afd64bb
MT
397
398
399class SIPStatusModule(ui_modules.UIModule):
400 def render(self, account):
401 return self.render_string("people/modules/sip-status.html", account=account)