Mercurial > libervia-backend
comparison sat/plugins/plugin_misc_account.py @ 2624:56f94936df1e
code style reformatting using black
author | Goffi <goffi@goffi.org> |
---|---|
date | Wed, 27 Jun 2018 20:14:46 +0200 |
parents | 26edcf3a30eb |
children | 378188abe941 |
comparison
equal
deleted
inserted
replaced
2623:49533de4540b | 2624:56f94936df1e |
---|---|
17 # You should have received a copy of the GNU Affero General Public License | 17 # You should have received a copy of the GNU Affero General Public License |
18 # along with this program. If not, see <http://www.gnu.org/licenses/>. | 18 # along with this program. If not, see <http://www.gnu.org/licenses/>. |
19 | 19 |
20 from sat.core.i18n import _, D_ | 20 from sat.core.i18n import _, D_ |
21 from sat.core.log import getLogger | 21 from sat.core.log import getLogger |
22 | |
22 log = getLogger(__name__) | 23 log = getLogger(__name__) |
23 from sat.core import exceptions | 24 from sat.core import exceptions |
24 from sat.tools import xml_tools | 25 from sat.tools import xml_tools |
25 from sat.memory.memory import Sessions | 26 from sat.memory.memory import Sessions |
26 from sat.memory.crypto import PasswordHasher | 27 from sat.memory.crypto import PasswordHasher |
29 from twisted.internet import defer | 30 from twisted.internet import defer |
30 from twisted.python.failure import Failure | 31 from twisted.python.failure import Failure |
31 from twisted.words.protocols.jabber import jid | 32 from twisted.words.protocols.jabber import jid |
32 from sat.tools import email as sat_email | 33 from sat.tools import email as sat_email |
33 | 34 |
34 # FIXME: this plugin code is old and need a cleaning | 35 # FIXME: this plugin code is old and need a cleaning |
35 # TODO: account deletion/password change need testing | 36 # TODO: account deletion/password change need testing |
36 | 37 |
37 | 38 |
38 PLUGIN_INFO = { | 39 PLUGIN_INFO = { |
39 C.PI_NAME: "Account Plugin", | 40 C.PI_NAME: "Account Plugin", |
40 C.PI_IMPORT_NAME: "MISC-ACCOUNT", | 41 C.PI_IMPORT_NAME: "MISC-ACCOUNT", |
41 C.PI_TYPE: "MISC", | 42 C.PI_TYPE: "MISC", |
42 C.PI_PROTOCOLS: [], | 43 C.PI_PROTOCOLS: [], |
43 C.PI_DEPENDENCIES: ["XEP-0077"], | 44 C.PI_DEPENDENCIES: ["XEP-0077"], |
44 C.PI_RECOMMENDATIONS: ['GROUPBLOG'], | 45 C.PI_RECOMMENDATIONS: ["GROUPBLOG"], |
45 C.PI_MAIN: "MiscAccount", | 46 C.PI_MAIN: "MiscAccount", |
46 C.PI_HANDLER: "no", | 47 C.PI_HANDLER: "no", |
47 C.PI_DESCRIPTION: _(u"""SàT account creation""") | 48 C.PI_DESCRIPTION: _(u"""SàT account creation"""), |
48 } | 49 } |
49 | 50 |
50 CONFIG_SECTION = "plugin account" | 51 CONFIG_SECTION = "plugin account" |
51 | 52 |
52 # You need do adapt the following consts to your server | 53 # You need do adapt the following consts to your server |
53 # all theses values (key=option name, value=default) can (and should) be overriden in sat.conf | 54 # all theses values (key=option name, value=default) can (and should) be overriden in sat.conf |
54 # in section CONFIG_SECTION | 55 # in section CONFIG_SECTION |
55 | 56 |
56 default_conf = {"email_from": "NOREPLY@example.net", | 57 default_conf = { |
57 "email_server": "localhost", | 58 "email_from": "NOREPLY@example.net", |
58 "email_sender_domain": "", | 59 "email_server": "localhost", |
59 "email_port": 25, | 60 "email_sender_domain": "", |
60 "email_username": "", | 61 "email_port": 25, |
61 "email_password": "", | 62 "email_username": "", |
62 "email_starttls": "false", | 63 "email_password": "", |
63 "email_auth": "false", | 64 "email_starttls": "false", |
64 "email_admins_list": [], | 65 "email_auth": "false", |
65 "admin_email": "", | 66 "email_admins_list": [], |
66 "new_account_server": "localhost", | 67 "admin_email": "", |
67 "new_account_domain": "", # use xmpp_domain if not found | 68 "new_account_server": "localhost", |
68 "reserved_list": ['libervia'] # profiles which can't be used | 69 "new_account_domain": "", # use xmpp_domain if not found |
69 } | 70 "reserved_list": ["libervia"], # profiles which can't be used |
70 | 71 } |
71 WELCOME_MSG = D_(u"""Welcome to Libervia, the web interface of Salut à Toi. | 72 |
73 WELCOME_MSG = D_( | |
74 u"""Welcome to Libervia, the web interface of Salut à Toi. | |
72 | 75 |
73 Your account on {domain} has been successfully created. | 76 Your account on {domain} has been successfully created. |
74 This is a demonstration version to show you the current status of the project. | 77 This is a demonstration version to show you the current status of the project. |
75 It is still under development, please keep it in mind! | 78 It is still under development, please keep it in mind! |
76 | 79 |
86 | 89 |
87 Any feedback welcome. Thank you! | 90 Any feedback welcome. Thank you! |
88 | 91 |
89 Salut à Toi association | 92 Salut à Toi association |
90 https://www.salut-a-toi.org | 93 https://www.salut-a-toi.org |
91 """) | 94 """ |
95 ) | |
92 | 96 |
93 DEFAULT_DOMAIN = u"example.net" | 97 DEFAULT_DOMAIN = u"example.net" |
94 | 98 |
95 | 99 |
96 class MiscAccount(object): | 100 class MiscAccount(object): |
97 """Account plugin: create a SàT + XMPP account, used by Libervia""" | 101 """Account plugin: create a SàT + XMPP account, used by Libervia""" |
102 | |
98 # XXX: This plugin was initialy a Q&D one used for the demo. | 103 # XXX: This plugin was initialy a Q&D one used for the demo. |
99 # TODO: cleaning, separate email handling, more configuration/tests, fixes | 104 # TODO: cleaning, separate email handling, more configuration/tests, fixes |
100 | |
101 | 105 |
102 def __init__(self, host): | 106 def __init__(self, host): |
103 log.info(_(u"Plugin Account initialization")) | 107 log.info(_(u"Plugin Account initialization")) |
104 self.host = host | 108 self.host = host |
105 host.bridge.addMethod("registerSatAccount", ".plugin", in_sign='sss', out_sign='', method=self._registerAccount, async=True) | 109 host.bridge.addMethod( |
106 host.bridge.addMethod("getNewAccountDomain", ".plugin", in_sign='', out_sign='s', method=self.getNewAccountDomain, async=False) | 110 "registerSatAccount", |
107 host.bridge.addMethod("getAccountDialogUI", ".plugin", in_sign='s', out_sign='s', method=self._getAccountDialogUI, async=False) | 111 ".plugin", |
108 host.bridge.addMethod("asyncConnectWithXMPPCredentials", ".plugin", in_sign='ss', out_sign='b', method=self.asyncConnectWithXMPPCredentials, async=True) | 112 in_sign="sss", |
113 out_sign="", | |
114 method=self._registerAccount, | |
115 async=True, | |
116 ) | |
117 host.bridge.addMethod( | |
118 "getNewAccountDomain", | |
119 ".plugin", | |
120 in_sign="", | |
121 out_sign="s", | |
122 method=self.getNewAccountDomain, | |
123 async=False, | |
124 ) | |
125 host.bridge.addMethod( | |
126 "getAccountDialogUI", | |
127 ".plugin", | |
128 in_sign="s", | |
129 out_sign="s", | |
130 method=self._getAccountDialogUI, | |
131 async=False, | |
132 ) | |
133 host.bridge.addMethod( | |
134 "asyncConnectWithXMPPCredentials", | |
135 ".plugin", | |
136 in_sign="ss", | |
137 out_sign="b", | |
138 method=self.asyncConnectWithXMPPCredentials, | |
139 async=True, | |
140 ) | |
109 | 141 |
110 self.fixEmailAdmins() | 142 self.fixEmailAdmins() |
111 self._sessions = Sessions() | 143 self._sessions = Sessions() |
112 | 144 |
113 self.__account_cb_id = host.registerCallback(self._accountDialogCb, with_data=True) | 145 self.__account_cb_id = host.registerCallback( |
114 self.__change_password_id = host.registerCallback(self.__changePasswordCb, with_data=True) | 146 self._accountDialogCb, with_data=True |
147 ) | |
148 self.__change_password_id = host.registerCallback( | |
149 self.__changePasswordCb, with_data=True | |
150 ) | |
115 | 151 |
116 def deleteBlogCallback(posts, comments): | 152 def deleteBlogCallback(posts, comments): |
117 return lambda data, profile: self.__deleteBlogPostsCb(posts, comments, data, profile) | 153 return lambda data, profile: self.__deleteBlogPostsCb( |
118 | 154 posts, comments, data, profile |
119 self.__delete_posts_id = host.registerCallback(deleteBlogCallback(True, False), with_data=True) | 155 ) |
120 self.__delete_comments_id = host.registerCallback(deleteBlogCallback(False, True), with_data=True) | 156 |
121 self.__delete_posts_comments_id = host.registerCallback(deleteBlogCallback(True, True), with_data=True) | 157 self.__delete_posts_id = host.registerCallback( |
122 | 158 deleteBlogCallback(True, False), with_data=True |
123 self.__delete_account_id = host.registerCallback(self.__deleteAccountCb, with_data=True) | 159 ) |
124 | 160 self.__delete_comments_id = host.registerCallback( |
161 deleteBlogCallback(False, True), with_data=True | |
162 ) | |
163 self.__delete_posts_comments_id = host.registerCallback( | |
164 deleteBlogCallback(True, True), with_data=True | |
165 ) | |
166 | |
167 self.__delete_account_id = host.registerCallback( | |
168 self.__deleteAccountCb, with_data=True | |
169 ) | |
125 | 170 |
126 # FIXME: remove this after some time, when the deprecated parameter is really abandoned | 171 # FIXME: remove this after some time, when the deprecated parameter is really abandoned |
127 def fixEmailAdmins(self): | 172 def fixEmailAdmins(self): |
128 """Handle deprecated config option "admin_email" to fix the admin emails list""" | 173 """Handle deprecated config option "admin_email" to fix the admin emails list""" |
129 admin_email = self.getConfig('admin_email') | 174 admin_email = self.getConfig("admin_email") |
130 if not admin_email: | 175 if not admin_email: |
131 return | 176 return |
132 log.warning(u"admin_email parameter is deprecated, please use email_admins_list instead") | 177 log.warning( |
178 u"admin_email parameter is deprecated, please use email_admins_list instead" | |
179 ) | |
133 param_name = "email_admins_list" | 180 param_name = "email_admins_list" |
134 try: | 181 try: |
135 section = "" | 182 section = "" |
136 value = self.host.memory.getConfig(section, param_name, Exception) | 183 value = self.host.memory.getConfig(section, param_name, Exception) |
137 except (ConfigParser.NoOptionError, ConfigParser.NoSectionError): | 184 except (ConfigParser.NoOptionError, ConfigParser.NoSectionError): |
138 section = CONFIG_SECTION | 185 section = CONFIG_SECTION |
139 value = self.host.memory.getConfig(section, param_name, default_conf[param_name]) | 186 value = self.host.memory.getConfig( |
187 section, param_name, default_conf[param_name] | |
188 ) | |
140 | 189 |
141 value = set(value) | 190 value = set(value) |
142 value.add(admin_email) | 191 value.add(admin_email) |
143 self.host.memory.config.set(section, param_name, ",".join(value)) | 192 self.host.memory.config.set(section, param_name, ",".join(value)) |
144 | 193 |
191 @return Deferred | 240 @return Deferred |
192 """ | 241 """ |
193 if not password or not profile: | 242 if not password or not profile: |
194 raise exceptions.DataError | 243 raise exceptions.DataError |
195 | 244 |
196 if profile.lower() in self.getConfig('reserved_list'): | 245 if profile.lower() in self.getConfig("reserved_list"): |
197 return defer.fail(Failure(exceptions.ConflictError)) | 246 return defer.fail(Failure(exceptions.ConflictError)) |
198 | 247 |
199 d = self.host.memory.createProfile(profile, password) | 248 d = self.host.memory.createProfile(profile, password) |
200 d.addCallback(lambda dummy: self.profileCreated(password, jid_s, profile)) | 249 d.addCallback(lambda dummy: self.profileCreated(password, jid_s, profile)) |
201 return d | 250 return d |
214 d = defer.succeed(None) | 263 d = defer.succeed(None) |
215 jid_ = jid.JID(jid_s) | 264 jid_ = jid.JID(jid_s) |
216 else: | 265 else: |
217 jid_s = profile + u"@" + self.getNewAccountDomain() | 266 jid_s = profile + u"@" + self.getNewAccountDomain() |
218 jid_ = jid.JID(jid_s) | 267 jid_ = jid.JID(jid_s) |
219 d = self.host.plugins['XEP-0077'].registerNewAccount(jid_, password) | 268 d = self.host.plugins["XEP-0077"].registerNewAccount(jid_, password) |
220 | 269 |
221 def setParams(dummy): | 270 def setParams(dummy): |
222 self.host.memory.setParam("JabberID", jid_s, "Connection", profile_key=profile) | 271 self.host.memory.setParam( |
223 d = self.host.memory.setParam("Password", password, "Connection", profile_key=profile) | 272 "JabberID", jid_s, "Connection", profile_key=profile |
273 ) | |
274 d = self.host.memory.setParam( | |
275 "Password", password, "Connection", profile_key=profile | |
276 ) | |
224 return d | 277 return d |
225 | 278 |
226 def removeProfile(failure): | 279 def removeProfile(failure): |
227 self.host.memory.asyncDeleteProfile(profile) | 280 self.host.memory.asyncDeleteProfile(profile) |
228 return failure | 281 return failure |
233 d.addErrback(removeProfile) | 286 d.addErrback(removeProfile) |
234 return d | 287 return d |
235 | 288 |
236 def _sendEmailEb(self, failure_, email): | 289 def _sendEmailEb(self, failure_, email): |
237 # TODO: return error code to user | 290 # TODO: return error code to user |
238 log.error(_(u"Failed to send account creation confirmation to {email}: {msg}").format( | 291 log.error( |
239 email = email, | 292 _(u"Failed to send account creation confirmation to {email}: {msg}").format( |
240 msg = failure_)) | 293 email=email, msg=failure_ |
294 ) | |
295 ) | |
241 | 296 |
242 def sendEmails(self, email, profile): | 297 def sendEmails(self, email, profile): |
243 # time to send the email | 298 # time to send the email |
244 | 299 |
245 domain = self.getNewAccountDomain() | 300 domain = self.getNewAccountDomain() |
246 | 301 |
247 # email to the administrators | 302 # email to the administrators |
248 admins_emails = self.getConfig('email_admins_list') | 303 admins_emails = self.getConfig("email_admins_list") |
249 if not admins_emails: | 304 if not admins_emails: |
250 log.warning(u"No known admin email, we can't send email to administrator(s).\nPlease fill email_admins_list parameter") | 305 log.warning( |
306 u"No known admin email, we can't send email to administrator(s).\nPlease fill email_admins_list parameter" | |
307 ) | |
251 d_admin = defer.fail(exceptions.DataError("no admin email")) | 308 d_admin = defer.fail(exceptions.DataError("no admin email")) |
252 else: | 309 else: |
253 subject = _(u'New Libervia account created') | 310 subject = _(u"New Libervia account created") |
254 body = (u"""New account created: {profile} [{email}]""".format( | 311 body = u"""New account created: {profile} [{email}]""".format( |
255 profile = profile, | 312 profile=profile, |
256 # there is no email when an existing XMPP account is used | 313 # there is no email when an existing XMPP account is used |
257 email = email or u"<no email>")) | 314 email=email or u"<no email>", |
315 ) | |
258 d_admin = sat_email.sendEmail(self.host, admins_emails, subject, body) | 316 d_admin = sat_email.sendEmail(self.host, admins_emails, subject, body) |
259 | 317 |
260 admins_emails_txt = u', '.join([u'<' + addr + u'>' for addr in admins_emails]) | 318 admins_emails_txt = u", ".join([u"<" + addr + u">" for addr in admins_emails]) |
261 d_admin.addCallbacks(lambda dummy: log.debug(u"Account creation notification sent to admin(s) {}".format(admins_emails_txt)), | 319 d_admin.addCallbacks( |
262 lambda dummy: log.error(u"Failed to send account creation notification to admin {}".format(admins_emails_txt))) | 320 lambda dummy: log.debug( |
321 u"Account creation notification sent to admin(s) {}".format( | |
322 admins_emails_txt | |
323 ) | |
324 ), | |
325 lambda dummy: log.error( | |
326 u"Failed to send account creation notification to admin {}".format( | |
327 admins_emails_txt | |
328 ) | |
329 ), | |
330 ) | |
263 if not email: | 331 if not email: |
264 # TODO: if use register with an existing account, an XMPP message should be sent | 332 # TODO: if use register with an existing account, an XMPP message should be sent |
265 return d_admin | 333 return d_admin |
266 | 334 |
267 jid_s = self.host.memory.getParamA(u"JabberID", u"Connection", profile_key=profile) | 335 jid_s = self.host.memory.getParamA( |
268 subject = _(u'Your Libervia account has been created') | 336 u"JabberID", u"Connection", profile_key=profile |
269 body = (_(WELCOME_MSG).format(profile=profile, jid=jid_s, domain=domain)) | 337 ) |
338 subject = _(u"Your Libervia account has been created") | |
339 body = _(WELCOME_MSG).format(profile=profile, jid=jid_s, domain=domain) | |
270 | 340 |
271 # XXX: this will not fail when the email address doesn't exist | 341 # XXX: this will not fail when the email address doesn't exist |
272 # FIXME: check email reception to validate email given by the user | 342 # FIXME: check email reception to validate email given by the user |
273 # FIXME: delete the profile if the email could not been sent? | 343 # FIXME: delete the profile if the email could not been sent? |
274 d_user = sat_email.sendEmail(self.host, [email], subject, body) | 344 d_user = sat_email.sendEmail(self.host, [email], subject, body) |
275 d_user.addCallbacks(lambda dummy: log.debug(u"Account creation confirmation sent to <{}>".format(email)), | 345 d_user.addCallbacks( |
276 self._sendEmailEb) | 346 lambda dummy: log.debug( |
347 u"Account creation confirmation sent to <{}>".format(email) | |
348 ), | |
349 self._sendEmailEb, | |
350 ) | |
277 return defer.DeferredList([d_user, d_admin]) | 351 return defer.DeferredList([d_user, d_admin]) |
278 | 352 |
279 def getNewAccountDomain(self): | 353 def getNewAccountDomain(self): |
280 """get the domain that will be set to new account""" | 354 """get the domain that will be set to new account""" |
281 | 355 |
282 domain = self.getConfig('new_account_domain') or self.getConfig('xmpp_domain', None) | 356 domain = self.getConfig("new_account_domain") or self.getConfig( |
357 "xmpp_domain", None | |
358 ) | |
283 if not domain: | 359 if not domain: |
284 log.warning(_(u'xmpp_domain needs to be set in sat.conf. Using "{default}" meanwhile').format(default=DEFAULT_DOMAIN)) | 360 log.warning( |
361 _( | |
362 u'xmpp_domain needs to be set in sat.conf. Using "{default}" meanwhile' | |
363 ).format(default=DEFAULT_DOMAIN) | |
364 ) | |
285 return DEFAULT_DOMAIN | 365 return DEFAULT_DOMAIN |
286 return domain | 366 return domain |
287 | 367 |
288 def _getAccountDialogUI(self, profile): | 368 def _getAccountDialogUI(self, profile): |
289 """Get the main dialog to manage your account | 369 """Get the main dialog to manage your account |
290 @param menu_data | 370 @param menu_data |
291 @param profile: %(doc_profile)s | 371 @param profile: %(doc_profile)s |
292 @return: XML of the dialog | 372 @return: XML of the dialog |
293 """ | 373 """ |
294 form_ui = xml_tools.XMLUI("form", "tabs", title=D_("Manage your account"), submit_id=self.__account_cb_id) | 374 form_ui = xml_tools.XMLUI( |
375 "form", | |
376 "tabs", | |
377 title=D_("Manage your account"), | |
378 submit_id=self.__account_cb_id, | |
379 ) | |
295 tab_container = form_ui.current_container | 380 tab_container = form_ui.current_container |
296 | 381 |
297 tab_container.addTab("update", D_("Change your password"), container=xml_tools.PairsContainer) | 382 tab_container.addTab( |
383 "update", D_("Change your password"), container=xml_tools.PairsContainer | |
384 ) | |
298 form_ui.addLabel(D_("Current profile password")) | 385 form_ui.addLabel(D_("Current profile password")) |
299 form_ui.addPassword("current_passwd", value="") | 386 form_ui.addPassword("current_passwd", value="") |
300 form_ui.addLabel(D_("New password")) | 387 form_ui.addLabel(D_("New password")) |
301 form_ui.addPassword("new_passwd1", value="") | 388 form_ui.addPassword("new_passwd1", value="") |
302 form_ui.addLabel(D_("New password (again)")) | 389 form_ui.addLabel(D_("New password (again)")) |
326 def _accountDialogCb(self, data, profile): | 413 def _accountDialogCb(self, data, profile): |
327 """Called when the user submits the main account dialog | 414 """Called when the user submits the main account dialog |
328 @param data | 415 @param data |
329 @param profile | 416 @param profile |
330 """ | 417 """ |
331 sat_cipher = yield self.host.memory.asyncGetParamA(C.PROFILE_PASS_PATH[1], C.PROFILE_PASS_PATH[0], profile_key=profile) | 418 sat_cipher = yield self.host.memory.asyncGetParamA( |
419 C.PROFILE_PASS_PATH[1], C.PROFILE_PASS_PATH[0], profile_key=profile | |
420 ) | |
332 | 421 |
333 @defer.inlineCallbacks | 422 @defer.inlineCallbacks |
334 def verify(attempt): | 423 def verify(attempt): |
335 auth = yield PasswordHasher.verify(attempt, sat_cipher) | 424 auth = yield PasswordHasher.verify(attempt, sat_cipher) |
336 defer.returnValue(auth) | 425 defer.returnValue(auth) |
338 def error_ui(message=None): | 427 def error_ui(message=None): |
339 if not message: | 428 if not message: |
340 message = D_("The provided profile password doesn't match.") | 429 message = D_("The provided profile password doesn't match.") |
341 error_ui = xml_tools.XMLUI("popup", title=D_("Attempt failure")) | 430 error_ui = xml_tools.XMLUI("popup", title=D_("Attempt failure")) |
342 error_ui.addText(message) | 431 error_ui.addText(message) |
343 return {'xmlui': error_ui.toXml()} | 432 return {"xmlui": error_ui.toXml()} |
344 | 433 |
345 # check for account deletion | 434 # check for account deletion |
346 # FIXME: uncomment and fix these features | 435 # FIXME: uncomment and fix these features |
347 """ | 436 """ |
348 delete_passwd = data[xml_tools.SAT_FORM_PREFIX + 'delete_passwd'] | 437 delete_passwd = data[xml_tools.SAT_FORM_PREFIX + 'delete_passwd'] |
368 defer.returnValue(self.__deleteBlogPosts(posts, comments, profile)) | 457 defer.returnValue(self.__deleteBlogPosts(posts, comments, profile)) |
369 defer.returnValue(error_ui()) | 458 defer.returnValue(error_ui()) |
370 """ | 459 """ |
371 | 460 |
372 # check for password modification | 461 # check for password modification |
373 current_passwd = data[xml_tools.SAT_FORM_PREFIX + 'current_passwd'] | 462 current_passwd = data[xml_tools.SAT_FORM_PREFIX + "current_passwd"] |
374 new_passwd1 = data[xml_tools.SAT_FORM_PREFIX + 'new_passwd1'] | 463 new_passwd1 = data[xml_tools.SAT_FORM_PREFIX + "new_passwd1"] |
375 new_passwd2 = data[xml_tools.SAT_FORM_PREFIX + 'new_passwd2'] | 464 new_passwd2 = data[xml_tools.SAT_FORM_PREFIX + "new_passwd2"] |
376 if new_passwd1 or new_passwd2: | 465 if new_passwd1 or new_passwd2: |
377 verified = yield verify(current_passwd) | 466 verified = yield verify(current_passwd) |
378 assert isinstance(verified, bool) | 467 assert isinstance(verified, bool) |
379 if verified: | 468 if verified: |
380 if new_passwd1 == new_passwd2: | 469 if new_passwd1 == new_passwd2: |
381 data = yield self.__changePassword(new_passwd1, profile=profile) | 470 data = yield self.__changePassword(new_passwd1, profile=profile) |
382 defer.returnValue(data) | 471 defer.returnValue(data) |
383 else: | 472 else: |
384 defer.returnValue(error_ui(D_("The values entered for the new password are not equal."))) | 473 defer.returnValue( |
474 error_ui( | |
475 D_("The values entered for the new password are not equal.") | |
476 ) | |
477 ) | |
385 defer.returnValue(error_ui()) | 478 defer.returnValue(error_ui()) |
386 | 479 |
387 defer.returnValue({}) | 480 defer.returnValue({}) |
388 | 481 |
389 def __changePassword(self, password, profile): | 482 def __changePassword(self, password, profile): |
390 """Ask for a confirmation before changing the XMPP account and SàT profile passwords. | 483 """Ask for a confirmation before changing the XMPP account and SàT profile passwords. |
391 | 484 |
392 @param password (str): the new password | 485 @param password (str): the new password |
393 @param profile (str): %(doc_profile)s | 486 @param profile (str): %(doc_profile)s |
394 """ | 487 """ |
395 session_id, dummy = self._sessions.newSession({'new_password': password}, profile=profile) | 488 session_id, dummy = self._sessions.newSession( |
396 form_ui = xml_tools.XMLUI("form", title=D_("Change your password?"), submit_id=self.__change_password_id, session_id=session_id) | 489 {"new_password": password}, profile=profile |
397 form_ui.addText(D_("Note for advanced users: this will actually change both your SàT profile password AND your XMPP account password.")) | 490 ) |
491 form_ui = xml_tools.XMLUI( | |
492 "form", | |
493 title=D_("Change your password?"), | |
494 submit_id=self.__change_password_id, | |
495 session_id=session_id, | |
496 ) | |
497 form_ui.addText( | |
498 D_( | |
499 "Note for advanced users: this will actually change both your SàT profile password AND your XMPP account password." | |
500 ) | |
501 ) | |
398 form_ui.addText(D_("Continue with changing the password?")) | 502 form_ui.addText(D_("Continue with changing the password?")) |
399 return {'xmlui': form_ui.toXml()} | 503 return {"xmlui": form_ui.toXml()} |
400 | 504 |
401 def __changePasswordCb(self, data, profile): | 505 def __changePasswordCb(self, data, profile): |
402 """Actually change the user XMPP account and SàT profile password | 506 """Actually change the user XMPP account and SàT profile password |
403 @param data (dict) | 507 @param data (dict) |
404 @profile (str): %(doc_profile)s | 508 @profile (str): %(doc_profile)s |
405 """ | 509 """ |
406 client = self.host.getClient(profile) | 510 client = self.host.getClient(profile) |
407 password = self._sessions.profileGet(data['session_id'], profile)['new_password'] | 511 password = self._sessions.profileGet(data["session_id"], profile)["new_password"] |
408 del self._sessions[data['session_id']] | 512 del self._sessions[data["session_id"]] |
409 | 513 |
410 def passwordChanged(dummy): | 514 def passwordChanged(dummy): |
411 d = self.host.memory.setParam(C.PROFILE_PASS_PATH[1], password, C.PROFILE_PASS_PATH[0], profile_key=profile) | 515 d = self.host.memory.setParam( |
412 d.addCallback(lambda dummy: self.host.memory.setParam("Password", password, "Connection", profile_key=profile)) | 516 C.PROFILE_PASS_PATH[1], |
517 password, | |
518 C.PROFILE_PASS_PATH[0], | |
519 profile_key=profile, | |
520 ) | |
521 d.addCallback( | |
522 lambda dummy: self.host.memory.setParam( | |
523 "Password", password, "Connection", profile_key=profile | |
524 ) | |
525 ) | |
413 confirm_ui = xml_tools.XMLUI("popup", title=D_("Confirmation")) | 526 confirm_ui = xml_tools.XMLUI("popup", title=D_("Confirmation")) |
414 confirm_ui.addText(D_("Your password has been changed.")) | 527 confirm_ui.addText(D_("Your password has been changed.")) |
415 return defer.succeed({'xmlui': confirm_ui.toXml()}) | 528 return defer.succeed({"xmlui": confirm_ui.toXml()}) |
416 | 529 |
417 def errback(failure): | 530 def errback(failure): |
418 error_ui = xml_tools.XMLUI("popup", title=D_("Error")) | 531 error_ui = xml_tools.XMLUI("popup", title=D_("Error")) |
419 error_ui.addText(D_("Your password could not be changed: %s") % failure.getErrorMessage()) | 532 error_ui.addText( |
420 return defer.succeed({'xmlui': error_ui.toXml()}) | 533 D_("Your password could not be changed: %s") % failure.getErrorMessage() |
421 | 534 ) |
422 d = self.host.plugins['XEP-0077'].changePassword(client, password) | 535 return defer.succeed({"xmlui": error_ui.toXml()}) |
536 | |
537 d = self.host.plugins["XEP-0077"].changePassword(client, password) | |
423 d.addCallbacks(passwordChanged, errback) | 538 d.addCallbacks(passwordChanged, errback) |
424 return d | 539 return d |
425 | 540 |
426 def __deleteAccount(self, profile): | 541 def __deleteAccount(self, profile): |
427 """Ask for a confirmation before deleting the XMPP account and SàT profile | 542 """Ask for a confirmation before deleting the XMPP account and SàT profile |
428 @param profile | 543 @param profile |
429 """ | 544 """ |
430 form_ui = xml_tools.XMLUI("form", title=D_("Delete your account?"), submit_id=self.__delete_account_id) | 545 form_ui = xml_tools.XMLUI( |
431 form_ui.addText(D_("If you confirm this dialog, you will be disconnected and then your XMPP account AND your SàT profile will both be DELETED.")) | 546 "form", title=D_("Delete your account?"), submit_id=self.__delete_account_id |
432 target = D_('contact list, messages history, blog posts and comments' if 'GROUPBLOG' in self.host.plugins else D_('contact list and messages history')) | 547 ) |
433 form_ui.addText(D_("All your data stored on %(server)s, including your %(target)s will be erased.") % {'server': self.getNewAccountDomain(), 'target': target}) | 548 form_ui.addText( |
434 form_ui.addText(D_("There is no other confirmation dialog, this is the very last one! Are you sure?")) | 549 D_( |
435 return {'xmlui': form_ui.toXml()} | 550 "If you confirm this dialog, you will be disconnected and then your XMPP account AND your SàT profile will both be DELETED." |
551 ) | |
552 ) | |
553 target = D_( | |
554 "contact list, messages history, blog posts and comments" | |
555 if "GROUPBLOG" in self.host.plugins | |
556 else D_("contact list and messages history") | |
557 ) | |
558 form_ui.addText( | |
559 D_( | |
560 "All your data stored on %(server)s, including your %(target)s will be erased." | |
561 ) | |
562 % {"server": self.getNewAccountDomain(), "target": target} | |
563 ) | |
564 form_ui.addText( | |
565 D_( | |
566 "There is no other confirmation dialog, this is the very last one! Are you sure?" | |
567 ) | |
568 ) | |
569 return {"xmlui": form_ui.toXml()} | |
436 | 570 |
437 def __deleteAccountCb(self, data, profile): | 571 def __deleteAccountCb(self, data, profile): |
438 """Actually delete the XMPP account and SàT profile | 572 """Actually delete the XMPP account and SàT profile |
439 | 573 |
440 @param data | 574 @param data |
441 @param profile | 575 @param profile |
442 """ | 576 """ |
443 client = self.host.getClient(profile) | 577 client = self.host.getClient(profile) |
578 | |
444 def userDeleted(dummy): | 579 def userDeleted(dummy): |
445 | 580 |
446 # FIXME: client should be disconnected at this point, so 2 next loop should be removed (to be confirmed) | 581 # FIXME: client should be disconnected at this point, so 2 next loop should be removed (to be confirmed) |
447 for jid_ in client.roster._jids: # empty roster | 582 for jid_ in client.roster._jids: # empty roster |
448 client.presence.unsubscribe(jid_) | 583 client.presence.unsubscribe(jid_) |
449 | 584 |
450 for jid_ in self.host.memory.getWaitingSub(profile): # delete waiting subscriptions | 585 for jid_ in self.host.memory.getWaitingSub( |
586 profile | |
587 ): # delete waiting subscriptions | |
451 self.host.memory.delWaitingSub(jid_) | 588 self.host.memory.delWaitingSub(jid_) |
452 | 589 |
453 delete_profile = lambda: self.host.memory.asyncDeleteProfile(profile, force=True) | 590 delete_profile = lambda: self.host.memory.asyncDeleteProfile( |
454 if 'GROUPBLOG' in self.host.plugins: | 591 profile, force=True |
455 d = self.host.plugins['GROUPBLOG'].deleteAllGroupBlogsAndComments(profile_key=profile) | 592 ) |
593 if "GROUPBLOG" in self.host.plugins: | |
594 d = self.host.plugins["GROUPBLOG"].deleteAllGroupBlogsAndComments( | |
595 profile_key=profile | |
596 ) | |
456 d.addCallback(lambda dummy: delete_profile()) | 597 d.addCallback(lambda dummy: delete_profile()) |
457 else: | 598 else: |
458 delete_profile() | 599 delete_profile() |
459 | 600 |
460 return defer.succeed({}) | 601 return defer.succeed({}) |
461 | 602 |
462 def errback(failure): | 603 def errback(failure): |
463 error_ui = xml_tools.XMLUI("popup", title=D_("Error")) | 604 error_ui = xml_tools.XMLUI("popup", title=D_("Error")) |
464 error_ui.addText(D_("Your XMPP account could not be deleted: %s") % failure.getErrorMessage()) | 605 error_ui.addText( |
465 return defer.succeed({'xmlui': error_ui.toXml()}) | 606 D_("Your XMPP account could not be deleted: %s") |
466 | 607 % failure.getErrorMessage() |
467 d = self.host.plugins['XEP-0077'].unregister(client, jid.JID(client.jid.host)) | 608 ) |
609 return defer.succeed({"xmlui": error_ui.toXml()}) | |
610 | |
611 d = self.host.plugins["XEP-0077"].unregister(client, jid.JID(client.jid.host)) | |
468 d.addCallbacks(userDeleted, errback) | 612 d.addCallbacks(userDeleted, errback) |
469 return d | 613 return d |
470 | 614 |
471 def __deleteBlogPosts(self, posts, comments, profile): | 615 def __deleteBlogPosts(self, posts, comments, profile): |
472 """Ask for a confirmation before deleting the blog posts | 616 """Ask for a confirmation before deleting the blog posts |
475 @param data | 619 @param data |
476 @param profile | 620 @param profile |
477 """ | 621 """ |
478 if posts: | 622 if posts: |
479 if comments: # delete everything | 623 if comments: # delete everything |
480 form_ui = xml_tools.XMLUI("form", title=D_("Delete all your (micro-)blog posts and comments?"), submit_id=self.__delete_posts_comments_id) | 624 form_ui = xml_tools.XMLUI( |
481 form_ui.addText(D_("If you confirm this dialog, all the (micro-)blog data you submitted will be erased.")) | 625 "form", |
482 form_ui.addText(D_("These are the public and private posts and comments you sent to any group.")) | 626 title=D_("Delete all your (micro-)blog posts and comments?"), |
483 form_ui.addText(D_("There is no other confirmation dialog, this is the very last one! Are you sure?")) | 627 submit_id=self.__delete_posts_comments_id, |
628 ) | |
629 form_ui.addText( | |
630 D_( | |
631 "If you confirm this dialog, all the (micro-)blog data you submitted will be erased." | |
632 ) | |
633 ) | |
634 form_ui.addText( | |
635 D_( | |
636 "These are the public and private posts and comments you sent to any group." | |
637 ) | |
638 ) | |
639 form_ui.addText( | |
640 D_( | |
641 "There is no other confirmation dialog, this is the very last one! Are you sure?" | |
642 ) | |
643 ) | |
484 else: # delete only the posts | 644 else: # delete only the posts |
485 form_ui = xml_tools.XMLUI("form", title=D_("Delete all your (micro-)blog posts?"), submit_id=self.__delete_posts_id) | 645 form_ui = xml_tools.XMLUI( |
486 form_ui.addText(D_("If you confirm this dialog, all the public and private posts you sent to any group will be erased.")) | 646 "form", |
487 form_ui.addText(D_("There is no other confirmation dialog, this is the very last one! Are you sure?")) | 647 title=D_("Delete all your (micro-)blog posts?"), |
648 submit_id=self.__delete_posts_id, | |
649 ) | |
650 form_ui.addText( | |
651 D_( | |
652 "If you confirm this dialog, all the public and private posts you sent to any group will be erased." | |
653 ) | |
654 ) | |
655 form_ui.addText( | |
656 D_( | |
657 "There is no other confirmation dialog, this is the very last one! Are you sure?" | |
658 ) | |
659 ) | |
488 elif comments: # delete only the comments | 660 elif comments: # delete only the comments |
489 form_ui = xml_tools.XMLUI("form", title=D_("Delete all your (micro-)blog comments?"), submit_id=self.__delete_comments_id) | 661 form_ui = xml_tools.XMLUI( |
490 form_ui.addText(D_("If you confirm this dialog, all the public and private comments you made on other people's posts will be erased.")) | 662 "form", |
491 form_ui.addText(D_("There is no other confirmation dialog, this is the very last one! Are you sure?")) | 663 title=D_("Delete all your (micro-)blog comments?"), |
492 | 664 submit_id=self.__delete_comments_id, |
493 return {'xmlui': form_ui.toXml()} | 665 ) |
666 form_ui.addText( | |
667 D_( | |
668 "If you confirm this dialog, all the public and private comments you made on other people's posts will be erased." | |
669 ) | |
670 ) | |
671 form_ui.addText( | |
672 D_( | |
673 "There is no other confirmation dialog, this is the very last one! Are you sure?" | |
674 ) | |
675 ) | |
676 | |
677 return {"xmlui": form_ui.toXml()} | |
494 | 678 |
495 def __deleteBlogPostsCb(self, posts, comments, data, profile): | 679 def __deleteBlogPostsCb(self, posts, comments, data, profile): |
496 """Actually delete the XMPP account and SàT profile | 680 """Actually delete the XMPP account and SàT profile |
497 @param posts: delete all posts of the user (and their comments) | 681 @param posts: delete all posts of the user (and their comments) |
498 @param comments: delete all the comments of the user on other's posts | 682 @param comments: delete all the comments of the user on other's posts |
499 @param profile | 683 @param profile |
500 """ | 684 """ |
501 if posts: | 685 if posts: |
502 if comments: | 686 if comments: |
503 target = D_('blog posts and comments') | 687 target = D_("blog posts and comments") |
504 d = self.host.plugins['GROUPBLOG'].deleteAllGroupBlogsAndComments(profile_key=profile) | 688 d = self.host.plugins["GROUPBLOG"].deleteAllGroupBlogsAndComments( |
689 profile_key=profile | |
690 ) | |
505 else: | 691 else: |
506 target = D_('blog posts') | 692 target = D_("blog posts") |
507 d = self.host.plugins['GROUPBLOG'].deleteAllGroupBlogs(profile_key=profile) | 693 d = self.host.plugins["GROUPBLOG"].deleteAllGroupBlogs( |
694 profile_key=profile | |
695 ) | |
508 elif comments: | 696 elif comments: |
509 target = D_('comments') | 697 target = D_("comments") |
510 d = self.host.plugins['GROUPBLOG'].deleteAllGroupBlogsComments(profile_key=profile) | 698 d = self.host.plugins["GROUPBLOG"].deleteAllGroupBlogsComments( |
699 profile_key=profile | |
700 ) | |
511 | 701 |
512 def deleted(result): | 702 def deleted(result): |
513 ui = xml_tools.XMLUI("popup", title=D_("Deletion confirmation")) | 703 ui = xml_tools.XMLUI("popup", title=D_("Deletion confirmation")) |
514 # TODO: change the message when delete/retract notifications are done with XEP-0060 | 704 # TODO: change the message when delete/retract notifications are done with XEP-0060 |
515 ui.addText(D_("Your %(target)s have been deleted.") % {'target': target}) | 705 ui.addText(D_("Your %(target)s have been deleted.") % {"target": target}) |
516 ui.addText(D_("Known issue of the demo version: you need to refresh the page to make the deleted posts actually disappear.")) | 706 ui.addText( |
517 return defer.succeed({'xmlui': ui.toXml()}) | 707 D_( |
708 "Known issue of the demo version: you need to refresh the page to make the deleted posts actually disappear." | |
709 ) | |
710 ) | |
711 return defer.succeed({"xmlui": ui.toXml()}) | |
518 | 712 |
519 def errback(failure): | 713 def errback(failure): |
520 error_ui = xml_tools.XMLUI("popup", title=D_("Error")) | 714 error_ui = xml_tools.XMLUI("popup", title=D_("Error")) |
521 error_ui.addText(D_("Your %(target)s could not be deleted: %(message)s") % {'target': target, 'message': failure.getErrorMessage()}) | 715 error_ui.addText( |
522 return defer.succeed({'xmlui': error_ui.toXml()}) | 716 D_("Your %(target)s could not be deleted: %(message)s") |
717 % {"target": target, "message": failure.getErrorMessage()} | |
718 ) | |
719 return defer.succeed({"xmlui": error_ui.toXml()}) | |
523 | 720 |
524 d.addCallbacks(deleted, errback) | 721 d.addCallbacks(deleted, errback) |
525 return d | 722 return d |
526 | 723 |
527 def asyncConnectWithXMPPCredentials(self, jid_s, password): | 724 def asyncConnectWithXMPPCredentials(self, jid_s, password): |
539 pass | 736 pass |
540 else: | 737 else: |
541 raise exceptions.ConflictError | 738 raise exceptions.ConflictError |
542 | 739 |
543 d = self.createProfile(password, jid_s, jid_s) | 740 d = self.createProfile(password, jid_s, jid_s) |
544 d.addCallback(lambda dummy: self.host.memory.getProfileName(jid_s)) # checks if the profile has been successfuly created | 741 d.addCallback( |
742 lambda dummy: self.host.memory.getProfileName(jid_s) | |
743 ) # checks if the profile has been successfuly created | |
545 d.addCallback(self.host.connect, password, {}, 0) | 744 d.addCallback(self.host.connect, password, {}, 0) |
546 | |
547 | 745 |
548 def connected(result): | 746 def connected(result): |
549 self.sendEmails(None, profile=jid_s) | 747 self.sendEmails(None, profile=jid_s) |
550 return result | 748 return result |
551 | 749 |
552 def removeProfile(failure): # profile has been successfully created but the XMPP credentials are wrong! | 750 def removeProfile( |
553 log.debug("Removing previously auto-created profile: %s" % failure.getErrorMessage()) | 751 failure |
752 ): # profile has been successfully created but the XMPP credentials are wrong! | |
753 log.debug( | |
754 "Removing previously auto-created profile: %s" % failure.getErrorMessage() | |
755 ) | |
554 self.host.memory.asyncDeleteProfile(jid_s) | 756 self.host.memory.asyncDeleteProfile(jid_s) |
555 raise failure | 757 raise failure |
556 | 758 |
557 # FIXME: we don't catch the case where the JID host is not an XMPP server, and the user | 759 # FIXME: we don't catch the case where the JID host is not an XMPP server, and the user |
558 # has to wait until the DBUS timeout ; as a consequence, emails are sent to the admins | 760 # has to wait until the DBUS timeout ; as a consequence, emails are sent to the admins |