22f204b9427af48fa1271d6e9b095129bae00aa7
[odoo/odoo.git] / addons / survey / wizard / survey_email_compose_message.py
1 # -*- coding: utf-8 -*-
2 ##############################################################################
3 #
4 #    OpenERP, Open Source Management Solution
5 #    Copyright (C) 2010-Today OpenERP SA (<http://www.openerp.com>)
6 #
7 #    This program is free software: you can redistribute it and/or modify
8 #    it under the terms of the GNU General Public License as published by
9 #    the Free Software Foundation, either version 3 of the License, or
10 #    (at your option) any later version.
11 #
12 #    This program is distributed in the hope that it will be useful,
13 #    but WITHOUT ANY WARRANTY; without even the implied warranty of
14 #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 #    GNU General Public License for more details.
16 #
17 #    You should have received a copy of the GNU General Public License
18 #    along with this program.  If not, see <http://www.gnu.org/licenses/>
19 #
20 ##############################################################################
21
22 from openerp.osv import osv
23 from openerp.osv import fields
24 from openerp.tools.translate import _
25 from datetime import datetime
26
27 import re
28 import uuid
29 import urlparse
30
31 emails_split = re.compile(r"[;,\n\r]+")
32
33
34 class survey_mail_compose_message(osv.TransientModel):
35     _name = 'survey.mail.compose.message'
36     _inherit = 'mail.compose.message'
37     _description = 'Email composition wizard for Survey'
38     _log_access = True
39
40     def _get_public_url(self, cr, uid, ids, name, arg, context=None):
41         res = dict((id, 0) for id in ids)
42         survey_obj = self.pool.get('survey.survey')
43         for wizard in self.browse(cr, uid, ids, context=context):
44             res[wizard.id] = survey_obj.browse(cr, uid, wizard.survey_id, context=context).public_url
45         return res
46
47     def _get_public_url_html(self, cr, uid, ids, name, arg, context=None):
48         """ Compute if the message is unread by the current user """
49         urls = self._get_public_url(cr, uid, ids, name, arg, context=context)
50         for key, url in urls.items():
51             urls[key] = '<a href="%s">%s</a>' % (url, _("Click here to start survey"))
52         return urls
53
54     _columns = {
55         'survey_id': fields.many2one('survey.survey', 'Survey', required=True),
56         'public': fields.selection([('public_link', 'Share the public web link to your audience.'),
57                                     ('email_public_link', 'Send by email the public web link to your audience.'),
58                                     ('email_private', 'Send private invitation to your audience (only one response per recipient and per invitation).')],
59             string='Share options', required=True),
60         'public_url': fields.function(_get_public_url, string="Public url", type="char"),
61         'public_url_html': fields.function(_get_public_url_html, string="Public HTML web link", type="char"),
62         'partner_ids': fields.many2many('res.partner',
63             'survey_mail_compose_message_res_partner_rel',
64             'wizard_id', 'partner_id', 'Existing contacts'),
65         'attachment_ids': fields.many2many('ir.attachment',
66             'survey_mail_compose_message_ir_attachments_rel',
67             'wizard_id', 'attachment_id', 'Attachments'),
68         'multi_email': fields.text(string='List of emails', help="This list of emails of recipients will not converted in contacts. Emails separated by commas, semicolons or newline."),
69         'date_deadline': fields.date(string="Deadline to which the invitation to respond is valid", help="Deadline to which the invitation to respond for this survey is valid. If the field is empty, the invitation is still valid."),
70     }
71
72     _defaults = {
73         'public': 'public_link',
74         'survey_id': lambda self, cr, uid, ctx={}: ctx.get('model') == 'survey.survey' and ctx.get('res_id') or None
75     }
76
77     def default_get(self, cr, uid, fields, context=None):
78         res = super(survey_mail_compose_message, self).default_get(cr, uid, fields, context=context)
79         if context.get('active_model') == 'res.partner' and context.get('active_ids'):
80             res.update({'partner_ids': context.get('active_ids')})
81         return res
82
83     def onchange_multi_email(self, cr, uid, ids, multi_email, context=None):
84         emails = list(set(emails_split.split(multi_email or "")))
85         emails_checked = []
86         error_message = ""
87         for email in emails:
88             email = email.strip()
89             if email:
90                 if not re.search(r"^[^@]+@[^@]+$", email):
91                     error_message += "\n'%s'" % email
92                 else:
93                     emails_checked.append(email)
94         if error_message:
95             raise osv.except_osv(_('Warning!'), _("One email at least is incorrect: %s" % error_message))
96
97         emails_checked.sort()
98         values = {'multi_email': '\n'.join(emails_checked)}
99         return {'value': values}
100
101     def onchange_survey_id(self, cr, uid, ids, survey_id, context=None):
102         """ Compute if the message is unread by the current user. """
103         if survey_id:
104             survey = self.pool.get('survey.survey').browse(cr, uid, survey_id, context=context)
105             return {
106                 'value': {
107                     'subject': survey.title,
108                     'public_url': survey.public_url,
109                     'public_url_html': '<a href="%s">%s</a>' % (survey.public_url, _("Click here to take survey")),
110                 }}
111         else:
112             txt = _("Please select a survey")
113             return {
114                 'value': {
115                     'public_url': txt,
116                     'public_url_html': txt,
117                 }}
118
119     #------------------------------------------------------
120     # Wizard validation and send
121     #------------------------------------------------------
122
123     def send_mail(self, cr, uid, ids, context=None):
124         """ Process the wizard content and proceed with sending the related
125             email(s), rendering any template patterns on the fly if needed """
126         if context is None:
127             context = {}
128
129         survey_response_obj = self.pool.get('survey.user_input')
130         partner_obj = self.pool.get('res.partner')
131         mail_mail_obj = self.pool.get('mail.mail')
132         try:
133             model, anonymous_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'portal', 'group_anonymous')
134         except ValueError:
135             anonymous_id = None
136
137         def create_response_and_send_mail(wizard, token, partner_id, email):
138             """ Create one mail by recipients and replace __URL__ by link with identification token """
139             #set url
140             url = wizard.survey_id.public_url
141
142             url = urlparse.urlparse(url).path[1:]  # dirty hack to avoid incorrect urls
143
144             if token:
145                 url = url + '/' + token
146
147             # post the message
148             values = {
149                 'model': None,
150                 'res_id': None,
151                 'subject': wizard.subject,
152                 'body': wizard.body.replace("__URL__", url),
153                 'body_html': wizard.body.replace("__URL__", url),
154                 'parent_id': None,
155                 'partner_ids': partner_id and [(4, partner_id)] or None,
156                 'notified_partner_ids': partner_id and [(4, partner_id)] or None,
157                 'attachment_ids': wizard.attachment_ids or None,
158                 'email_from': wizard.email_from or None,
159                 'email_to': email,
160             }
161             mail_id = mail_mail_obj.create(cr, uid, values, context=context)
162             mail_mail_obj.send(cr, uid, [mail_id], context=context)
163
164         def create_token(wizard, partner_id, email):
165             if context.get("survey_resent_token"):
166                 response_ids = survey_response_obj.search(cr, uid, [('survey_id', '=', wizard.survey_id.id), ('state', 'in', ['new', 'skip']), '|', ('partner_id', '=', partner_id), ('email', '=', email)], context=context)
167                 if response_ids:
168                     return survey_response_obj.read(cr, uid, response_ids, ['token'], context=context)[0]['token']
169             if wizard.public != 'email_private':
170                 return None
171             else:
172                 token = uuid.uuid4().__str__()
173                 # create response with token
174                 survey_response_obj.create(cr, uid, {
175                     'survey_id': wizard.survey_id.id,
176                     'deadline': wizard.date_deadline,
177                     'date_create': datetime.now(),
178                     'type': 'link',
179                     'state': 'new',
180                     'token': token,
181                     'partner_id': partner_id,
182                     'email': email})
183                 return token
184
185         for wizard in self.browse(cr, uid, ids, context=context):
186             # check if __URL__ is in the text
187             if wizard.body.find("__URL__") < 0:
188                 raise osv.except_osv(_('Warning!'), _("The content of the text don't contain '__URL__'. \
189                     __URL__ is automaticaly converted into the special url of the survey."))
190
191             if not wizard.multi_email and not wizard.partner_ids and (context.get('default_partner_ids') or context.get('default_multi_email')):
192                 wizard.multi_email = context.get('default_multi_email')
193                 wizard.partner_ids = context.get('default_partner_ids')
194
195             # quick check of email list
196             emails_list = []
197             if wizard.multi_email:
198                 emails = list(set(emails_split.split(wizard.multi_email)) - set([partner.email for partner in wizard.partner_ids]))
199                 for email in emails:
200                     email = email.strip()
201                     if re.search(r"^[^@]+@[^@]+$", email):
202                         emails_list.append(email)
203
204             # remove public anonymous access
205             partner_list = []
206             for partner in wizard.partner_ids:
207                 if not anonymous_id or not partner.user_ids or anonymous_id not in [x.id for x in partner.user_ids[0].groups_id]:
208                     partner_list.append({'id': partner.id, 'email': partner.email})
209
210             if not len(emails_list) and not len(partner_list):
211                 if wizard.model == 'res.partner' and wizard.res_id:
212                     return False
213                 raise osv.except_osv(_('Warning!'), _("Please enter at least one valid recipient."))
214
215             for email in emails_list:
216                 partner_id = partner_obj.search(cr, uid, [('email', '=', email)], context=context)
217                 partner_id = partner_id and partner_id[0] or None
218                 token = create_token(wizard, partner_id, email)
219                 create_response_and_send_mail(wizard, token, partner_id, email)
220
221             for partner in partner_list:
222                 token = create_token(wizard, partner['id'], partner['email'])
223                 create_response_and_send_mail(wizard, token, partner['id'], partner['email'])
224
225         return {'type': 'ir.actions.act_window_close'}