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