]> git.ipfire.org Git - ipfire.org.git/blame - src/web/people.py
users: Move group handlers
[ipfire.org.git] / src / web / people.py
CommitLineData
2cd9af74
MT
1#!/usr/bin/python
2
bdaf6b46 3import datetime
e96e445b 4import ldap
2cd9af74 5import tornado.web
2dac7110 6import urllib.parse
2cd9af74 7
0099c2a7
MT
8from .. import countries
9
9b8ff27d 10from . import auth
124a8404 11from . import base
786e9ca8
MT
12from . import ui_modules
13
9b8ff27d 14class IndexHandler(auth.CacheMixin, base.BaseHandler):
786e9ca8
MT
15 @tornado.web.authenticated
16 def get(self):
15bb44ee 17 self.render("people/index.html")
786e9ca8 18
2cd9af74 19
9b8ff27d 20class CallsHandler(auth.CacheMixin, base.BaseHandler):
bdaf6b46
MT
21 @tornado.web.authenticated
22 def get(self, uid, date=None):
23 account = self.backend.accounts.get_by_uid(uid)
24 if not account:
25 raise tornado.web.HTTPError(404, "Could not find account %s" % uid)
26
d561d931
MT
27 # Check for permissions
28 if not account.can_be_managed_by(self.current_user):
29 raise tornado.web.HTTPError(403, "%s cannot manage %s" % (self.current_user, account))
30
bdaf6b46 31 if date:
44b4640b
MT
32 try:
33 date = datetime.datetime.strptime(date, "%Y-%m-%d").date()
34 except ValueError:
35 raise tornado.web.HTTPError(400, "Invalid date: %s" % date)
bdaf6b46
MT
36 else:
37 date = datetime.date.today()
38
39 self.render("people/calls.html", account=account, date=date)
40
41
9b8ff27d 42class CallHandler(auth.CacheMixin, base.BaseHandler):
68ece434
MT
43 @tornado.web.authenticated
44 def get(self, uid, uuid):
d09d554b
MT
45 account = self.backend.accounts.get_by_uid(uid)
46 if not account:
47 raise tornado.web.HTTPError(404, "Could not find account %s" % uid)
48
d561d931
MT
49 # Check for permissions
50 if not account.can_be_managed_by(self.current_user):
51 raise tornado.web.HTTPError(403, "%s cannot manage %s" % (self.current_user, account))
52
68ece434
MT
53 call = self.backend.talk.freeswitch.get_call_by_uuid(uuid)
54 if not call:
55 raise tornado.web.HTTPError(404, "Could not find call %s" % uuid)
56
57 # XXX limit
58
d09d554b 59 self.render("people/call.html", account=account, call=call)
68ece434
MT
60
61
9b8ff27d 62class ConferencesHandler(auth.CacheMixin, base.BaseHandler):
30aeccdb
MT
63 @tornado.web.authenticated
64 def get(self):
65 self.render("people/conferences.html", conferences=self.backend.talk.conferences)
66
67
92c4b559 68class SubscribeHandler(auth.CacheMixin, base.BaseHandler):
92c4b559
MT
69 @tornado.web.authenticated
70 def post(self):
71 # Give consent
72 self.current_user.consents_to_promotional_emails = True
73
74 self.render("people/subscribed.html")
75
76
77class UnsubscribeHandler(auth.CacheMixin, base.BaseHandler):
78 @tornado.web.authenticated
79 def get(self):
80 if self.current_user.consents_to_promotional_emails:
81 return self.render("people/unsubscribe.html")
82
83 self.render("people/unsubscribed.html")
84
85 @tornado.web.authenticated
86 def post(self):
87 # Withdraw consent
88 self.current_user.consents_to_promotional_emails = False
89
90 self.render("people/unsubscribed.html")
91
92
9b8ff27d 93class SIPHandler(auth.CacheMixin, base.BaseHandler):
e0daee8f
MT
94 @tornado.web.authenticated
95 def get(self, uid):
96 account = self.backend.accounts.get_by_uid(uid)
97 if not account:
98 raise tornado.web.HTTPError(404, "Could not find account %s" % uid)
99
100 # Check for permissions
101 if not account.can_be_managed_by(self.current_user):
102 raise tornado.web.HTTPError(403, "%s cannot manage %s" % (self.current_user, account))
103
104 self.render("people/sip.html", account=account)
105
106
9b8ff27d 107class UserEditHandler(auth.CacheMixin, base.BaseHandler):
e96e445b
MT
108 @tornado.web.authenticated
109 def get(self, uid):
110 account = self.backend.accounts.get_by_uid(uid)
111 if not account:
112 raise tornado.web.HTTPError(404, "Could not find account %s" % uid)
113
114 # Check for permissions
115 if not account.can_be_managed_by(self.current_user):
116 raise tornado.web.HTTPError(403, "%s cannot manage %s" % (self.current_user, account))
117
0099c2a7 118 self.render("people/user-edit.html", account=account, countries=countries.get_all())
e96e445b
MT
119
120 @tornado.web.authenticated
121 def post(self, uid):
122 account = self.backend.accounts.get_by_uid(uid)
123 if not account:
124 raise tornado.web.HTTPError(404, "Could not find account %s" % uid)
125
126 # Check for permissions
127 if not account.can_be_managed_by(self.current_user):
128 raise tornado.web.HTTPError(403, "%s cannot manage %s" % (self.current_user, account))
129
130 # Unfortunately this cannot be wrapped into a transaction
131 try:
0099c2a7
MT
132 account.first_name = self.get_argument("first_name")
133 account.last_name = self.get_argument("last_name")
d6e57f73 134 account.nickname = self.get_argument("nickname", None)
0099c2a7
MT
135 account.street = self.get_argument("street", None)
136 account.city = self.get_argument("city", None)
137 account.postal_code = self.get_argument("postal_code", None)
138 account.country_code = self.get_argument("country_code", None)
1c4522dc 139 account.description = self.get_argument("description", None)
e96e445b 140
5cc10421
MT
141 # Avatar
142 try:
143 filename, data, mimetype = self.get_file("avatar")
144
145 if not mimetype.startswith("image/"):
146 raise tornado.web.HTTPError(400, "Avatar is not an image file: %s" % mimetype)
147
148 account.upload_avatar(data)
9bbf48b8 149 except TypeError:
5cc10421
MT
150 pass
151
e96e445b
MT
152 # Email
153 account.mail_routing_address = self.get_argument("mail_routing_address", None)
154
155 # Telephone
156 account.phone_numbers = self.get_argument("phone_numbers", "").splitlines()
157 account.sip_routing_address = self.get_argument("sip_routing_address", None)
158 except ldap.STRONG_AUTH_REQUIRED as e:
159 raise tornado.web.HTTPError(403, "%s" % e) from e
160
161 # Redirect back to user page
162 self.redirect("/users/%s" % account.uid)
163
164
9b8ff27d 165class UserPasswdHandler(auth.CacheMixin, base.BaseHandler):
3ea97943
MT
166 @tornado.web.authenticated
167 def get(self, uid):
168 account = self.backend.accounts.get_by_uid(uid)
169 if not account:
170 raise tornado.web.HTTPError(404, "Could not find account %s" % uid)
171
172 # Check for permissions
173 if not account.can_be_managed_by(self.current_user):
174 raise tornado.web.HTTPError(403, "%s cannot manage %s" % (self.current_user, account))
175
176 self.render("people/passwd.html", account=account)
177
178 @tornado.web.authenticated
179 def post(self, uid):
180 account = self.backend.accounts.get_by_uid(uid)
181 if not account:
182 raise tornado.web.HTTPError(404, "Could not find account %s" % uid)
183
184 # Check for permissions
185 if not account.can_be_managed_by(self.current_user):
186 raise tornado.web.HTTPError(403, "%s cannot manage %s" % (self.current_user, account))
187
188 # Get current password
189 password = self.get_argument("password")
190
191 # Get new password
192 password1 = self.get_argument("password1")
193 password2 = self.get_argument("password2")
194
195 # Passwords must match
196 if not password1 == password2:
197 raise tornado.web.HTTPError(400, "Passwords do not match")
198
199 # XXX Check password complexity
200
201 # Check if old password matches
202 if not account.check_password(password):
203 raise tornado.web.HTTPError(403, "Incorrect password for %s" % account)
204
205 # Save new password
206 account.passwd(password1)
207
208 # Redirect back to user's page
209 self.redirect("/users/%s" % account.uid)
210
211
2dac7110 212class SSODiscourse(auth.CacheMixin, base.BaseHandler):
880fd132
MT
213 @base.ratelimit(minutes=24*60, requests=100)
214 @tornado.web.authenticated
215 def get(self):
2dac7110
MT
216 # Fetch Discourse's parameters
217 sso = self.get_argument("sso")
218 sig = self.get_argument("sig")
219
220 # Decode payload
221 try:
880fd132 222 params = self.accounts.decode_discourse_payload(sso, sig)
2dac7110
MT
223
224 # Raise bad request if the signature is invalid
225 except ValueError:
226 raise tornado.web.HTTPError(400)
227
880fd132 228 # Redirect back if user is already logged in
2dac7110 229 args = {
880fd132
MT
230 "nonce" : params.get("nonce"),
231 "external_id" : self.current_user.uid,
2dac7110
MT
232
233 # Pass email address
880fd132 234 "email" : self.current_user.email,
2dac7110
MT
235 "require_activation" : "false",
236
237 # More details about the user
880fd132
MT
238 "username" : self.current_user.uid,
239 "name" : "%s" % self.current_user,
240 "bio" : self.current_user.description or "",
2dac7110
MT
241
242 # Avatar
0da30c28 243 "avatar_url" : self.current_user.avatar_url(absolute=True),
2dac7110
MT
244 "avatar_force_update" : "true",
245
246 # Send a welcome message
247 "suppress_welcome_message" : "false",
248
249 # Group memberships
880fd132
MT
250 "admin" : "true" if self.current_user.is_admin() else "false",
251 "moderator" : "true" if self.current_user.is_moderator() else "false",
2dac7110
MT
252 }
253
254 # Format payload and sign it
255 payload = self.accounts.encode_discourse_payload(**args)
256 signature = self.accounts.sign_discourse_payload(payload)
257
258 qs = urllib.parse.urlencode({
259 "sso" : payload,
260 "sig" : signature,
261 })
262
263 # Redirect user
880fd132 264 self.redirect("%s?%s" % (params.get("return_sso_url"), qs))
2dac7110
MT
265
266
786e9ca8
MT
267class AccountsListModule(ui_modules.UIModule):
268 def render(self, accounts=None):
269 if accounts is None:
51907e45 270 accounts = self.backend.accounts
786e9ca8
MT
271
272 return self.render_string("people/modules/accounts-list.html", accounts=accounts)
273
274
c66f2152
MT
275class AgentModule(ui_modules.UIModule):
276 def render(self, account):
277 return self.render_string("people/modules/agent.html", account=account)
278
279
786e9ca8 280class CDRModule(ui_modules.UIModule):
bdaf6b46
MT
281 def render(self, account, date=None, limit=None):
282 cdr = account.get_cdr(date=date, limit=limit)
786e9ca8 283
89e47299
MT
284 return self.render_string("people/modules/cdr.html",
285 account=account, cdr=list(cdr))
786e9ca8
MT
286
287
288class ChannelsModule(ui_modules.UIModule):
289 def render(self, account):
1f38be5a
MT
290 return self.render_string("people/modules/channels.html",
291 account=account, channels=account.sip_channels)
786e9ca8
MT
292
293
68ece434
MT
294class MOSModule(ui_modules.UIModule):
295 def render(self, call):
296 return self.render_string("people/modules/mos.html", call=call)
297
298
b5e2077f 299class PasswordModule(ui_modules.UIModule):
56894a8b 300 def render(self, account=None):
b5e2077f
MT
301 return self.render_string("people/modules/password.html", account=account)
302
303 def javascript_files(self):
304 return "js/zxcvbn.js"
305
306 def embedded_javascript(self):
307 return self.render_string("people/modules/password.js")
308
309
786e9ca8
MT
310class RegistrationsModule(ui_modules.UIModule):
311 def render(self, account):
312 return self.render_string("people/modules/registrations.html", account=account)