Mercurial > libervia-backend
comparison src/plugins/plugin_misc_account.py @ 730:32bbabe809da
plugin account: configuration constants can be overriden in sat.conf (section "plugin account") + better deferred management in email sending
author | Goffi <goffi@goffi.org> |
---|---|
date | Fri, 13 Dec 2013 17:15:57 +0100 |
parents | 712e3782af12 |
children | ffc3ddcdaf48 |
comparison
equal
deleted
inserted
replaced
729:8f50a0079769 | 730:32bbabe809da |
---|---|
1 #!/usr/bin/python | 1 #!/usr/bin/python |
2 # -*- coding: utf-8 -*- | 2 # -*- coding: utf-8 -*- |
3 | 3 |
4 # SAT plugin for parrot mode (experimental) | 4 # SAT plugin for account creation (experimental) |
5 # Copyright (C) 2009, 2010, 2011, 2012, 2013 Jérôme Poisson (goffi@goffi.org) | 5 # Copyright (C) 2009, 2010, 2011, 2012, 2013 Jérôme Poisson (goffi@goffi.org) |
6 | 6 |
7 # This program is free software: you can redistribute it and/or modify | 7 # This program is free software: you can redistribute it and/or modify |
8 # it under the terms of the GNU Affero General Public License as published by | 8 # it under the terms of the GNU Affero General Public License as published by |
9 # the Free Software Foundation, either version 3 of the License, or | 9 # the Free Software Foundation, either version 3 of the License, or |
35 "main": "MiscAccount", | 35 "main": "MiscAccount", |
36 "handler": "no", | 36 "handler": "no", |
37 "description": _(u"""SàT account creation""") | 37 "description": _(u"""SàT account creation""") |
38 } | 38 } |
39 | 39 |
40 #You need do adapt the following consts to your server | 40 CONFIG_SECTION = "plugin account" |
41 _REG_EMAIL_FROM = "NOREPLY@example.net" | 41 |
42 _REG_EMAIL_SERVER = "localhost" | 42 # You need do adapt the following consts to your server |
43 _REG_ADMIN_EMAIL = "admin@example.net" | 43 # all theses values (key=option name, value=default) can (and should) be overriden in sat.conf |
44 _NEW_ACCOUNT_SERVER = "localhost" | 44 # in section CONFIG_SECTION |
45 _NEW_ACCOUNT_DOMAIN = "example.net" | 45 |
46 _NEW_ACCOUNT_RESOURCE = "libervia" | 46 default_conf = {"email_from": "NOREPLY@example.net", |
47 _PROSODY_PATH = None # prosody path (where prosodyctl will be executed from), or None to automaticaly find it | 47 "email_server": "localhost", |
48 _PROSODYCTL = "prosodyctl" | 48 "admin_email": "admin@example.net", |
49 | 49 "new_account_server": "localhost", |
50 RESERVED = ['libervia'] | 50 "new_account_domain": "example.net", |
51 "new_account_resource": "libervia", | |
52 "prosody_path": None, # prosody path (where prosodyctl will be executed from), or None to automaticaly find it | |
53 "prosodyctl": "prosodyctl", | |
54 "reserved_list": ['libervia'] # profiles which can't be used | |
55 } | |
51 | 56 |
52 | 57 |
53 class ProsodyRegisterProtocol(protocol.ProcessProtocol): | 58 class ProsodyRegisterProtocol(protocol.ProcessProtocol): |
54 """ Try to register an account with prosody """ | 59 """ Try to register an account with prosody """ |
55 | 60 |
79 | 84 |
80 class MiscAccount(object): | 85 class MiscAccount(object): |
81 """Account plugin: create a SàT + Prosody account, used by Libervia""" | 86 """Account plugin: create a SàT + Prosody account, used by Libervia""" |
82 #XXX: This plugin is a Q&D one used for the demo. Something more generic (and not | 87 #XXX: This plugin is a Q&D one used for the demo. Something more generic (and not |
83 # only focused on Prosody) is planed | 88 # only focused on Prosody) is planed |
84 _prosody_path = _PROSODY_PATH or '' | |
85 | 89 |
86 def __init__(self, host): | 90 def __init__(self, host): |
87 info(_(u"Plugin Account initialization")) | 91 info(_(u"Plugin Account initialization")) |
88 self.host = host | 92 self.host = host |
89 host.bridge.addMethod("registerSatAccount", ".plugin", in_sign='sss', out_sign='', method=self._registerAccount, async=True) | 93 host.bridge.addMethod("registerSatAccount", ".plugin", in_sign='sss', out_sign='', method=self._registerAccount, async=True) |
90 host.bridge.addMethod("getNewAccountDomain", ".plugin", in_sign='', out_sign='s', method=self._getNewAccountDomain, async=False) | 94 host.bridge.addMethod("getNewAccountDomain", ".plugin", in_sign='', out_sign='s', method=self._getNewAccountDomain, async=False) |
91 if not self._prosody_path: | 95 self._prosody_path = self.getConfig('prosody_path') |
92 paths = which(_PROSODYCTL) | 96 if self._prosody_path is None: |
97 paths = which(self.getConfig('prosodyctl')) | |
93 if not paths: | 98 if not paths: |
94 error(_("Can't find %s") % (_PROSODYCTL, )) | 99 error(_("Can't find %s") % (self.getConfig('prosodyctl'), )) |
95 else: | 100 else: |
96 self._prosody_path = dirname(paths[0]) | 101 self._prosody_path = dirname(paths[0]) |
97 info(_('Prosody path found: %s') % (self._prosody_path, )) | 102 info(_('Prosody path found: %s') % (self._prosody_path, )) |
103 | |
104 def getConfig(self, name): | |
105 return self.host.memory.getConfig(CONFIG_SECTION, name) or default_conf[name] | |
98 | 106 |
99 def _registerAccount(self, email, password, profile): | 107 def _registerAccount(self, email, password, profile): |
100 | 108 |
101 """ | 109 """ |
102 #Password Generation | 110 #Password Generation |
107 password = ''.join([random.choice(_charset) for i in range(15)]) | 115 password = ''.join([random.choice(_charset) for i in range(15)]) |
108 """ | 116 """ |
109 if not email or not password or not profile: | 117 if not email or not password or not profile: |
110 raise exceptions.DataError | 118 raise exceptions.DataError |
111 | 119 |
112 if profile.lower() in RESERVED: | 120 if profile.lower() in self.getConfig('reserved_list'): |
113 return defer.fail(Failure(u'CONFLICT')) | 121 return defer.fail(Failure(u'CONFLICT')) |
114 | 122 |
115 d = self.host.memory.asyncCreateProfile(profile) | 123 d = self.host.memory.asyncCreateProfile(profile) |
116 d.addCallback(self._profileRegistered, email, password, profile) | 124 d.addCallback(self._profileRegistered, email, password, profile) |
117 return d | 125 return d |
118 | 126 |
119 def _profileRegistered(self, result, email, password, profile): | 127 def _profileRegistered(self, result, email, password, profile): |
120 | 128 |
121 #FIXME: values must be in a config file instead of hardcoded | 129 #FIXME: values must be in a config file instead of hardcoded |
122 self.host.memory.setParam("JabberID", "%s@%s/%s" % (profile, _NEW_ACCOUNT_DOMAIN, _NEW_ACCOUNT_RESOURCE), | 130 self.host.memory.setParam("JabberID", "%s@%s/%s" % (profile, self.getConfig('new_account_domain'), self.getConfig('new_account_resource')), |
123 "Connection", profile_key=profile) | 131 "Connection", profile_key=profile) |
124 self.host.memory.setParam("Server", _NEW_ACCOUNT_SERVER, | 132 self.host.memory.setParam("Server", self.getConfig('new_account_server'), |
125 "Connection", profile_key=profile) | 133 "Connection", profile_key=profile) |
126 self.host.memory.setParam("Password", password, | 134 self.host.memory.setParam("Password", password, |
127 "Connection", profile_key=profile) | 135 "Connection", profile_key=profile) |
128 #and the account | 136 #and the account |
129 | 137 |
130 #XXX: we use "prosodyctl adduser" because "register" doesn't check conflict | 138 #XXX: we use "prosodyctl adduser" because "register" doesn't check conflict |
131 # and just change the password if the account already exists | 139 # and just change the password if the account already exists |
132 d = defer.Deferred() | 140 d = defer.Deferred() |
133 prosody_reg = ProsodyRegisterProtocol(password, d) | 141 prosody_reg = ProsodyRegisterProtocol(password, d) |
134 prosody_exe = join(self._prosody_path, _PROSODYCTL) | 142 prosody_exe = join(self._prosody_path, self.getConfig('prosodyctl')) |
135 reactor.spawnProcess(prosody_reg, prosody_exe, [prosody_exe, 'adduser', "%s@%s" % (profile, _NEW_ACCOUNT_DOMAIN)], path=self._prosody_path) | 143 reactor.spawnProcess(prosody_reg, prosody_exe, [prosody_exe, 'adduser', "%s@%s" % (profile, self.getConfig('new_account_domain'))], path=self._prosody_path) |
136 | 144 |
137 d.addCallback(self._accountCreated, profile, email, password) | 145 d.addCallback(self._sendEmails, profile, email, password) |
146 d.addCallback(lambda ignore: None) | |
138 return d | 147 return d |
139 | 148 |
140 def _accountCreated(self, result, login, email, password): | 149 def _sendEmails(self, result, login, email, password): |
141 #time to send the email | 150 #time to send the email |
142 | 151 |
143 _email_host = _REG_EMAIL_SERVER | 152 _email_host = self.getConfig('email_server') |
144 _email_from = _REG_EMAIL_FROM | 153 _email_from = self.getConfig("email_from") |
145 | 154 |
146 def email_ok(ignore): | 155 def email_ok(ignore): |
147 print ("Account creation email sent to %s" % email) | 156 print ("Account creation email sent to %s" % email) |
148 | 157 |
149 def email_ko(ignore): | 158 def email_ko(ignore): |
166 follow SàT news: http://www.goffi.org | 175 follow SàT news: http://www.goffi.org |
167 | 176 |
168 Any feedback welcome | 177 Any feedback welcome |
169 | 178 |
170 Cheers | 179 Cheers |
171 Goffi""" % {'login': login, 'password': password, 'jid': "%s@%s" % (login, _NEW_ACCOUNT_DOMAIN)}).encode('utf-8') | 180 Goffi""" % {'login': login, 'password': password, 'jid': "%s@%s" % (login, self.getConfig('new_account_domain'))}).encode('utf-8') |
172 msg = MIMEText(body, 'plain', 'UTF-8') | 181 msg = MIMEText(body, 'plain', 'UTF-8') |
173 msg['Subject'] = 'Libervia account created' | 182 msg['Subject'] = 'Libervia account created' |
174 msg['From'] = _email_from | 183 msg['From'] = _email_from |
175 msg['To'] = email | 184 msg['To'] = email |
176 | 185 |
177 d = sendmail(_email_host, _email_from, email, msg.as_string()) | 186 d_user = sendmail(_email_host, _email_from, email, msg.as_string()) |
178 d.addCallbacks(email_ok, email_ko) | 187 d_user.addCallbacks(email_ok, email_ko) |
188 | |
179 #email to the administrator | 189 #email to the administrator |
180 | |
181 body = (u"""New account created: %(login)s [%(email)s]""" % {'login': login, 'email': email}).encode('utf-8') | 190 body = (u"""New account created: %(login)s [%(email)s]""" % {'login': login, 'email': email}).encode('utf-8') |
182 msg = MIMEText(body, 'plain', 'UTF-8') | 191 msg = MIMEText(body, 'plain', 'UTF-8') |
183 msg['Subject'] = 'Libervia new account created' | 192 msg['Subject'] = 'Libervia new account created' |
184 msg['From'] = _email_from | 193 msg['From'] = _email_from |
185 msg['To'] = _REG_ADMIN_EMAIL | 194 msg['To'] = self.getConfig('admin_email') |
186 | 195 |
187 d = sendmail(_email_host, _email_from, _REG_ADMIN_EMAIL, msg.as_string()) | 196 d_admin = sendmail(_email_host, _email_from, self.getConfig('admin_email'), msg.as_string()) |
188 d.addCallbacks(email_ok, email_ko) | 197 d_admin.addCallbacks(email_ok, email_ko) |
198 return defer.DeferredList([d_user, d_admin]) | |
189 | 199 |
190 def _getNewAccountDomain(self): | 200 def _getNewAccountDomain(self): |
191 """@return: the domain that will be set to new account""" | 201 """@return: the domain that will be set to new account""" |
192 return _NEW_ACCOUNT_DOMAIN | 202 return self.getConfig('new_account_domain') |
193 | 203 |