Permalink
Browse files

email attachment with PTO on notification

  • Loading branch information...
1 parent 0e2056a commit 6c6eaa00a40faf4be29b5555b2894a659ec3814a @peterbe peterbe committed Aug 12, 2011
View
@@ -1,3 +1,6 @@
[submodule "vendor"]
path = vendor
url = git://github.com/mozilla/playdoh-lib.git
+[submodule "vendor-local/src/python-dateutil"]
+ path = vendor-local/src/python-dateutil
+ url = git://github.com/cozi/python-dateutil.git
View
@@ -23,3 +23,4 @@ class Hours(models.Model):
entry = models.ForeignKey(Entry)
hours = models.IntegerField()
date = models.DateField()
+ birthday = models.BooleanField(default=False)
@@ -109,10 +109,12 @@
<ul>
<li class="active" title="You're lookin' at it">Table</li>
<li><a class="format" href="?format=csv" id="format-csv" title="Good for spreadsheet software">CSV / Excel</a></li>
+ <!--
<li><a class="format" href="?format=atom" id="format-atom" title="Good for feed readers">Atom</a></li>
<li><a class="format" href="?format=ical" id="format-ical" title="Good for calendar apps">iCal</a></li>
<li><a class="format" href="?format=json" id="format-json" title="Good for mash-ups">JSON</a></li>
<li><a class="format" href="?format=sql" id="format-sql" title="Good for importing test data">SQL</a></li>
+ -->
</ul>
</div>
View
@@ -674,3 +674,78 @@ def test_notify_free_input(self):
ok_('valid@ test.com' not in response.content)
ok_('axe l@e..com' not in response.content)
ok_(settings.HR_MANAGERS[0] in response.content)
+
+ def test_notify_notification_attachment(self):
+ url = reverse('dates.notify')
+ peter = User.objects.create(
+ username='peter',
+ email='pbengtsson@mozilla.com',
+ first_name='Peter',
+ last_name='Bengtsson',
+ )
+ peter.set_password('secret')
+ peter.save()
+
+ assert self.client.login(username='peter', password='secret')
+ monday = datetime.date(2018, 1, 1) # I know this is a Monday
+ wednesday = monday + datetime.timedelta(days=2)
+
+ entry = Entry.objects.create(
+ start=monday,
+ end=wednesday,
+ user=peter,
+ )
+ tuesday = monday + datetime.timedelta(days=1)
+ data = {
+ monday.strftime('d-%Y%m%d'): 8,
+ tuesday.strftime('d-%Y%m%d'): 8,
+ wednesday.strftime('d-%Y%m%d'): 8,
+ }
+ url = reverse('dates.hours', args=[entry.pk])
+ response = self.client.post(url, data)
+ print response.content
+ eq_(response.status_code, 302)
+
+ assert len(mail.outbox)
+ email = mail.outbox[-1]
+
+ attachment = email.attachments[0]
+ filename, content, mimetype = attachment
+ eq_(filename, 'event.ics')
+ eq_(mimetype, 'text/calendar')
+ ok_('Peter Bengtsson on PTO (2 days)' in content)
+
+ def test_notify_notification_attachment_one_day(self):
+ url = reverse('dates.notify')
+ peter = User.objects.create(
+ username='peter',
+ email='pbengtsson@mozilla.com',
+ )
+ peter.set_password('secret')
+ peter.save()
+
+ assert self.client.login(username='peter', password='secret')
+ monday = datetime.date(2018, 1, 1) # I know this is a Monday
+
+ entry = Entry.objects.create(
+ start=monday,
+ end=monday,
+ user=peter,
+ )
+ tuesday = monday + datetime.timedelta(days=1)
+ data = {
+ monday.strftime('d-%Y%m%d'): 4,
+ }
+ url = reverse('dates.hours', args=[entry.pk])
+ response = self.client.post(url, data)
+ print response.content
+ eq_(response.status_code, 302)
+
+ assert len(mail.outbox)
+ email = mail.outbox[-1]
+
+ attachment = email.attachments[0]
+ filename, content, mimetype = attachment
+ eq_(filename, 'event.ics')
+ eq_(mimetype, 'text/calendar')
+ ok_('peter on PTO (4 hours)' in content)
View
@@ -12,6 +12,7 @@
from django.db.models import Q
from django.core.mail import send_mail
from django.template import Context, loader
+import vobject
from models import Entry, Hours
from users.models import UserProfile
from users.utils import ldap_lookup
@@ -284,15 +285,46 @@ def send_email_notification(entry, extra_users, is_edit=False):
}
body = template.render(Context(context)).strip()
connection = get_connection()
- success = EmailMessage(
+ message = EmailMessage(
subject=subject,
body=body,
from_email=entry.user.email,
to=email_addresses,
cc=entry.user.email and [entry.user.email] or None,
connection=connection
- ).send()
+ )
+ cal = vobject.iCalendar()
+ cal.add('method').value = 'PUBLISH' # IE/Outlook needs this
+ event = cal.add('vevent')
+ if entry.total_hours < 8:
+ hours = Hours.objects.get(entry=entry)
+ if hours.birthday:
+ length = 'birthday'
+ else:
+ length = '%s hours' % entry.total_hours
+ else:
+ days = (entry.end - entry.start).days
+ if days == 1:
+ length = '1 day'
+ else:
+ length = '%d days' % days
+ if entry.user.first_name:
+ user_name = ('%s %s' %
+ (entry.user.first_name, entry.user.last_name)).strip()
+ else:
+ user_name = entry.user.username
+ summary = '%s on PTO (%s)' % (user_name, length)
+ event.add('summary').value = summary
+ event.add('dtstart').value = entry.start
+ event.add('dtend').value = entry.end
+ #url = (home_url + '?cal_y=%d&cal_m=%d' %
+ #(slot.date.year, slot.date.month))
+ #event.add('url').value = url
+ description = ''
+ event.add('description').value = description
+ message.attach('event.ics', cal.serialize(), 'text/calendar')
+ success = message.send()
return success, email_addresses
@login_required
View
@@ -7,7 +7,7 @@
class Pto(models.Model):
id = models.IntegerField(primary_key=True)
person = models.CharField(max_length=384)
- added = models.IntegerField(primary_key=True)
+ added = models.IntegerField()
hours = models.FloatField()
hours_daily = models.TextField()
details = models.CharField(max_length=765)
View
@@ -26,7 +26,6 @@
<ul id="menu">
<li><a href="{{ url('dates.notify') }}">Notify</a></li>
<li><a href="{{ url('dates.list') }}">List</a></li>
- <li><a href="./report.php">Report</a></li>
<li>Hi <strong>{{ request.user.first_name }}</strong>
<a href="{{ url('users.logout') }}">log out</a>
</li>
@@ -1,26 +0,0 @@
-Metadata-Version: 1.0
-Name: python-memcached
-Version: 1.47
-Summary: Pure python memcached client
-Home-page: http://www.tummy.com/Community/software/python-memcached/
-Author: Sean Reifschneider
-Author-email: jafo@tummy.com
-License: UNKNOWN
-Download-URL: ftp://ftp.tummy.com/pub/python-memcached/
-Description: This software is a 100% Python interface to the memcached memory cache
- daemon. It is the client side software which allows storing values in one
- or more, possibly remote, memcached servers. Search google for memcached
- for more information.
-
- This package was originally written by Evan Martin of Danga.
- Please do not contact Evan about maintenance.
- Sean Reifschneider of tummy.com, ltd. has taken over maintenance of it.
-
-Platform: UNKNOWN
-Classifier: Development Status :: 5 - Production/Stable
-Classifier: Intended Audience :: Developers
-Classifier: License :: OSI Approved :: Python Software Foundation License
-Classifier: Operating System :: OS Independent
-Classifier: Programming Language :: Python
-Classifier: Topic :: Internet
-Classifier: Topic :: Software Development :: Libraries :: Python Modules
@@ -1,7 +0,0 @@
-README
-memcache.py
-setup.cfg
-python_memcached.egg-info/PKG-INFO
-python_memcached.egg-info/SOURCES.txt
-python_memcached.egg-info/dependency_links.txt
-python_memcached.egg-info/top_level.txt
@@ -1,7 +0,0 @@
-../memcache.py
-../memcache.pyc
-./
-dependency_links.txt
-PKG-INFO
-SOURCES.txt
-top_level.txt
@@ -0,0 +1,86 @@
+"""
+VObject Overview
+================
+ vobject parses vCard or vCalendar files, returning a tree of Python objects.
+ It also provids an API to create vCard or vCalendar data structures which
+ can then be serialized.
+
+ Parsing existing streams
+ ------------------------
+ Streams containing one or many L{Component<base.Component>}s can be
+ parsed using L{readComponents<base.readComponents>}. As each Component
+ is parsed, vobject will attempt to give it a L{Behavior<behavior.Behavior>}.
+ If an appropriate Behavior is found, any base64, quoted-printable, or
+ backslash escaped data will automatically be decoded. Dates and datetimes
+ will be transformed to datetime.date or datetime.datetime instances.
+ Components containing recurrence information will have a special rruleset
+ attribute (a dateutil.rrule.rruleset instance).
+
+ Validation
+ ----------
+ L{Behavior<behavior.Behavior>} classes implement validation for
+ L{Component<base.Component>}s. To validate, an object must have all
+ required children. There (TODO: will be) a toggle to raise an exception or
+ just log unrecognized, non-experimental children and parameters.
+
+ Creating objects programatically
+ --------------------------------
+ A L{Component<base.Component>} can be created from scratch. No encoding
+ is necessary, serialization will encode data automatically. Factory
+ functions (TODO: will be) available to create standard objects.
+
+ Serializing objects
+ -------------------
+ Serialization:
+ - Looks for missing required children that can be automatically generated,
+ like a UID or a PRODID, and adds them
+ - Encodes all values that can be automatically encoded
+ - Checks to make sure the object is valid (unless this behavior is
+ explicitly disabled)
+ - Appends the serialized object to a buffer, or fills a new
+ buffer and returns it
+
+ Examples
+ --------
+
+ >>> import datetime
+ >>> import dateutil.rrule as rrule
+ >>> x = iCalendar()
+ >>> x.add('vevent')
+ <VEVENT| []>
+ >>> x
+ <VCALENDAR| [<VEVENT| []>]>
+ >>> v = x.vevent
+ >>> utc = icalendar.utc
+ >>> v.add('dtstart').value = datetime.datetime(2004, 12, 15, 14, tzinfo = utc)
+ >>> v
+ <VEVENT| [<DTSTART{}2004-12-15 14:00:00+00:00>]>
+ >>> x
+ <VCALENDAR| [<VEVENT| [<DTSTART{}2004-12-15 14:00:00+00:00>]>]>
+ >>> newrule = rrule.rruleset()
+ >>> newrule.rrule(rrule.rrule(rrule.WEEKLY, count=2, dtstart=v.dtstart.value))
+ >>> v.rruleset = newrule
+ >>> list(v.rruleset)
+ [datetime.datetime(2004, 12, 15, 14, 0, tzinfo=tzutc()), datetime.datetime(2004, 12, 22, 14, 0, tzinfo=tzutc())]
+ >>> v.add('uid').value = "randomuid@MYHOSTNAME"
+ >>> print x.serialize()
+ BEGIN:VCALENDAR
+ VERSION:2.0
+ PRODID:-//PYVOBJECT//NONSGML Version 1//EN
+ BEGIN:VEVENT
+ UID:randomuid@MYHOSTNAME
+ DTSTART:20041215T140000Z
+ RRULE:FREQ=WEEKLY;COUNT=2
+ END:VEVENT
+ END:VCALENDAR
+
+"""
+
+import base, icalendar, vcard
+from base import readComponents, readOne, newFromBehavior
+
+def iCalendar():
+ return newFromBehavior('vcalendar', '2.0')
+
+def vCard():
+ return newFromBehavior('vcard', '3.0')
Oops, something went wrong.

0 comments on commit 6c6eaa0

Please sign in to comment.