def _make_ics(event, etime): cal = Calendar() cal.add("prodid", "N1-send-availability-package") cal.add("version", "2.0") cal.add("method", "REQUEST") # also have PUBLISH or CANCEL evt = Event() evt.add("summary", event.title) evt.add("location", event.location) evt.add("description", event.description) evt.add("dtstart", etime.start.replace(tzinfo=pytz.UTC)) evt.add("dtend", etime.end.replace(tzinfo=pytz.UTC)) evt.add("dtstamp", datetime.now(pytz.UTC)) evt["uid"] = "{timestamp}/{email}".format( timestamp=time.mktime(datetime.now(pytz.UTC).timetuple()), email=event.organizer.email ) evt.add("priority", 5) organizer = vCalAddress("MAILTO:{}".format(event.organizer.email)) organizer.params["cn"] = vText(event.organizer.name) organizer.params["role"] = vText("CHAIR") evt["organizer"] = organizer for attendee in event.attendees: atnd = vCalAddress("MAILTO:{}".format(attendee.email)) atnd.params["cn"] = vText(attendee.name) atnd.params["ROLE"] = vText("REQ-PARTICIPANT") evt.add("attendee", atnd, encode=0) cal.add_component(evt) return cal.to_ical()
def _make_ics(event, etime): cal = Calendar() cal.add('prodid', 'N1-send-availability-package') cal.add('version', '1.0') evt = Event() evt.add('summary', event.title) evt.add('location', event.location) evt.add('description', event.description) evt.add('dtstart', etime.start) evt.add('dtend', etime.end) evt.add('dtstamp', datetime.now()) evt['uid'] = '{timestamp}/{email}'.format( timestamp=time.mktime(datetime.now().timetuple()), email=event.organizer.email ) evt.add('priority', 5) organizer = vCalAddress('MAILTO:{}'.format(event.organizer.email)) organizer.params['cn'] = vText(event.organizer.name) organizer.params['role'] = vText('CHAIR') evt['organizer'] = organizer for attendee in event.attendees: atnd = vCalAddress('MAILTO:{}'.format(attendee.email)) atnd.params['cn'] = vText(attendee.name) atnd.params['ROLE'] = vText('REQ-PARTICIPANT') evt.add('attendee', atnd, encode=0) cal.add_component(evt) return cal.to_ical()
def _make_ics(event, etime): cal = Calendar() cal.add('prodid', 'N1-send-availability-package') cal.add('version', '1.0') evt = Event() evt.add('summary', event.title) evt.add('location', event.location) evt.add('description', event.description) evt.add('dtstart', etime.start) evt.add('dtend', etime.end) evt.add('dtstamp', datetime.now()) evt['uid'] = '{timestamp}/{email}'.format(timestamp=time.mktime( datetime.now().timetuple()), email=event.organizer.email) evt.add('priority', 5) organizer = vCalAddress('MAILTO:{}'.format(event.organizer.email)) organizer.params['cn'] = vText(event.organizer.name) organizer.params['role'] = vText('CHAIR') evt['organizer'] = organizer for attendee in event.attendees: atnd = vCalAddress('MAILTO:{}'.format(attendee.email)) atnd.params['cn'] = vText(attendee.name) atnd.params['ROLE'] = vText('REQ-PARTICIPANT') evt.add('attendee', atnd, encode=0) cal.add_component(evt) return cal.to_ical()
def marshall_event_to_vevent(instance): wf = getToolByName(instance, 'portal_workflow') dtstamp = utc_strftime(datetime.utcnow(), "%Y%m%dT%H%M%SZ") uid_hash = abs(hash(instance)) state = wf.getInfoFor(instance, 'review_state') status = re_status_mapping.get(state, 'TENTATIVE') event = VEvent() event.add('uid', generateUID(instance)) event.add('summary', instance.Title(), encode=False) event.add('description', instance.Description(), encode=False) if hasattr(aq_base(instance), 'getLocation'): location = instance.getLocation() if location: event.add('location', location, encode=False) if hasattr(aq_base(instance), 'Subject'): subject = instance.Subject() if subject: for category in subject: event.add('categories', category, encode=False) if hasattr(aq_base(instance), 'event_url'): url = instance.event_url if callable(url): # Ugh, it's callable in ATContentTypes. url = url() if url: event.add('url', url) event['url'].params['value'] = 'URI' if hasattr(aq_base(instance), 'getAttendees'): for att in instance.getAttendees(): name, email = parseaddr(att) if not name: name = att email = '' if email: email = 'mailto:%s' % email else: email = 'invalid:nomail' address = vCalAddress(email) address.params['cn'] = name event.add('attendee', address, encode=False) if (hasattr(aq_base(instance), 'duration') and instance.duration == date.resolution): # All day event. dtstart = vDate.from_ical(utc_strftime(instance.start_date, '%Y%m%d')) event.add('dtstart', dtstart) dtend = vDate.from_ical(utc_strftime(instance.end_date, '%Y%m%d')) event.add('dtend', dtend) else: # Normal event dtstart = vDatetime.from_ical( utc_strftime(instance.start_date, '%Y%m%dT%H%M%SZ')) event.add('dtstart', dtstart) dtend = vDatetime.from_ical( utc_strftime(instance.end_date, '%Y%m%dT%H%M%SZ')) event.add('dtend', dtend) dtstamp = vDatetime.from_ical(dtstamp) event.add('dtstamp', dtstamp) #event.add('status', status) return event
def _make_ics(event, etime): cal = Calendar() cal.add('prodid', 'N1-quick-schedule-package') cal.add('version', '2.0') cal.add('method', 'REQUEST') # also have PUBLISH or CANCEL evt = Event() evt.add('summary', event.title) evt.add('location', event.location) evt.add('description', event.description) evt.add('dtstart', etime.start.replace(tzinfo=pytz.UTC)) evt.add('dtend', etime.end.replace(tzinfo=pytz.UTC)) evt.add('dtstamp', datetime.now(pytz.UTC)) evt['uid'] = '{timestamp}/{email}'.format( timestamp=time.mktime(datetime.now(pytz.UTC).timetuple()), email=event.organizer.email ) evt.add('priority', 5) organizer = vCalAddress('MAILTO:{}'.format(event.organizer.email)) organizer.params['cn'] = vText(event.organizer.name) organizer.params['role'] = vText('CHAIR') evt['organizer'] = organizer for attendee in event.attendees: atnd = vCalAddress('MAILTO:{}'.format(attendee.email)) atnd.params['cn'] = vText(attendee.name) atnd.params['ROLE'] = vText('REQ-PARTICIPANT') evt.add('attendee', atnd, encode=0) cal.add_component(evt) return cal.to_ical()
def generate_calendar(request): """http://codespeak.net/icalendar/""" cal = Calendar() cal.add("prodid", "-//Club Connect//ericleong.me//") cal.add("version", "2.0") posts = Post.objects.order_by("-created") cal["X-WR-CALNAME"] = "Club Connect Events" cal["X-PUBLISH-TTL"] = "PT12H" cal["CALSCALE"] = "GREGORIAN" cal["METHOD"] = "PUBLISH" # TODO: separate out private events using a private URL? # TODO: switch to using EDT for post in posts: if post.start_time: # Make sure we have a time event = Event() event.add("summary", vText(post.title)) event.add("dtstart", post.start_time) event.add("dtend", post.end_time if post.end_time else post.start_time) # event.add('dtstamp', datetime(2005,4,4,0,10,0,tzinfo=UTC)) event["uid"] = vText(post.id) event["organizer"] = vText(post.author.username) event["description"] = vText(post.description) event["url"] = vUri(post.get_absolute_url()) if post.location: if post.location.room: event["location"] = vText("%s (%s)" % (post.location.name, post.location.room)) else: event["location"] = vText(post.location.name) for commit in post.committed.all(): attendee = vCalAddress("MAILTO:" + commit.email) name = ( ([commit.first_name, commit.last_name]) if (commit.first_name and commit.last_name) else commit.username ) attendee.params["cn"] = vText(name) event.add("attendee", attendee, encode=0) cal.add_component(event) return HttpResponse(cal.to_ical().replace("\n", "\r\n"), content_type="text/calendar")
def test_cal_Component(self): from icalendar.cal import Component, Calendar, Event from icalendar import prop # A component is like a dictionary with extra methods and attributes. c = Component() c.name = 'VCALENDAR' # Every key defines a property.A property can consist of either a # single item. This can be set with a single value... c['prodid'] = '-//max m//icalendar.mxm.dk/' self.assertEqual( c, Calendar({'PRODID': '-//max m//icalendar.mxm.dk/'}) ) # or with a list c['ATTENDEE'] = ['Max M', 'Rasmussen'] self.assertEqual( c, Calendar({'ATTENDEE': ['Max M', 'Rasmussen'], 'PRODID': '-//max m//icalendar.mxm.dk/'}) ) ### ADD MULTIPLE VALUES TO A PROPERTY # if you use the add method you don't have to considder if a value is # a list or not. c = Component() c.name = 'VEVENT' # add multiple values at once c.add('attendee', ['*****@*****.**', '*****@*****.**']) # or add one per line c.add('attendee', '*****@*****.**') c.add('attendee', '*****@*****.**') # add again multiple values at once to very concatenaton of lists c.add('attendee', ['*****@*****.**', '*****@*****.**']) self.assertEqual( c, Event({'ATTENDEE': [ prop.vCalAddress('*****@*****.**'), prop.vCalAddress('*****@*****.**'), prop.vCalAddress('*****@*****.**'), prop.vCalAddress('*****@*****.**'), prop.vCalAddress('*****@*****.**'), prop.vCalAddress('*****@*****.**') ]}) ) ### # You can get the values back directly ... c.add('prodid', '-//my product//') self.assertEqual(c['prodid'], prop.vText(u'-//my product//')) # ... or decoded to a python type self.assertEqual(c.decoded('prodid'), b'-//my product//') # With default values for non existing properties self.assertEqual(c.decoded('version', 'No Version'), 'No Version') c.add('rdate', [datetime(2013, 3, 28), datetime(2013, 3, 27)]) self.assertTrue(isinstance(c.decoded('rdate'), prop.vDDDLists)) # The component can render itself in the RFC 2445 format. c = Component() c.name = 'VCALENDAR' c.add('attendee', 'Max M') self.assertEqual( c.to_ical(), b'BEGIN:VCALENDAR\r\nATTENDEE:Max M\r\nEND:VCALENDAR\r\n' ) # Components can be nested, so You can add a subcompont. Eg a calendar # holds events. e = Component(summary='A brief history of time') e.name = 'VEVENT' e.add('dtend', '20000102T000000', encode=0) e.add('dtstart', '20000101T000000', encode=0) self.assertEqual( e.to_ical(), b'BEGIN:VEVENT\r\nDTEND:20000102T000000\r\n' + b'DTSTART:20000101T000000\r\nSUMMARY:A brief history of time\r' + b'\nEND:VEVENT\r\n' ) c.add_component(e) self.assertEqual( c.subcomponents, [Event({'DTEND': '20000102T000000', 'DTSTART': '20000101T000000', 'SUMMARY': 'A brief history of time'})] ) # We can walk over nested componentes with the walk method. self.assertEqual([i.name for i in c.walk()], ['VCALENDAR', 'VEVENT']) # We can also just walk over specific component types, by filtering # them on their name. self.assertEqual([i.name for i in c.walk('VEVENT')], ['VEVENT']) self.assertEqual( [i['dtstart'] for i in c.walk('VEVENT')], ['20000101T000000'] ) # We can enumerate property items recursively with the property_items # method. self.assertEqual( c.property_items(), [('BEGIN', b'VCALENDAR'), ('ATTENDEE', prop.vCalAddress('Max M')), ('BEGIN', b'VEVENT'), ('DTEND', '20000102T000000'), ('DTSTART', '20000101T000000'), ('SUMMARY', 'A brief history of time'), ('END', b'VEVENT'), ('END', b'VCALENDAR')] ) # We can also enumerate property items just under the component. self.assertEqual( c.property_items(recursive=False), [('BEGIN', b'VCALENDAR'), ('ATTENDEE', prop.vCalAddress('Max M')), ('END', b'VCALENDAR')] ) sc = c.subcomponents[0] self.assertEqual( sc.property_items(recursive=False), [('BEGIN', b'VEVENT'), ('DTEND', '20000102T000000'), ('DTSTART', '20000101T000000'), ('SUMMARY', 'A brief history of time'), ('END', b'VEVENT')] ) # Text fields which span multiple mulitple lines require proper # indenting c = Calendar() c['description'] = u'Paragraph one\n\nParagraph two' self.assertEqual( c.to_ical(), b'BEGIN:VCALENDAR\r\nDESCRIPTION:Paragraph one\\n\\nParagraph two' + b'\r\nEND:VCALENDAR\r\n' ) # INLINE properties have their values on one property line. Note the # double quoting of the value with a colon in it. c = Calendar() c['resources'] = 'Chair, Table, "Room: 42"' self.assertEqual( c, Calendar({'RESOURCES': 'Chair, Table, "Room: 42"'}) ) self.assertEqual( c.to_ical(), b'BEGIN:VCALENDAR\r\nRESOURCES:Chair\\, Table\\, "Room: 42"\r\n' + b'END:VCALENDAR\r\n' ) # The inline values must be handled by the get_inline() and # set_inline() methods. self.assertEqual( c.get_inline('resources', decode=0), [u'Chair', u'Table', u'Room: 42'] ) # These can also be decoded self.assertEqual( c.get_inline('resources', decode=1), [b'Chair', b'Table', b'Room: 42'] ) # You can set them directly ... c.set_inline('resources', ['A', 'List', 'of', 'some, recources'], encode=1) self.assertEqual(c['resources'], 'A,List,of,"some, recources"') # ... and back again self.assertEqual( c.get_inline('resources', decode=0), ['A', 'List', 'of', 'some, recources'] ) c['freebusy'] = '19970308T160000Z/PT3H,19970308T200000Z/PT1H,'\ + '19970308T230000Z/19970309T000000Z' self.assertEqual( c.get_inline('freebusy', decode=0), ['19970308T160000Z/PT3H', '19970308T200000Z/PT1H', '19970308T230000Z/19970309T000000Z'] ) freebusy = c.get_inline('freebusy', decode=1) self.assertTrue(isinstance(freebusy[0][0], datetime)) self.assertTrue(isinstance(freebusy[0][1], timedelta))
def test_cal_Component(self): from icalendar.cal import Component, Calendar, Event from icalendar import prop # A component is like a dictionary with extra methods and attributes. c = Component() c.name = 'VCALENDAR' # Every key defines a property.A property can consist of either a # single item. This can be set with a single value... c['prodid'] = '-//max m//icalendar.mxm.dk/' self.assertEqual(c, Calendar({'PRODID': '-//max m//icalendar.mxm.dk/'})) # or with a list c['ATTENDEE'] = ['Max M', 'Rasmussen'] self.assertEqual( c, Calendar({ 'ATTENDEE': ['Max M', 'Rasmussen'], 'PRODID': '-//max m//icalendar.mxm.dk/' })) ### ADD MULTIPLE VALUES TO A PROPERTY # if you use the add method you don't have to considder if a value is # a list or not. c = Component() c.name = 'VEVENT' # add multiple values at once c.add('attendee', ['*****@*****.**', '*****@*****.**']) # or add one per line c.add('attendee', '*****@*****.**') c.add('attendee', '*****@*****.**') # add again multiple values at once to very concatenaton of lists c.add('attendee', ['*****@*****.**', '*****@*****.**']) self.assertEqual( c, Event({ 'ATTENDEE': [ prop.vCalAddress('*****@*****.**'), prop.vCalAddress('*****@*****.**'), prop.vCalAddress('*****@*****.**'), prop.vCalAddress('*****@*****.**'), prop.vCalAddress('*****@*****.**'), prop.vCalAddress('*****@*****.**') ] })) ### # You can get the values back directly ... c.add('prodid', '-//my product//') self.assertEqual(c['prodid'], prop.vText(u'-//my product//')) # ... or decoded to a python type self.assertEqual(c.decoded('prodid'), b'-//my product//') # With default values for non existing properties self.assertEqual(c.decoded('version', 'No Version'), 'No Version') c.add('rdate', [datetime(2013, 3, 28), datetime(2013, 3, 27)]) self.assertTrue(isinstance(c.decoded('rdate'), prop.vDDDLists)) # The component can render itself in the RFC 2445 format. c = Component() c.name = 'VCALENDAR' c.add('attendee', 'Max M') self.assertEqual( c.to_ical(), b'BEGIN:VCALENDAR\r\nATTENDEE:Max M\r\nEND:VCALENDAR\r\n') # Components can be nested, so You can add a subcompont. Eg a calendar # holds events. e = Component(summary='A brief history of time') e.name = 'VEVENT' e.add('dtend', '20000102T000000', encode=0) e.add('dtstart', '20000101T000000', encode=0) self.assertEqual( e.to_ical(), b'BEGIN:VEVENT\r\nDTEND:20000102T000000\r\n' + b'DTSTART:20000101T000000\r\nSUMMARY:A brief history of time\r' + b'\nEND:VEVENT\r\n') c.add_component(e) self.assertEqual(c.subcomponents, [ Event({ 'DTEND': '20000102T000000', 'DTSTART': '20000101T000000', 'SUMMARY': 'A brief history of time' }) ]) # We can walk over nested componentes with the walk method. self.assertEqual([i.name for i in c.walk()], ['VCALENDAR', 'VEVENT']) # We can also just walk over specific component types, by filtering # them on their name. self.assertEqual([i.name for i in c.walk('VEVENT')], ['VEVENT']) self.assertEqual([i['dtstart'] for i in c.walk('VEVENT')], ['20000101T000000']) # We can enumerate property items recursively with the property_items # method. self.assertEqual(c.property_items(), [('BEGIN', b'VCALENDAR'), ('ATTENDEE', prop.vCalAddress('Max M')), ('BEGIN', b'VEVENT'), ('DTEND', '20000102T000000'), ('DTSTART', '20000101T000000'), ('SUMMARY', 'A brief history of time'), ('END', b'VEVENT'), ('END', b'VCALENDAR')]) # We can also enumerate property items just under the component. self.assertEqual(c.property_items(recursive=False), [('BEGIN', b'VCALENDAR'), ('ATTENDEE', prop.vCalAddress('Max M')), ('END', b'VCALENDAR')]) sc = c.subcomponents[0] self.assertEqual(sc.property_items(recursive=False), [('BEGIN', b'VEVENT'), ('DTEND', '20000102T000000'), ('DTSTART', '20000101T000000'), ('SUMMARY', 'A brief history of time'), ('END', b'VEVENT')]) # Text fields which span multiple mulitple lines require proper # indenting c = Calendar() c['description'] = u'Paragraph one\n\nParagraph two' self.assertEqual( c.to_ical(), b'BEGIN:VCALENDAR\r\nDESCRIPTION:Paragraph one\\n\\nParagraph two' + b'\r\nEND:VCALENDAR\r\n') # INLINE properties have their values on one property line. Note the # double quoting of the value with a colon in it. c = Calendar() c['resources'] = 'Chair, Table, "Room: 42"' self.assertEqual(c, Calendar({'RESOURCES': 'Chair, Table, "Room: 42"'})) self.assertEqual( c.to_ical(), b'BEGIN:VCALENDAR\r\nRESOURCES:Chair\\, Table\\, "Room: 42"\r\n' + b'END:VCALENDAR\r\n') # The inline values must be handled by the get_inline() and # set_inline() methods. self.assertEqual(c.get_inline('resources', decode=0), [u'Chair', u'Table', u'Room: 42']) # These can also be decoded self.assertEqual(c.get_inline('resources', decode=1), [b'Chair', b'Table', b'Room: 42']) # You can set them directly ... c.set_inline('resources', ['A', 'List', 'of', 'some, recources'], encode=1) self.assertEqual(c['resources'], 'A,List,of,"some, recources"') # ... and back again self.assertEqual(c.get_inline('resources', decode=0), ['A', 'List', 'of', 'some, recources']) c['freebusy'] = '19970308T160000Z/PT3H,19970308T200000Z/PT1H,'\ + '19970308T230000Z/19970309T000000Z' self.assertEqual(c.get_inline('freebusy', decode=0), [ '19970308T160000Z/PT3H', '19970308T200000Z/PT1H', '19970308T230000Z/19970309T000000Z' ]) freebusy = c.get_inline('freebusy', decode=1) self.assertTrue(isinstance(freebusy[0][0], datetime)) self.assertTrue(isinstance(freebusy[0][1], timedelta))
def test_cal_Component(self): from icalendar.cal import Component, Calendar, Event from icalendar import prop # A component is like a dictionary with extra methods and attributes. c = Component() c.name = "VCALENDAR" # Every key defines a property.A property can consist of either a # single item. This can be set with a single value... c["prodid"] = "-//max m//icalendar.mxm.dk/" self.assertEqual(c, Calendar({"PRODID": "-//max m//icalendar.mxm.dk/"})) # or with a list c["ATTENDEE"] = ["Max M", "Rasmussen"] self.assertEqual(c, Calendar({"ATTENDEE": ["Max M", "Rasmussen"], "PRODID": "-//max m//icalendar.mxm.dk/"})) ### ADD MULTIPLE VALUES TO A PROPERTY # if you use the add method you don't have to considder if a value is # a list or not. c = Component() c.name = "VEVENT" # add multiple values at once c.add("attendee", ["*****@*****.**", "*****@*****.**"]) # or add one per line c.add("attendee", "*****@*****.**") c.add("attendee", "*****@*****.**") # add again multiple values at once to very concatenaton of lists c.add("attendee", ["*****@*****.**", "*****@*****.**"]) self.assertEqual( c, Event( { "ATTENDEE": [ prop.vCalAddress("*****@*****.**"), prop.vCalAddress("*****@*****.**"), prop.vCalAddress("*****@*****.**"), prop.vCalAddress("*****@*****.**"), prop.vCalAddress("*****@*****.**"), prop.vCalAddress("*****@*****.**"), ] } ), ) ### # You can get the values back directly ... c.add("prodid", "-//my product//") self.assertEqual(c["prodid"], prop.vText(u"-//my product//")) # ... or decoded to a python type self.assertEqual(c.decoded("prodid"), b"-//my product//") # With default values for non existing properties self.assertEqual(c.decoded("version", "No Version"), "No Version") c.add("rdate", [datetime(2013, 3, 28), datetime(2013, 3, 27)]) self.assertTrue(isinstance(c.decoded("rdate"), prop.vDDDLists)) # The component can render itself in the RFC 2445 format. c = Component() c.name = "VCALENDAR" c.add("attendee", "Max M") self.assertEqual(c.to_ical(), b"BEGIN:VCALENDAR\r\nATTENDEE:Max M\r\nEND:VCALENDAR\r\n") # Components can be nested, so You can add a subcompont. Eg a calendar # holds events. e = Component(summary="A brief history of time") e.name = "VEVENT" e.add("dtend", "20000102T000000", encode=0) e.add("dtstart", "20000101T000000", encode=0) self.assertEqual( e.to_ical(), b"BEGIN:VEVENT\r\nDTEND:20000102T000000\r\n" + b"DTSTART:20000101T000000\r\nSUMMARY:A brief history of time\r" + b"\nEND:VEVENT\r\n", ) c.add_component(e) self.assertEqual( c.subcomponents, [Event({"DTEND": "20000102T000000", "DTSTART": "20000101T000000", "SUMMARY": "A brief history of time"})], ) # We can walk over nested componentes with the walk method. self.assertEqual([i.name for i in c.walk()], ["VCALENDAR", "VEVENT"]) # We can also just walk over specific component types, by filtering # them on their name. self.assertEqual([i.name for i in c.walk("VEVENT")], ["VEVENT"]) self.assertEqual([i["dtstart"] for i in c.walk("VEVENT")], ["20000101T000000"]) # We can enumerate property items recursively with the property_items # method. self.assertEqual( c.property_items(), [ ("BEGIN", b"VCALENDAR"), ("ATTENDEE", prop.vCalAddress("Max M")), ("BEGIN", b"VEVENT"), ("DTEND", "20000102T000000"), ("DTSTART", "20000101T000000"), ("SUMMARY", "A brief history of time"), ("END", b"VEVENT"), ("END", b"VCALENDAR"), ], ) # We can also enumerate property items just under the component. self.assertEqual( c.property_items(recursive=False), [("BEGIN", b"VCALENDAR"), ("ATTENDEE", prop.vCalAddress("Max M")), ("END", b"VCALENDAR")], ) sc = c.subcomponents[0] self.assertEqual( sc.property_items(recursive=False), [ ("BEGIN", b"VEVENT"), ("DTEND", "20000102T000000"), ("DTSTART", "20000101T000000"), ("SUMMARY", "A brief history of time"), ("END", b"VEVENT"), ], ) # Text fields which span multiple mulitple lines require proper # indenting c = Calendar() c["description"] = u"Paragraph one\n\nParagraph two" self.assertEqual( c.to_ical(), b"BEGIN:VCALENDAR\r\nDESCRIPTION:Paragraph one\\n\\nParagraph two" + b"\r\nEND:VCALENDAR\r\n" ) # INLINE properties have their values on one property line. Note the # double quoting of the value with a colon in it. c = Calendar() c["resources"] = 'Chair, Table, "Room: 42"' self.assertEqual(c, Calendar({"RESOURCES": 'Chair, Table, "Room: 42"'})) self.assertEqual( c.to_ical(), b'BEGIN:VCALENDAR\r\nRESOURCES:Chair\\, Table\\, "Room: 42"\r\n' + b"END:VCALENDAR\r\n" ) # The inline values must be handled by the get_inline() and # set_inline() methods. self.assertEqual(c.get_inline("resources", decode=0), [u"Chair", u"Table", u"Room: 42"]) # These can also be decoded self.assertEqual(c.get_inline("resources", decode=1), [b"Chair", b"Table", b"Room: 42"]) # You can set them directly ... c.set_inline("resources", ["A", "List", "of", "some, recources"], encode=1) self.assertEqual(c["resources"], 'A,List,of,"some, recources"') # ... and back again self.assertEqual(c.get_inline("resources", decode=0), ["A", "List", "of", "some, recources"]) c["freebusy"] = "19970308T160000Z/PT3H,19970308T200000Z/PT1H," + "19970308T230000Z/19970309T000000Z" self.assertEqual( c.get_inline("freebusy", decode=0), ["19970308T160000Z/PT3H", "19970308T200000Z/PT1H", "19970308T230000Z/19970309T000000Z"], ) freebusy = c.get_inline("freebusy", decode=1) self.assertTrue(isinstance(freebusy[0][0], datetime)) self.assertTrue(isinstance(freebusy[0][1], timedelta))
def get_calendar_entry(self): """ Build the iCalendar string for the event iCal validator, useful for debugging: http://icalvalid.cloudapp.net/ """ event = self.event event_tz = event.timezone creation_time = django_timezone.now() # Generate some description strings title, desc_plain, _desc_html = self.get_invite_texts() # Generate the Calendar event cal = icalendar.Calendar() cal.add("prodid", "-//OneEvent event entry//onevent//EN") cal.add("version", "2.0") cal.add("calscale", "GREGORIAN") cal.add("method", "REQUEST") # Generate timezone infos relevant to the event tzmap = {} tzmap = add_to_zones_map(tzmap, event_tz.zone, event.start) tzmap = add_to_zones_map(tzmap, event_tz.zone, event.get_real_end()) tzmap = add_to_zones_map(tzmap, django_timezone.get_default_timezone_name(), creation_time) for tzid, transitions in tzmap.items(): cal_tz = icalendar.Timezone() cal_tz.add("tzid", tzid) cal_tz.add("x-lic-location", tzid) for transition, tzinfo in transitions.items(): if tzinfo["dst"]: cal_tz_sub = icalendar.TimezoneDaylight() else: cal_tz_sub = icalendar.TimezoneStandard() cal_tz_sub.add("tzname", tzinfo["name"]) cal_tz_sub.add("dtstart", transition) cal_tz_sub.add("tzoffsetfrom", tzinfo["tzoffsetfrom"]) cal_tz_sub.add("tzoffsetto", tzinfo["tzoffsetto"]) cal_tz.add_component(cal_tz_sub) cal.add_component(cal_tz) cal_evt = icalendar.Event() cal_evt.add("uid", "event{0}-booking{1}@oneevent".format(event.id, self.id)) cal_evt.add("dtstamp", creation_time) cal_evt.add("dtstart", event.start.astimezone(event_tz)) cal_evt.add("dtend", event.get_real_end().astimezone(event_tz)) cal_evt.add("created", creation_time) cal_evt.add("sequence", "1") cal_evt.add("summary", title) cal_evt.add("description", desc_plain) cal_evt.add("location", vText(event.location_name)) cal_evt.add("category", "Event") cal_evt.add("status", "CONFIRMED") cal_evt.add("transp", "OPAQUE") cal_evt.add("priority", "5") cal_evt.add("class", "PUBLIC") organiser = vCalAddress("mailto:{0}".format(event.owner.email)) organiser.params["cn"] = vText(event.owner.get_full_name()) organiser.params["role"] = vText("CHAIR") cal_evt.add("organizer", organiser, encode=0) attendee = vCalAddress("mailto:{0}".format(self.person.email)) attendee.params["cutype"] = vText("INDIVIDUAL") attendee.params["role"] = vText("REQ-PARTICIPANT") attendee.params["partstat"] = vText("NEEDS-ACTION") attendee.params["rsvp"] = vText("FALSE") attendee.params["cn"] = vText(self.person.get_full_name()) cal_evt.add("attendee", attendee, encode=0) cal.add_component(cal_evt) return cal.to_ical()
def marshall_event_to_vevent(instance): wf = getToolByName(instance, 'portal_workflow') dtstamp = utc_strftime(datetime.utcnow(), "%Y%m%dT%H%M%SZ") uid_hash = abs(hash(instance)) state = wf.getInfoFor(instance, 'review_state') status = re_status_mapping.get(state, 'TENTATIVE') event = VEvent() event.add('uid', generateUID(instance)) event.add('summary', instance.Title(), encode=False) event.add('description', instance.Description(), encode=False) if hasattr(aq_base(instance), 'getLocation'): location = instance.getLocation() if location: event.add('location', location, encode=False) if hasattr(aq_base(instance), 'Subject'): subject = instance.Subject() if subject: for category in subject: event.add('categories', category, encode=False) if hasattr(aq_base(instance), 'event_url'): url = instance.event_url if callable(url): # Ugh, it's callable in ATContentTypes. url = url() if url: event.add('url', url) event['url'].params['value'] = 'URI' if hasattr(aq_base(instance), 'getAttendees'): for att in instance.getAttendees(): name, email = parseaddr(att) if not name: name = att email = '' if email: email = 'mailto:%s' % email else: email = 'invalid:nomail' address = vCalAddress(email) address.params['cn'] = name event.add('attendee', address, encode=False) if (hasattr(aq_base(instance), 'duration') and instance.duration == date.resolution): # All day event. dtstart = vDate.from_ical( utc_strftime(instance.start_date, '%Y%m%d')) event.add('dtstart', dtstart) dtend = vDate.from_ical( utc_strftime(instance.end_date, '%Y%m%d')) event.add('dtend', dtend) else: # Normal event dtstart = vDatetime.from_ical( utc_strftime(instance.start_date, '%Y%m%dT%H%M%SZ')) event.add('dtstart', dtstart) dtend = vDatetime.from_ical( utc_strftime(instance.end_date, '%Y%m%dT%H%M%SZ')) event.add('dtend', dtend) dtstamp = vDatetime.from_ical(dtstamp) event.add('dtstamp', dtstamp) #event.add('status', status) return event