]>
git.ipfire.org Git - ipfire.org.git/blob - src/web/people.py
10 from .. import countries
14 from . import ui_modules
16 class IndexHandler(auth
.CacheMixin
, base
.BaseHandler
):
17 @tornado.web
.authenticated
19 self
.render("people/index.html")
22 class AvatarHandler(base
.BaseHandler
):
24 # Get the desired size of the avatar file
25 size
= self
.get_argument("size", None)
29 except (TypeError, ValueError):
32 logging
.debug("Querying for avatar of %s" % uid
)
35 account
= self
.backend
.accounts
.get_by_uid(uid
)
37 raise tornado
.web
.HTTPError(404, "Could not find account %s" % uid
)
39 # Allow downstream to cache this for 60 minutes
40 self
.set_expires(3600)
43 avatar
= account
.get_avatar(size
)
45 # If there is no avatar, we serve a default image
47 logging
.debug("No avatar uploaded for %s" % account
)
49 return self
.redirect(self
.static_url("img/default-avatar.jpg"))
52 type = imghdr
.what(None, avatar
)
54 # Set headers about content
55 self
.set_header("Content-Disposition", "inline; filename=\"%s.%s\"" % (account
.uid
, type))
56 self
.set_header("Content-Type", "image/%s" % type)
62 class CallsHandler(auth
.CacheMixin
, base
.BaseHandler
):
63 @tornado.web
.authenticated
64 def get(self
, uid
, date
=None):
65 account
= self
.backend
.accounts
.get_by_uid(uid
)
67 raise tornado
.web
.HTTPError(404, "Could not find account %s" % uid
)
69 # Check for permissions
70 if not account
.can_be_managed_by(self
.current_user
):
71 raise tornado
.web
.HTTPError(403, "%s cannot manage %s" % (self
.current_user
, account
))
75 date
= datetime
.datetime
.strptime(date
, "%Y-%m-%d").date()
77 raise tornado
.web
.HTTPError(400, "Invalid date: %s" % date
)
79 date
= datetime
.date
.today()
81 self
.render("people/calls.html", account
=account
, date
=date
)
84 class CallHandler(auth
.CacheMixin
, base
.BaseHandler
):
85 @tornado.web
.authenticated
86 def get(self
, uid
, uuid
):
87 account
= self
.backend
.accounts
.get_by_uid(uid
)
89 raise tornado
.web
.HTTPError(404, "Could not find account %s" % uid
)
91 # Check for permissions
92 if not account
.can_be_managed_by(self
.current_user
):
93 raise tornado
.web
.HTTPError(403, "%s cannot manage %s" % (self
.current_user
, account
))
95 call
= self
.backend
.talk
.freeswitch
.get_call_by_uuid(uuid
)
97 raise tornado
.web
.HTTPError(404, "Could not find call %s" % uuid
)
101 self
.render("people/call.html", account
=account
, call
=call
)
104 class ConferencesHandler(auth
.CacheMixin
, base
.BaseHandler
):
105 @tornado.web
.authenticated
107 self
.render("people/conferences.html", conferences
=self
.backend
.talk
.conferences
)
110 class SearchHandler(auth
.CacheMixin
, base
.BaseHandler
):
111 @tornado.web
.authenticated
113 q
= self
.get_argument("q")
116 accounts
= self
.backend
.accounts
.search(q
)
118 # Redirect when only one result was found
119 if len(accounts
) == 1:
120 self
.redirect("/users/%s" % accounts
[0].uid
)
123 self
.render("people/search.html", q
=q
, accounts
=accounts
)
126 class SIPHandler(auth
.CacheMixin
, base
.BaseHandler
):
127 @tornado.web
.authenticated
129 account
= self
.backend
.accounts
.get_by_uid(uid
)
131 raise tornado
.web
.HTTPError(404, "Could not find account %s" % uid
)
133 # Check for permissions
134 if not account
.can_be_managed_by(self
.current_user
):
135 raise tornado
.web
.HTTPError(403, "%s cannot manage %s" % (self
.current_user
, account
))
137 self
.render("people/sip.html", account
=account
)
140 class UsersHandler(auth
.CacheMixin
, base
.BaseHandler
):
141 @tornado.web
.authenticated
143 # Only staff can see other users
144 if not self
.current_user
.is_staff():
145 raise tornado
.web
.HTTPError(403)
147 self
.render("people/users.html")
150 class UserHandler(auth
.CacheMixin
, base
.BaseHandler
):
151 @tornado.web
.authenticated
153 account
= self
.backend
.accounts
.get_by_uid(uid
)
155 raise tornado
.web
.HTTPError(404, "Could not find account %s" % uid
)
157 self
.render("people/user.html", account
=account
)
160 class UserEditHandler(auth
.CacheMixin
, base
.BaseHandler
):
161 @tornado.web
.authenticated
163 account
= self
.backend
.accounts
.get_by_uid(uid
)
165 raise tornado
.web
.HTTPError(404, "Could not find account %s" % uid
)
167 # Check for permissions
168 if not account
.can_be_managed_by(self
.current_user
):
169 raise tornado
.web
.HTTPError(403, "%s cannot manage %s" % (self
.current_user
, account
))
171 self
.render("people/user-edit.html", account
=account
, countries
=countries
.get_all())
173 @tornado.web
.authenticated
175 account
= self
.backend
.accounts
.get_by_uid(uid
)
177 raise tornado
.web
.HTTPError(404, "Could not find account %s" % uid
)
179 # Check for permissions
180 if not account
.can_be_managed_by(self
.current_user
):
181 raise tornado
.web
.HTTPError(403, "%s cannot manage %s" % (self
.current_user
, account
))
183 # Unfortunately this cannot be wrapped into a transaction
185 account
.first_name
= self
.get_argument("first_name")
186 account
.last_name
= self
.get_argument("last_name")
187 account
.nickname
= self
.get_argument("nickname", None)
188 account
.street
= self
.get_argument("street", None)
189 account
.city
= self
.get_argument("city", None)
190 account
.postal_code
= self
.get_argument("postal_code", None)
191 account
.country_code
= self
.get_argument("country_code", None)
195 filename
, data
, mimetype
= self
.get_file("avatar")
197 if not mimetype
.startswith("image/"):
198 raise tornado
.web
.HTTPError(400, "Avatar is not an image file: %s" % mimetype
)
200 account
.upload_avatar(data
)
205 account
.mail_routing_address
= self
.get_argument("mail_routing_address", None)
208 account
.phone_numbers
= self
.get_argument("phone_numbers", "").splitlines()
209 account
.sip_routing_address
= self
.get_argument("sip_routing_address", None)
210 except ldap
.STRONG_AUTH_REQUIRED
as e
:
211 raise tornado
.web
.HTTPError(403, "%s" % e
) from e
213 # Redirect back to user page
214 self
.redirect("/users/%s" % account
.uid
)
217 class UserPasswdHandler(auth
.CacheMixin
, base
.BaseHandler
):
218 @tornado.web
.authenticated
220 account
= self
.backend
.accounts
.get_by_uid(uid
)
222 raise tornado
.web
.HTTPError(404, "Could not find account %s" % uid
)
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
))
228 self
.render("people/passwd.html", account
=account
)
230 @tornado.web
.authenticated
232 account
= self
.backend
.accounts
.get_by_uid(uid
)
234 raise tornado
.web
.HTTPError(404, "Could not find account %s" % uid
)
236 # Check for permissions
237 if not account
.can_be_managed_by(self
.current_user
):
238 raise tornado
.web
.HTTPError(403, "%s cannot manage %s" % (self
.current_user
, account
))
240 # Get current password
241 password
= self
.get_argument("password")
244 password1
= self
.get_argument("password1")
245 password2
= self
.get_argument("password2")
247 # Passwords must match
248 if not password1
== password2
:
249 raise tornado
.web
.HTTPError(400, "Passwords do not match")
251 # XXX Check password complexity
253 # Check if old password matches
254 if not account
.check_password(password
):
255 raise tornado
.web
.HTTPError(403, "Incorrect password for %s" % account
)
258 account
.passwd(password1
)
260 # Redirect back to user's page
261 self
.redirect("/users/%s" % account
.uid
)
264 class SSODiscourse(auth
.CacheMixin
, base
.BaseHandler
):
265 def _get_discourse_params(self
):
266 # Fetch Discourse's parameters
267 sso
= self
.get_argument("sso")
268 sig
= self
.get_argument("sig")
272 return self
.accounts
.decode_discourse_payload(sso
, sig
)
274 # Raise bad request if the signature is invalid
276 raise tornado
.web
.HTTPError(400)
278 def _redirect_user_to_discourse(self
, account
, nonce
, return_sso_url
):
280 Redirects the user back to Discourse passing some
281 attributes of the user account to Discourse
285 "external_id" : account
.uid
,
288 "email" : account
.email
,
289 "require_activation" : "false",
291 # More details about the user
292 "username" : account
.uid
,
293 "name" : "%s" % account
,
296 "avatar_url" : account
.avatar_url(),
297 "avatar_force_update" : "true",
299 # Send a welcome message
300 "suppress_welcome_message" : "false",
303 "admin" : "true" if account
.is_admin() else "false",
304 "moderator" : "true" if account
.is_staff() else "false",
307 # Format payload and sign it
308 payload
= self
.accounts
.encode_discourse_payload(**args
)
309 signature
= self
.accounts
.sign_discourse_payload(payload
)
311 qs
= urllib
.parse
.urlencode({
317 self
.redirect("%s?%s" % (return_sso_url
, qs
))
319 @base.ratelimit(minutes
=24*60, requests
=100)
321 params
= self
._get
_discourse
_params
()
323 # Redirect back if user is already logged in
324 if self
.current_user
:
325 return self
._redirect
_user
_to
_discourse
(self
.current_user
, **params
)
327 # Otherwise the user needs to authenticate
328 self
.render("auth/login.html", next
=None)
330 @base.ratelimit(minutes
=24*60, requests
=100)
332 params
= self
._get
_discourse
_params
()
335 username
= self
.get_argument("username")
336 password
= self
.get_argument("password")
339 account
= self
.accounts
.auth(username
, password
)
341 raise tornado
.web
.HTTPError(401, "Unknown user or invalid password: %s" % username
)
343 # If the user has been authenticated, we will redirect to Discourse
344 self
._redirect
_user
_to
_discourse
(account
, **params
)
347 class NewAccountsModule(ui_modules
.UIModule
):
348 def render(self
, days
=14):
349 t
= datetime
.datetime
.utcnow() - datetime
.timedelta(days
=days
)
351 # Fetch all accounts created after t
352 accounts
= self
.backend
.accounts
.get_created_after(t
)
354 accounts
.sort(key
=lambda a
: a
.created_at
, reverse
=True)
356 return self
.render_string("people/modules/accounts-new.html",
357 accounts
=accounts
, t
=t
)
360 class AccountsListModule(ui_modules
.UIModule
):
361 def render(self
, accounts
=None):
363 accounts
= self
.backend
.accounts
365 return self
.render_string("people/modules/accounts-list.html", accounts
=accounts
)
368 class CDRModule(ui_modules
.UIModule
):
369 def render(self
, account
, date
=None, limit
=None):
370 cdr
= account
.get_cdr(date
=date
, limit
=limit
)
372 return self
.render_string("people/modules/cdr.html",
373 account
=account
, cdr
=list(cdr
))
376 class ChannelsModule(ui_modules
.UIModule
):
377 def render(self
, account
):
378 return self
.render_string("people/modules/channels.html",
379 account
=account
, channels
=account
.sip_channels
)
382 class MOSModule(ui_modules
.UIModule
):
383 def render(self
, call
):
384 return self
.render_string("people/modules/mos.html", call
=call
)
387 class PasswordModule(ui_modules
.UIModule
):
388 def render(self
, account
=None):
389 return self
.render_string("people/modules/password.html", account
=account
)
391 def javascript_files(self
):
392 return "js/zxcvbn.js"
394 def embedded_javascript(self
):
395 return self
.render_string("people/modules/password.js")
398 class RegistrationsModule(ui_modules
.UIModule
):
399 def render(self
, account
):
400 return self
.render_string("people/modules/registrations.html", account
=account
)
403 class SIPStatusModule(ui_modules
.UIModule
):
404 def render(self
, account
):
405 return self
.render_string("people/modules/sip-status.html", account
=account
)