Ignore:
Timestamp:
4 Nov 2020, 17:52:22 (4 years ago)
Author:
Henrik Bettermann
Message:

Implement bulk emailing.

Location:
main/waeup.kofa/trunk/src/waeup/kofa
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • main/waeup.kofa/trunk/src/waeup/kofa/interfaces.py

    r16059 r16299  
    508508        )
    509509
     510    bcc_to = schema.Text(
     511        title = _(u'Bcc to:'),
     512        required = True,
     513        #readonly = True,
     514        )
     515
    510516    subject = schema.TextLine(
    511517        title = _(u'Subject:'),
     
    519525        title = _(u'Text:'),
    520526        required = True,)
     527
    521528
    522529class IKofaPrincipalInfo(IPrincipalInfo):
  • main/waeup.kofa/trunk/src/waeup/kofa/smtp.py

    r12836 r16299  
    160160
    161161def send_mail(from_name, from_addr, rcpt_name, rcpt_addrs,
    162               subject, body, config=None, cc=False):
     162              subject, body, config=None, cc=None, bcc=None):
    163163    """Send mail.
    164164
     
    173173    The from-address set here will be: `FROM_ADDRESS` as set above.
    174174
    175     ``cc`` tells whether we want the from-address to be CCed. This is
    176     not the case by default as we easily act as an open relay
    177     otherwise.
    178 
    179175    XXX: The hard-coded from-address should be changable or be
    180176         determined smarter by looking up a FQDN or similar.
     
    184180    rcpt_addrs = rcpt_addrs.replace(' ', '').split(',')
    185181    body_to = ''
     182    from_addr = from_addr.split(',')[0]
    186183    for email in rcpt_addrs:
    187184        body_to += '%s, ' % encode_address(email, rcpt_name)
     
    192189    body["To"] = body_to.strip(', ')
    193190    if cc:
    194         body["Cc"] = reply_addr
     191        body["Cc"] = cc
     192    if bcc:
     193        body["Bcc"] = bcc
    195194    body["Reply-To"] = reply_addr
    196195    body["Subject"] = encode_header_item(subject)
  • main/waeup.kofa/trunk/src/waeup/kofa/students/browser.py

    r16286 r16299  
    3636from zope.security import checkPermission
    3737from zope.securitypolicy.interfaces import IPrincipalRoleManager
     38from waeup.kofa.smtp import encode_address
    3839from waeup.kofa.accesscodes import invalidate_accesscode, get_access_code
    3940from waeup.kofa.accesscodes.workflow import USED
     
    309310    search_button = _('Find student(s)')
    310311    remove_button = _('Remove selected')
     312    send_email_button = _('Send bulk email')
    311313    doclink = DOCLINK + '/students.html'
    312314
     
    340342            if not self.hitlist:
    341343                self.flash(_('No student found.'), type="warning")
    342             if 'remove' in form:
     344            if 'remove' in form or 'send_email' in form:
    343345                self.flash(_('No item selected.'), type="warning")
    344346            return
     
    346348        if isinstance(entries, basestring):
    347349            entries = [entries]
     350        entries.sort()
    348351        deleted = []
     352        emails_tobesent = ''
    349353        for entry in entries:
    350354            if 'remove' in form:
    351355                del self.context[entry]
    352356                deleted.append(entry)
     357            if 'send_email' in form and self.context[entry].email:
     358                emails_tobesent += '%s,' % encode_address(
     359                    self.context[entry].email,
     360                    self.context[entry].student_id)
     361        if 'send_email' in form and not len(emails_tobesent):
     362            self.flash(_('No email address found.'), type="warning")
     363            return
     364        if len(emails_tobesent):
     365            args = {'bcc_to': emails_tobesent.strip(',')}
     366            self.redirect(self.url(self.context) +
     367                '/send_bulk_email?%s' % urlencode(args))
     368            return
    353369        self.hitlist = search(query=self.searchterm,
    354370            searchtype=self.searchtype, view=self)
     
    521537                self.config.name,
    522538                data['body'],data['subject'])
     539        if success:
     540            self.flash(_('Your message has been sent.'))
     541        else:
     542            self.flash(_('An smtp server error occurred.'), type="danger")
     543        return
     544
     545class SendBulEmailsFormPage(ContactAdminFormPage):
     546    grok.context(IStudentsContainer)
     547    grok.name('send_bulk_email')
     548    grok.require('waeup.manageStudent')
     549    pnav = 4
     550    form_fields = grok.AutoFields(IContactForm).select('subject', 'body', 'bcc_to')
     551    label = _('Send bulk email')
     552
     553    def update(self, bcc_to=u''):
     554        self.form_fields.get('bcc_to').field.default = bcc_to
     555        return
     556
     557    @action('Send message now', style='primary')
     558    def send(self, *args, **data):
     559        try:
     560            email = self.request.principal.email
     561        except AttributeError:
     562            email = self.config.email_admin
     563        usertype = getattr(self.request.principal,
     564                           'user_type', 'system').title()
     565        kofa_utils = getUtility(IKofaUtils)
     566        success = kofa_utils.sendContactForm(
     567                self.request.principal.title,email,
     568                self.request.principal.title,email, # sent to the sender's address
     569                self.request.principal.id,usertype,
     570                self.config.name,
     571                data['body'],data['subject'],
     572                data['bcc_to'])
    523573        if success:
    524574            self.flash(_('Your message has been sent.'))
  • main/waeup.kofa/trunk/src/waeup/kofa/students/browser_templates/containermanagepage.pt

    r15417 r16299  
    7575    <input type="submit" name="remove"
    7676           tal:attributes="value view/remove_button" class="btn btn-default"
    77            onclick="return confirmPost('Are you sure?')"/>
     77           onclick="return window.confirm('Are you sure?')"/>
     78    <input type="submit" name="send_email"
     79           tal:attributes="value view/send_email_button" class="btn btn-default"
     80           onclick="return window.confirm('Are you sure?')"/>
    7881
    7982  </div>
  • main/waeup.kofa/trunk/src/waeup/kofa/students/tests/test_browser.py

    r16266 r16299  
    9090    def setUp(self):
    9191        super(StudentsFullSetup, self).setUp()
     92        self.setup_logging()
    9293
    9394        # Setup a sample site for each test
     
    252253
    253254    layer = FunctionalLayer
     255
     256    def setup_logging(self):
     257        # setup a log-handler that catches all fake mailer output
     258        self.stream = StringIO()
     259        handler = logging.StreamHandler(self.stream)
     260        logger = logging.getLogger('test.smtp')
     261        logger.addHandler(handler)
     262        logger.setLevel(logging.INFO)
     263        return
     264
     265    def get_fake_smtp_output(self):
     266        # get output generated by fake mailer
     267        self.stream.flush()
     268        self.stream.seek(0)
     269        return self.stream.read()
    254270
    255271    def test_anonymous_access(self):
     
    432448        self.assertTrue('No student found' in self.browser.contents)
    433449        return
     450
     451    def test_send_bulk_emails(self):
     452        self.browser.addHeader('Authorization', 'Basic mgr:mgrpw')
     453        self.browser.open(self.manage_container_path)
     454        self.browser.getLink("Add student").click()
     455        self.assertEqual(self.browser.headers['Status'], '200 Ok')
     456        self.assertEqual(self.browser.url, self.add_student_path)
     457        self.browser.getControl(name="form.firstname").value = 'Bob'
     458        self.browser.getControl(name="form.lastname").value = 'Tester'
     459        self.browser.getControl(name="form.reg_number").value = '1234'
     460        self.browser.getControl("Create student").click()
     461        self.assertTrue('Student record created' in self.browser.contents)
     462        self.browser.getLink("Manage").click()
     463        self.browser.getControl(name="form.email").value = 'uli@uni.ng'
     464        self.browser.getControl(name="form.sex").value = ['m']
     465        self.browser.getControl("Save").click()
     466        # We can find Anna and Bob
     467        self.browser.open(self.manage_container_path)
     468        self.browser.getControl(name="searchtype").value = ['student_id']
     469        self.browser.getControl(name="searchterm").value = '*'
     470        self.browser.getControl("Find student(s)").click()
     471        self.assertTrue('Anna Tester' in self.browser.contents)
     472        self.assertTrue('Bob Tester' in self.browser.contents)
     473        # We can send bulk emails
     474        ctrl = self.browser.getControl(name='entries')
     475        ctrl.getControl(value='K1000000').selected = True
     476        ctrl.getControl(value='K1000001').selected = True
     477        self.browser.getControl("Send bulk", index=0).click()
     478        self.assertTrue('K1000000 &lt;aa@aa.ng&gt;,K1000001 &lt;uli@uni.ng&gt;'
     479            in self.browser.contents)
     480        self.browser.getControl(name="form.subject").value = 'Test'
     481        self.browser.getControl(name="form.body").value = 'Hello world'
     482        self.browser.getControl("Send message").click()
     483        self.assertTrue('Your message has been sent' in self.browser.contents)
     484        self.assertMatches(
     485        u'Sending email from no-reply@waeup.org to contact@waeup.org:\n'
     486        u'Message:\n'
     487        u'msg: MIME-Version: 1.0\n'
     488        u'msg: Content-Type: text/plain; charset="us-ascii"\n'
     489        u'msg: Content-Transfer-Encoding: 7bit\n'
     490        u'msg: From: Manager <no-reply@waeup.org>\n'
     491        u'msg: To: Manager <contact@waeup.org>\n'
     492        u'msg: Bcc: K1000000 <aa@aa.ng>,K1000001 <uli@uni.ng>\n'
     493        u'msg: Reply-To: Manager <contact@waeup.org>\n'
     494        u'msg: Subject: Test\n'
     495        u'msg: \n'
     496        u'msg: Hello world\n'
     497        u'msg: \n'
     498        u'msg: ---\n'
     499        u'msg: Manager (id: zope.mgr)\n'
     500        u'msg: Sample University\n'
     501        u'msg: \n',
     502            self.get_fake_smtp_output()
     503            )
    434504
    435505    def test_add_graduated_students(self):
  • main/waeup.kofa/trunk/src/waeup/kofa/tests/test_smtp.py

    r14016 r16299  
    259259            u'A recipient', u'recpt@example.com',
    260260            u'A subject',
    261             u'This is a test mail.',
    262             cc=True)
     261            u'This is a test mail.',None,
     262            u'A cc recipient <recpt@example.com>',
     263            u'A bcc recipient <recpt@example.com>,A 2nd bcc recipient <recpt@example.com>',
     264            )
    263265        self.assertEqual(mail_id, 'fake-message-id@example.com')
    264266        self.assertEqual(
     
    272274             u'msg: From: A sender <no-reply@waeup.org>',
    273275             u'msg: To: A recipient <recpt@example.com>',
    274              u'msg: Cc: A sender <sender@example.com>',
     276             u'msg: Cc: A cc recipient <recpt@example.com>',
     277             u'msg: Bcc: A bcc recipient <recpt@example.com>,',
     278             u'msg:  A 2nd bcc recipient <recpt@example.com>',
    275279             u'msg: Reply-To: A sender <sender@example.com>',
    276280             u'msg: Subject: A subject',
  • main/waeup.kofa/trunk/src/waeup/kofa/utils/utils.py

    r16213 r16299  
    3535def send_mail(from_name, from_addr,
    3636              rcpt_name, rcpt_addr,
    37               subject, body, config):
     37              subject, body, config,
     38              cc=None, bcc=None):
    3839    """Wrapper for the real SMTP functionality in :mod:`waeup.kofa.smtp`.
    3940
     
    4243    mail_id = send_mail_internally(
    4344        from_name, from_addr, rcpt_name, rcpt_addr,
    44         subject, body, config)
     45        subject, body, config, cc, bcc)
    4546    return True
    4647
     
    247248
    248249    def sendContactForm(self, from_name, from_addr, rcpt_name, rcpt_addr,
    249                         from_username, usertype, portal, body, subject):
     250                        from_username, usertype, portal, body, subject,
     251                        bcc_to=None):
    250252        """Send an email with data provided by forms.
    251253        """
     
    269271        return send_mail(
    270272            from_name, from_addr, rcpt_name, rcpt_addr,
    271             subject, body, config)
     273            subject, body, config, None, bcc_to)
    272274
    273275    def getUsers(self):
Note: See TracChangeset for help on using the changeset viewer.