def __call__(self):
        request = self.context.REQUEST
        event_uid = request.get('event')

        if event_uid:
            event_uid = event_uid.split('UID_')[1]

        brains = self.context.portal_catalog(UID=event_uid)
        obj = brains[0].getObject()
        startDate, endDate = starts(obj), ends(obj)
        dayDelta, minuteDelta = float(request.get('dayDelta', 0)), float(
            request.get('minuteDelta', 0))
        startDate = startDate + dayDelta + minuteDelta / 1440.0
        endDate = endDate + dayDelta + minuteDelta / 1440.0

        if HAS_PAE and not hasattr(obj, 'setStartDate'):
            # non-Archetypes duck type: use properties for start/end,
            # along with UTC-normalized datetime.datetime values
            from plone.event.utils import pydt
            obj.start = pydt(startDate)
            obj.end = pydt(endDate)
        else:
            obj.setStartDate(startDate)
            obj.setEndDate(endDate)
        adapted = interfaces.ISFBaseEventFields(obj, None)
        if adapted:
            if request.get('allDay', None) == 'true':
                setattr(adapted, 'allDay', True)
            if request.get('allDay', None) == 'false':
                setattr(adapted, 'allDay', False)

        obj.reindexObject()
        return True
Exemple #2
0
def get_events_by_date(context, range_start=None, range_end=None, **kw):
    """ Return a dictionary with dates in a given timeframe as keys and
    the actual events for that date.

    """
    # TODO: factor out, use for get_portal_events and whole_day_handler too.
    tz = default_tzinfo(context)
    range_start = pydt(range_start, missing_zone=tz)
    if isinstance(range_end, date):
        # set range_end to the next day, time will be 0:00
        # so the whole previous day is also used for search
        range_end = range_end + timedelta(days=1)
    range_end = pydt(range_end, missing_zone=tz)

    events = get_portal_events(context, range_start, range_end, **kw)
    # TODO: catalog brains are timezone'd. shouldn't they be in UTC?
    ## example catalog entry: 2011/09/16 16:35:00 Brazil/West
    events_by_date = {}
    for event in events:
        obj = event.getObject()
        occurrences = obj.occurrences(range_start, range_end)
        for occ in occurrences:
            # occ: (start, end)
            start_str = datetime.strftime(occ[0], '%Y-%m-%d')
            # TODO: add span_events parameter to include dates btw. start
            # and end also. for events lasting longer than a day...
            if start_str not in events_by_date:
                events_by_date[start_str] = [event]
            else:
                events_by_date[start_str].append(event)
    return events_by_date
Exemple #3
0
def _prepare_range(context, start, end):
    """Prepare a date-range to contain timezone info and set end to next day,
    if end is a date.

    :param context: [required] Context object.
    :type context: Content object

    :param start: [required] Range start.
    :type start: Python date or datetime

    :param end: [required] Range end.
    :type end: Python date or datetime

    :returns: Localized start and end datetime.
    :rtype: tuple

    """
    tz = default_timezone(context, as_tzinfo=True)
    start = pydt(start, missing_zone=tz)
    if is_date(end):
        # set range_end to the next day, time will be 0:00
        # so the whole previous day is also used for search
        end = end + timedelta(days=1)
    end = pydt(end, missing_zone=tz)
    return start, end
Exemple #4
0
def _prepare_range(context, start, end):
    """Prepare a date-range to contain timezone info and set end to next day,
    if end is a date.

    :param context: [required] Context object.
    :type context: Content object

    :param start: [required] Range start.
    :type start: Python date or datetime

    :param end: [required] Range end.
    :type end: Python date or datetime

    :returns: Localized start and end datetime.
    :rtype: tuple

    """
    tz = default_timezone(context, as_tzinfo=True)
    start = pydt(start, missing_zone=tz)
    if is_date(end):
        # set range_end to the next day, time will be 0:00
        # so the whole previous day is also used for search
        end = end + timedelta(days=1)
    end = pydt(end, missing_zone=tz)
    return start, end
    def __call__(self):
        request = self.context.REQUEST
        event_uid = request.get('event')

        if event_uid:
            event_uid = event_uid.split('UID_')[1]

        brains = self.context.portal_catalog(UID=event_uid)
        obj = brains[0].getObject()
        startDate, endDate = starts(obj), ends(obj)
        dayDelta, minuteDelta = float(request.get('dayDelta', 0)), float(request.get('minuteDelta', 0))
        startDate = startDate + dayDelta + minuteDelta / 1440.0
        endDate = endDate + dayDelta + minuteDelta / 1440.0

        if HAS_PAE and not hasattr(obj, 'setStartDate'):
            # non-Archetypes duck type: use properties for start/end,
            # along with UTC-normalized datetime.datetime values
            from plone.event.utils import pydt
            obj.start = pydt(startDate)
            obj.end = pydt(endDate)
        else:
            obj.setStartDate(startDate)
            obj.setEndDate(endDate)
        adapted = interfaces.ISFBaseEventFields(obj, None)
        if adapted:
            if request.get('allDay', None) == 'true':
                setattr(adapted, 'allDay', True)
            if request.get('allDay', None) == 'false':
                setattr(adapted, 'allDay', False)

        obj.reindexObject()
        return True
Exemple #6
0
 def __init__(self, uid=None, title=None, description=None, start=None,
              end=None, whole_day=None, created=None, modified=None,
              location=None, subject=[], attendees=[], contact_name=None,
              contact_phone=None, contact_email=None, event_url=None,
              recurrence=None, start_date=None, end_date=None):
     # start_date and end_date can be directly set with datetime values, if
     # no start or end DateTime is set.
     self.uid = uid
     self.title = title
     self.description = description
     self._start = start and DateTime(start) or None
     self.start_date = start and pydt(self._start) or start_date
     self._end = end and DateTime(end) or None
     self.end_date = end and pydt(self._end) or end_date
     self._whole_day = whole_day
     self.created = created
     self.modified = modified
     self.location = location
     self.subject = subject
     self.attendees = attendees
     self.cname = contact_name
     self.cphone = contact_phone
     self.cemail = contact_email
     self.eurl = event_url
     self.recurrence = recurrence
     self.duration = self.start_date and self.end_date and\
                     self.end_date-self.start_date or None
 def test_edit(self):
     new = self.obj
     self._edit_atevent(new)
     self.assertEqual(new.start_date, pydt(new.start()))
     self.assertEqual(new.end_date, pydt(new.end()))
     self.assertEqual(new.start_date, pydt(OBJ_DATA['startDate']))
     self.assertEqual(new.end_date, pydt(OBJ_DATA['endDate']))
     self.assertEqual(new.duration, new.end_date - new.start_date)
Exemple #8
0
    def __iter__(self):
        """Iterate over items."""
        default_timezone = self.options.get('default_timezone') or 'UTC'
        if HAS_PAC:
            try:
                tz = api.portal.get_registry_record('plone.portal_timezone')
            except InvalidParameterError:
                tz = None
            if tz is not None:
                tz = timezone(tz)
            else:
                tz = timezone(default_timezone)

        for item in self.previous:
            if self.condition(item):
                pathkey = self.pathkey(*item.keys())[0]
                if not pathkey:  # not enough info
                    yield item
                    continue
                path = item[pathkey]

                obj = traverse(self.context, str(path).lstrip('/'), None)
                if obj is None:
                    yield item
                    continue  # object not found
                print("SetAndFixKnownDates")
                if 'creation_date' in item:
                    # try:
                    #     obj.setCreationDate(item['creation_date'])
                    # except AttributeError:
                    #     # dexterity content does not have setCreationDate
                    #     obj.creation_date = item['creation_date']
                    obj.creation_date = item['creation_date']
                if 'modification_date' in item:
                    obj.setModificationDate(item['modification_date'])
                effectiveDate = item.get('effectiveDate', None)
                if effectiveDate and effectiveDate != u"None":
                    obj.setEffectiveDate(effectiveDate)
                else:
                    obj.setEffectiveDate(item.get('modification_date', None))
                # if item['_path']==u'/organisation/gv/arbeitshilfen/exuperantius/exuperantius-05-oeffentlichkeitsarbeit':
                #     import pdb; pdb.set_trace()
                print(item.get('effectiveDate', None) or item.get('modification_date', None))
                if 'expirationDate' in item:
                    obj.setExpirationDate(item['expirationDate'])

                # Fix issue where expiration date was before effective date
                effective = obj.effective()
                expires = obj.expires()
                if effective and expires and expires < effective:
                    obj.setExpirationDate(effective)

                if HAS_PAC and item.get('_type') == 'Event':
                    # obj = resolve_object(context, item)
                    obj.start = pydt(DateTime(obj.start)).astimezone(tz)
                    obj.end = pydt(DateTime(obj.end)).astimezone(tz)

            yield item
def recurrence_sequence_timedelta(start, delta=None, until=None, count=None,
                                  dst=DSTAUTO):
    """ Calculates a sequence of datetime objects from a timedelta integer,
    which defines the minutes between each occurence.

    :param start: datetime or DateTime instance of the date from which the
                  recurrence sequence is calculated.
    :type start: datetime

    :param delta: Integer which defines the minutes
                  between each date occurence.
    :type delta: integer

    :param until: datetime or DateTime instance of the date, until the
                  recurrence is calculated. If not given,
                  count or MAXDATE limit the recurrence calculation.
    :type until: datetime

    :param count: Integer which defines the number of occurences. If not given,
                  until or MAXDATE limits the recurrence calculation.
    :param count: integer

    :param dst:   Daylight Saving Time crossing behavior. DSTAUTO, DSTADJUST or
                  DSTKEEP. For more information, see
                  plone.event.utils.utcoffset_normalize.
    :param dst: string

    :return: A generator which generates a sequence of datetime instances.
    :rtype: generator

    """
    start = pydt(start)
    yield start

    if delta is None or delta < 1 or until is None:
        return

    until = pydt(until)

    before = start
    delta = datetime.timedelta(minutes=delta)
    cnt = 0
    while True:
        after = before + delta
        after = utcoffset_normalize(after, delta, dst)

        # Limit number of recurrences otherwise calculations take too long
        if MAXCOUNT and cnt + 1 > MAXCOUNT:
            break
        if count and cnt + 1 > count:
            break
        if until and utc(after) > utc(until):
            break
        cnt += 1

        yield after
        before = after
    def __call__(self):
        msg = PLMF(u'Copy or cut one or more items to paste.')
        self.request.response.setHeader("Content-type", "application/json")
        if self.context.cb_dataValid():
            try:
                baseObject = self.portal.restrictedTraverse(
                    self.copyDict['url'])
                baseId = 'UID_' + get_uid(baseObject)
                intervalle = ends(baseObject) - starts(baseObject)
                cb_copy_data = self.request['__cp']
                pasteList = self.context.manage_pasteObjects(
                    cb_copy_data=cb_copy_data)
                newObject = getattr(self.context, pasteList[0]['new_id'])
                startDate = self.startDate
                if self.EventAllDay:
                    startDate = DateTime(self.startDate).strftime(
                        '%Y-%m-%d ') + starts(baseObject).strftime('%H:%M')

                if HAS_PAE and not hasattr(newObject, 'setStartDate'):
                    # non-Archetypes duck type: use properties for start/end,
                    # along with UTC-normalized datetime.datetime values
                    from plone.event.utils import pydt
                    import pytz
                    local_start = DateTime(startDate)
                    _utc = lambda dt: pytz.UTC.normalize(dt)
                    newObject.start = _utc(pydt(local_start))
                    newObject.end = _utc(pydt(local_start + intervalle))
                    newObject.whole_day = self.EventAllDay
                else:
                    newObject.setStartDate(DateTime(startDate))
                    newObject.setEndDate(
                        newObject.getField('startDate').get(newObject) +
                        intervalle)
                newObject.reindexObject()
                transaction_note('Pasted content to %s' %
                                 (self.context.absolute_url()))
                return json.dumps({
                    'status': 'pasted',
                    'event': self.createJsonEvent(newObject),
                    'url': newObject.absolute_url(),
                    'op': self.copyDict['op'],
                    'id': baseId
                })
            except ConflictError:
                raise
            except ValueError:
                msg = PLMF(u'Disallowed to paste item(s).')
            except (Unauthorized, 'Unauthorized'):
                msg = PLMF(u'Unauthorized to paste item(s).')
            except CopyError:  # fallback
                msg = PLMF(u'Paste could not find clipboard content.')

        return json.dumps({
            'status': 'failure',
            'message': self.context.translate(msg)
        })
Exemple #11
0
    def _get_due(self, value=None):
        if value is None:
            value = getattr(self.context, 'due', None)
            if not value:
                taskplanner = self._get_taskplanner(self.context)
                if taskplanner:
                    value = getattr(taskplanner, 'due', None)

        if not value:
            return

        _type = value.get('type')
        _value = value.get('value')

        if _type == 'date':
            return parse_datetime(_value)

        elif _type == 'computed':
            field4 = getattr(self.context, _value['field4'])

            if not field4:
                return

            field3 = self._get_value(_value['field3'], TIME_RELATIONS)[2]

            if safe_callable(field4):
                field4 = field4()
            if isinstance(field4, DateTime):
                field4 = pydt(field4)

            if field3 is None:
                return field4
            else:
                field2 = self._get_value(_value['field2'], TIME_UNITS)[2]
                field1 = int(_value['field1'])
                return field4 + field2(field3 * field1)

        elif _type == 'computed_dow':
            field4 = getattr(self.context, _value['field4'])

            if not field4:
                return

            field3 = self._get_value(_value['field3'], TIME_RELATIONS)[2]

            if safe_callable(field4):
                field4 = field4()
            if isinstance(field4, DateTime):
                field4 = pydt(field4)

            if field3 is None:
                return field4
            else:
                field2 = self._get_value(_value['field2'], DAYS_OF_WEEK)[2]
                field1 = int(_value['field1'])
                return field4 + field2(field3 * field1)
Exemple #12
0
 def test_pydt__missing_zone_is_None(self, utctz, guesstz):
     from plone.event.utils import pydt
     dt = mock.Mock()
     dt.toZone.return_value = dt
     dt.parts.return_value = (2011, 11, 24, 11, 39, 00)
     guesstz.return_value = None
     import pytz
     utctz.return_value = pytz.timezone('UTC')
     pydt(dt)
     self.assertTrue(utctz.called)
Exemple #13
0
def event_component(context):
    """ Returns an icalendar object of the event.

    """
    ical_event = icalendar.Event()
    # TODO: until VTIMETZONE component is added and TZID used, everything is
    #       converted to UTC. use real TZID, when VTIMEZONE is used!
    ical_event.add('dtstamp', utc(pydt(datetime.now())))
    ical_event.add('created', utc(pydt(context.creation_date)))
    ical_event.add('uid', context.UID())
    ical_event.add('last-modified', utc(pydt(context.modification_date)))
    ical_event.add('summary', context.Title())
    ical_event.add('dtstart', utc(pydt(context.start())))
    ical_event.add('dtend', utc(pydt(context.end())))

    recurrence = context.recurrence
    if recurrence:
        if recurrence.startswith('RRULE:'): recurrence = recurrence[6:]
        ical_event.add('rrule', icalendar.prop.vRecur.from_ical(recurrence))

    description = context.Description()
    if description:
        ical_event.add('description', description)

    location = context.getLocation()
    if location:
        ical_event.add('location', location)

    subjects= context.Subject()
    for subject in subjects:
        ical_event.add('categories', subject)

    # TODO: revisit and implement attendee export according to RFC
    attendees = context.getAttendees()
    for attendee in attendees:
        ical_event.add('attendee', attendee)

    cn = []
    contact = context.contact_name()
    if contact:
        cn.append(contact) # TODO safe_unicode conversion needed?
    phone = context.contact_phone()
    if phone:
        cn.append(phone)
    email = context.contact_email()
    if email:
        cn.append(email)
    if cn:
        ical_event.add('contact', u', '.join(cn))

    url = context.event_url()
    if url:
        ical_event.add('url', url)

    return ical_event
    def test_import_from_ics(self):
        # Ical import unit test.
        self.portal.invokeFactory("Folder", "impfolder1")
        impfolder = self.portal.impfolder1

        directory = os.path.dirname(__file__)
        icsfile = open(os.path.join(directory, "icaltest.ics"), "rb").read()
        res = ical_import(impfolder, icsfile, self.event_type)

        self.assertEqual(res["count"], 5)
        self.assertEqual(len(impfolder.contentIds()), 5)

        at = pytz.timezone("Europe/Vienna")
        utc = pytz.utc

        # Use pydt to normalize for DST times.

        # TODO: test for attendees. see note in
        # plone.app.event.ical.importer.ical_import
        e1 = IEventAccessor(impfolder.e1)
        self.assertEqual(e1.start, pydt(datetime(2013, 7, 19, 12, 0, tzinfo=at)))
        self.assertEqual(e1.end, pydt(datetime(2013, 7, 20, 13, 0, tzinfo=at)))
        self.assertEqual(e1.description, "A basic event with many properties.")
        self.assertEqual(e1.whole_day, False)
        self.assertEqual(e1.open_end, False)
        self.assertEqual(e1.sync_uid, u"48f1a7ad64e847568d860cd092344970")

        e2 = IEventAccessor(impfolder.e2)
        self.assertEqual(e2.start, pydt(datetime(1996, 4, 1, 1, 0, tzinfo=utc)))
        self.assertEqual(e2.end, pydt(datetime(1996, 4, 1, 2, 0, tzinfo=utc)))
        self.assertEqual(
            e2.recurrence, u"RRULE:FREQ=DAILY;COUNT=100\nEXDATE:19960402T010000Z," u"19960403T010000Z,19960404T010000Z"
        )

        e3 = IEventAccessor(impfolder.e3)
        self.assertEqual(e3.start, pydt(datetime(2012, 3, 27, 10, 0, tzinfo=at)))
        self.assertEqual(e3.end, pydt(datetime(2012, 3, 27, 18, 0, tzinfo=at)))
        self.assertEqual(
            e3.recurrence,
            u"RRULE:FREQ=WEEKLY;UNTIL=20120703T080000Z;BYDAY=TU\n"
            u"EXDATE:20120529T100000,20120403T100000,20120410T100000,"
            u"20120501T100000,20120417T100000",
        )

        e4 = IEventAccessor(impfolder.e4)
        self.assertEqual(e4.start, pydt(datetime(2013, 4, 4, 0, 0, tzinfo=utc)))
        self.assertEqual(e4.end, pydt(datetime(2013, 4, 4, 23, 59, 59, tzinfo=utc)))
        self.assertEqual(e4.whole_day, True)
        self.assertEqual(e4.open_end, False)

        e5 = IEventAccessor(impfolder.e5)
        self.assertEqual(e5.start, pydt(datetime(2013, 4, 2, 12, 0, tzinfo=utc)))
        self.assertEqual(e5.end, pydt(datetime(2013, 4, 2, 23, 59, 59, tzinfo=utc)))
        self.assertEqual(e5.whole_day, False)
        self.assertEqual(e5.open_end, True)
    def create_g24_event(self, container, node):
        title = node.getAttribute('pc_title')
        try:
            text = node.getElementsByTagName('text')[0].childNodes[1].data
        except IndexError:
            text = u''
        tags = []
        for t in node.getElementsByTagName('tag'):
            tags.append(t.getAttribute('name'))

        loc = node.getAttribute('location_name')
        data = {
            'is_event': True,
            'title': title,
            'text': text,
            'subjects': tags,
            'timezone': 'Europe/Vienna',
            'whole_day': node.getAttribute('pc_alldayevent') == "1",
            'open_end': False,
            'recurrence': None,
            'location': LOC_TO_UUID.get(loc),
        }

        createdate = DateTime(node.getAttribute('pc_time'))
        event_date = DateTime(
            node.getAttribute('pc_eventDate') + " " +
            node.getAttribute('pc_startTime') + " Europe/Vienna"
        )
        data['start'] = pydt(event_date)

        # calc / use end date , fallback is same as start
        data['end'] = pydt(event_date)
        if node.hasAttribute('pc_endDate'):
            end_date = DateTime(
                node.getAttribute('pc_endDate') + " " +
                node.getAttribute('pc_endTime') + " Europe/Vienna"
            )
            data['end'] = pydt(end_date)
        elif node.getAttribute('pc_duration'):
            end_date = DateTime(
                int(event_date) +
                int(node.getAttribute('pc_duration'))
            )
            data['end'] = pydt(end_date)

        obj = create(container, G24_BASETYPE)
        # set the creators by loginname. if more than one,
        # seperate by whitespace
        obj.setCreators(node.getAttribute('pc_informant'))
        obj.creation_date = createdate
        edit(obj, data, order=FEATURES)
        obj = add(obj, container)

        return obj
Exemple #16
0
def get_recurring_events(request, event):
    if isinstance(event.start, datetime):
        tz = event.start.tzinfo
        start = datetime.fromtimestamp(request.get('start')).replace(tzinfo=tz)
        end = datetime.fromtimestamp(request.get('end')).replace(tzinfo=tz)
    else:
        start = pydt(DateTime(request.get('start')))
        end = pydt(DateTime(request.get('end')))
    events = IRecurrenceSupport(event).occurrences(range_start=start,
                                                   range_end=end)
    return events
Exemple #17
0
 def test_pydt__missing_zone_is_not_None(self, utctz, guesstz):
     from plone.event.utils import pydt
     dt = mock.Mock()
     import pytz
     utctz.return_value = pytz.timezone('UTC')
     missing_zone = utctz()
     dt.toZone.return_value = dt
     dt.parts.return_value = (2011, 11, 24, 11, 39, 00)
     guesstz.return_value = None
     pydt(dt, missing_zone=missing_zone)
     self.assertEqual(utctz.call_count, 1)
Exemple #18
0
    def to_icalendar(self):
        """ Returns an icalendar object of the event.

        """
        event = self
        ical_event = icalendar.Event()
        ical_event.add('dtstamp', datetime.now())
        ical_event.add('created', pydt(event.creation_date))
        ical_event.add('uid', event.UID())
        ical_event.add('last-modified', pydt(event.modification_date))
        ical_event.add('summary', event.Title())
        ical_event.add('dtstart', pydt(event.start()))
        ical_event.add('dtend', pydt(event.end()))

        recurrence = event.recurrence
        if recurrence:
            ical_event.add('rrule', icalendar.prop.vRecur.from_ical(recurrence))

        description = event.Description()
        if description:
            ical_event.add('description', description)

        location = event.getLocation()
        if location:
            ical_event.add('location', location)

        subjects= event.Subject()
        for subject in subjects:
            ical_event.add('categories', subject)

        # TODO: revisit and implement attendee export according to RFC
        attendees = event.getAttendees()
        for attendee in attendees:
            ical_event.add('attendee', attendee)

        cn = []
        contact = event.contact_name()
        if contact:
            cn.append(contact) # TODO safe_unicode conversion needed?
        phone = event.contact_phone()
        if phone:
            cn.append(phone)
        email = event.contact_email()
        if email:
            cn.append(email)
        if cn:
            ical_event.add('contact', u', '.join(cn))

        url = event.event_url()
        if url:
            ical_event.add('url', url)

        return ical_event
    def test_edit(self):
        new = self.obj
        self._edit_atevent(new)
        self.assertEqual(new.start_date, pydt(new.start()))
        self.assertEqual(new.end_date, pydt(new.end()))

        # TODO: sometimes the following tests fails, because of comparison of
        # microseconds. Is it an rounding error?
        # AssertionError: datetime.datetime(2012, 10, 25, 14, 2, 11, 855640,
        # tzinfo=<DstTzInfo 'Europe/Vienna' CEST+2:00:00 DST>) !=
        # datetime.datetime(2012, 10, 25, 14, 2, 11, 85564, tzinfo=<DstTzInfo
        # 'Europe/Vienna' CEST+2:00:00 DST>)
        self.assertEqual(new.start_date, pydt(OBJ_DATA['startDate']))
        self.assertEqual(new.end_date, pydt(OBJ_DATA['endDate']))
        self.assertEqual(new.duration, new.end_date - new.start_date)
Exemple #20
0
    def start_date(self):
        """ Return start date as Python datetime.

        :returns: Start of the event.
        :rtype: Python datetime
        """
        return pydt(self.start(), exact=False)
Exemple #21
0
 def _get_compare_attr(obj, attr):
     val = getattr(obj, attr, None)
     if safe_callable(val):
         val = val()
     if isinstance(val, DateTime):
         val = pydt(val)
     return val
Exemple #22
0
    def start_date(self):
        """ Return start date as Python datetime.

        :returns: Start of the event.
        :rtype: Python datetime
        """
        return pydt(self.start(), exact=False)
Exemple #23
0
    def json_config(self):
        events = []
        for brain in self.results():
            event = {
                'title': brain.Title,
                'url': brain.getURL()
            }
            if brain.portal_type == 'Event':
                event.update({
                    'start': brain.start and format_date(brain.start),
                    'end': brain.end and format_date(brain.end)
                })
            else:
                event['start'] = format_date(brain.effective)
                if brain.expires and brain.expires.year() != 2499:
                    event['end'] = format_date(brain.expires)
                else:
                    event['end'] = format_date(pydt(brain.effective) + timedelta(hours=1))
            events.append(event)

        return json.dumps({
            'header': {
                'left': 'prev,next today',
                'center': 'title',
                'right': 'month,agendaWeek,agendaDay'
            },
            'events': events
        })
Exemple #24
0
 def _get_compare_attr(obj, attr):
     val = getattr(obj, attr, None)
     if safe_callable(val):
         val = val()
     if isinstance(val, DateTime):
         val = pydt(val)
     return val
    def __call__(self):
        msg=PLMF(u'Copy or cut one or more items to paste.')
        self.request.response.setHeader("Content-type","application/json")
        if self.context.cb_dataValid():
            try:
                baseObject = self.portal.restrictedTraverse(self.copyDict['url'])
                baseId = 'UID_' + get_uid(baseObject)
                intervalle = ends(baseObject) - starts(baseObject)
                cb_copy_data = self.request['__cp']
                pasteList = self.context.manage_pasteObjects(cb_copy_data=cb_copy_data)
                newObject = getattr(self.context, pasteList[0]['new_id'])
                startDate = self.startDate
                if self.EventAllDay:
                    startDate = DateTime(self.startDate).strftime('%Y-%m-%d ')+starts(baseObject).strftime('%H:%M')

                if HAS_PAE and not hasattr(newObject, 'setStartDate'):
                    # non-Archetypes duck type: use properties for start/end,
                    # along with UTC-normalized datetime.datetime values
                    from plone.event.utils import pydt
                    import pytz
                    local_start = DateTime(startDate)
                    _utc = lambda dt: pytz.UTC.normalize(dt)
                    newObject.start = _utc(pydt(local_start))
                    newObject.end = _utc(pydt(local_start + intervalle))
                    newObject.whole_day = self.EventAllDay
                else:
                    newObject.setStartDate(DateTime(startDate))
                    newObject.setEndDate(newObject.getField('startDate').get(newObject) + intervalle)
                newObject.reindexObject()
                transaction_note('Pasted content to %s' % (self.context.absolute_url()))
                return json.dumps({'status':'pasted',
                                   'event':self.createJsonEvent(newObject),
                                   'url':newObject.absolute_url(),
                                   'op':self.copyDict['op'],
                                   'id':baseId})
            except ConflictError:
                raise
            except ValueError:
                msg=PLMF(u'Disallowed to paste item(s).')
            except (Unauthorized, 'Unauthorized'):
                msg=PLMF(u'Unauthorized to paste item(s).')
            except CopyError: # fallback
                msg=PLMF(u'Paste could not find clipboard content.')

        return json.dumps({'status':'failure',
                           'message':self.context.translate(msg)})
Exemple #26
0
    def end_date(self):
        """ Return end date as Python datetime.

        Please note, the end date marks only the end of an individual
        occurrence and not the end of a recurrence sequence.

        :returns: End of the event.
        :rtype: Python datetime
        """
        return pydt(self.end(), exact=False)
Exemple #27
0
def _get_compare_attr(obj, attr):
    """Return an compare attribute, supporting AT, DX and IEventAccessor
    objects.
    """
    val = getattr(obj, attr, None)
    if safe_callable(val):
        val = val()
    if isinstance(val, DateTime):
        val = pydt(val)
    return val
Exemple #28
0
 def timestamp(self):
     item = self.latest_blogentry()
     date = item.getObject().effective()
     date = pydt(date)
     timestamp = {}
     timestamp['day'] = date.strftime("%d")
     timestamp['month'] = date.strftime("%B")
     timestamp['year'] = date.strftime("%Y")
     timestamp['date'] = date
     return timestamp
Exemple #29
0
 def timestamp(self, uid):
     item = api.content.get(UID=uid)
     date = item.created()
     date = pydt(date)
     timestamp = {}
     timestamp['day'] = date.strftime("%d")
     timestamp['month'] = date.strftime("%m")
     timestamp['year'] = date.strftime("%Y")
     timestamp['date'] = date
     return timestamp
Exemple #30
0
 def timestamp(self):
     context = aq_inner(self.context)
     date = context.effective()
     date = pydt(date)
     timestamp = {}
     timestamp['day'] = date.strftime("%d")
     timestamp['month'] = date.strftime("%B")
     timestamp['year'] = date.strftime("%Y")
     timestamp['date'] = date
     return timestamp
Exemple #31
0
    def end_date(self):
        """ Return end date as Python datetime.

        Please note, the end date marks only the end of an individual
        occurrence and not the end of a recurrence sequence.

        :returns: End of the event.
        :rtype: Python datetime
        """
        return pydt(self.end(), exact=False)
Exemple #32
0
def _get_compare_attr(obj, attr):
    """Return an compare attribute, supporting AT, DX and IEventAccessor
    objects.
    """
    val = getattr(obj, attr, None)
    if safe_callable(val):
        val = val()
    if isinstance(val, DateTime):
        val = pydt(val)
    return val
Exemple #33
0
 def get_obj(start):
     if pydt(event.start.replace(microsecond=0)) == start:
         # If the occurrence date is the same as the event object, the
         # occurrence is the event itself. return it as such.
         # Dates from recurrence_sequence_ical are explicitly without
         # microseconds, while event.start may contain it. So we have to
         # remove it for a valid comparison.
         return self.context
     return Occurrence(id=str(start.date()),
                       start=start,
                       end=start + duration).__of__(self.context)
 def time_stamp(self):
     context = aq_inner(self.context)
     date = context.effective()
     date = pydt(date)
     timestamp = {
         "day": date.strftime("%d"),
         "month": get_localized_month_name(date.strftime("%B")),
         "year": date.strftime("%Y"),
         "date": date,
     }
     return timestamp
Exemple #35
0
 def timestamp(self):
     item = self.latest_blogentry()
     date = item.getObject().effective()
     date = pydt(date)
     timestamp = {
         'day': date.strftime("%d"),
         'month': get_localized_month_name(date.strftime("%B")),
         'year': date.strftime("%Y"),
         'date': date
     }
     return timestamp
Exemple #36
0
    def __iter__(self):
        context = self.transmogrifier.context
        default_timezone = self.options.get('default_timezone') or 'UTC'
        if HAS_PAC:
            try:
                tz = api.portal.get_registry_record('plone.portal_timezone')
            except InvalidParameterError:
                tz = None
            if tz is not None:
                tz = timezone(tz)
            else:
                tz = timezone(default_timezone)

        for item in self.previous:
            if self.condition(item):
                obj = resolve_object(context, item)
                if 'creation_date' in item:
                    try:
                        obj.setCreationDate(item['creation_date'])
                    except AttributeError:
                        # dexterity content does not have setCreationDate
                        obj.creation_date = item['creation_date']
                if 'modification_date' in item:
                    obj.setModificationDate(item['modification_date'])
                if 'effective_date' in item:
                    obj.setEffectiveDate(item['effective_date'])
                if 'expiration_date' in item:
                    obj.setExpirationDate(item['expiration_date'])

                # Fix issue where expiration date was before effective date
                effective = obj.effective()
                expires = obj.expires()
                if effective and expires and expires < effective:
                    obj.setExpirationDate(effective)

                if HAS_PAC and item.get('_type') == 'Event':
                    obj = resolve_object(context, item)
                    obj.start = pydt(DateTime(obj.start)).astimezone(tz)
                    obj.end = pydt(DateTime(obj.end)).astimezone(tz)

            yield item
Exemple #37
0
 def get_obj(start):
     if pydt(event.start.replace(microsecond=0)) == start:
         # If the occurrence date is the same as the event object, the
         # occurrence is the event itself. return it as such.
         # Dates from recurrence_sequence_ical are explicitly without
         # microseconds, while event.start may contain it. So we have to
         # remove it for a valid comparison.
         return self.context
     return Occurrence(
         id=str(start.date()),
         start=start,
         end=start + duration).__of__(self.context)
    def test_traverse_occurrence(self):
        self.at.setRecurrence('RRULE:FREQ=WEEKLY;COUNT=10')
        transaction.commit()

        qdatedt = pydt(self.at.start() + 7)
        url = '/'.join([self.portal['at'].absolute_url(),
                        str(qdatedt.date())])

        browser = Browser(self.layer['app'])
        browser.addHeader('Authorization', 'Basic %s:%s' % (
            TEST_USER_ID, TEST_USER_PASSWORD))
        browser.open(url)
        self.assertTrue(
            self.portal['at'].title.encode('ascii') in browser.contents)
    def test_occurrence(self):
        self.at.setRecurrence('RRULE:FREQ=WEEKLY;COUNT=10')

        # does not match occurrence date
        qdate = datetime.date.today() + datetime.timedelta(days=4)
        self.assertRaises(
            AttributeError,
            self.at_traverser.publishTraverse,
            self.layer['request'], str(qdate))

        qdatedt = pydt(self.at.start() + 7)
        item = self.at_traverser.publishTraverse(self.layer['request'],
                                                 str(qdatedt.date()))
        self.assertTrue(IOccurrence.providedBy(item))
        self.assertTrue(IATEvent.providedBy(item.aq_parent))
Exemple #40
0
 def time_stamp(date_value):
     date = pydt(date_value)
     timestamp = {
         'day': format_datetime(date, 'dd', locale='de'),
         'day_name': format_datetime(date, 'EEEE', locale='de'),
         'month': date.strftime("%m"),
         'month_name': format_datetime(date, 'LLLL', locale='de'),
         'year': date.strftime("%Y"),
         'hour': date.strftime('%H'),
         'minute': date.strftime('%M'),
         'time': format_datetime(date, 'H:mm', locale='de'),
         'date': date,
         'date_short': format_datetime(date, format='short', locale='de'),
         'date_long': format_datetime(date, format='full', locale='de')
     }
     return timestamp
Exemple #41
0
    def notifications(self):
        dates = []
        rules = None

        # if assignee is asking for notifications look first if there are
        # customezed ones
        current = api.user.get_current().getId()
        annotations = self._setup_annotations()
        assignee = getattr(self.context, 'assignee', None)
        if assignee and current in assignee and \
                current in annotations[TASK_NOTIFICATIONS_KEY]:
            rules = annotations[TASK_NOTIFICATIONS_KEY][current]

        # in all other cases just return notifications
        else:
            rules = getattr(self.context, 'notifications', None)
            if not rules:
                taskplanner = self._get_taskplanner(self.context)
                if taskplanner:
                    rules = getattr(taskplanner, 'notifications', None)

        if rules:
            for rule in rules:
                if rule['field4'] == 'due':
                    field4 = self._get_due(
                        getattr(self.context, rule['field4']))
                else:
                    field4 = getattr(self.context, rule['field4'])

                if not field4:
                    continue

                field3 = self._get_value(rule['field3'], TIME_RELATIONS)[2]

                if safe_callable(field4):
                    field4 = field4()
                if isinstance(field4, DateTime):
                    field4 = pydt(field4)

                if field3 is None:
                    dates.append(field4)
                else:
                    field2 = self._get_value(rule['field2'], TIME_UNITS)[2]
                    field1 = int(rule['field1'])
                    dates.append(field4 + field2(field3 * field1))

        return dates
Exemple #42
0
    def json_config(self):
        events = []
        for brain in self.results():
            event = {'title': brain.Title, 'url': brain.getURL()}
            if brain.portal_type == 'Event':
                event.update({
                    'start': brain.start and format_date(brain.start),
                    'end': brain.end and format_date(brain.end)
                })

                if hasattr(brain,
                           'recurrence') and brain.recurrence is not None:
                    time_delta = brain.end - brain.start
                    recurring_events = recurrences(brain.start,
                                                   brain.recurrence)
                    for new_event in recurring_events:
                        if new_event != brain.start:  # skip the actual event
                            events.append({
                                'title':
                                brain.Title,
                                'url':
                                brain.getURL(),
                                'start':
                                format_date(new_event),
                                'end':
                                format_date(new_event + time_delta)
                            })

            else:
                event['start'] = format_date(brain.effective)
                if brain.expires and brain.expires.year() != 2499:
                    event['end'] = format_date(brain.expires)
                else:
                    event['end'] = format_date(
                        pydt(brain.effective) + timedelta(hours=1))
            events.append(event)

        return json.dumps({
            'header': {
                'left': 'prev,next today',
                'center': 'title',
                'right': 'month,agendaWeek,agendaDay'
            },
            'events': events
        })
    def __call__(self):
        request = self.context.REQUEST
        event_uid = request.get('event')
        if event_uid:
            event_uid = event_uid.split('UID_')[1]
        brains = self.context.portal_catalog(UID=event_uid)
        obj = brains[0].getObject()
        endDate = ends(obj)
        dayDelta, minuteDelta = float(request.get('dayDelta', 0)), float(request.get('minuteDelta', 0))
        endDate = endDate + dayDelta + minuteDelta / 1440.0

        if HAS_PAE and not hasattr(obj, 'setEndDate'):
            # duck-typed: dexterity-based plone.app.event type UTC datetime
            from plone.event.utils import pydt
            obj.end = pydt(endDate)  # endDate is already in UTC
        else:
            obj.setEndDate(endDate)
        obj.reindexObject()
        return True
    def __call__(self):
        request = self.context.REQUEST
        event_uid = request.get('event')
        if event_uid:
            event_uid = event_uid.split('UID_')[1]
        brains = self.context.portal_catalog(UID=event_uid)
        obj = brains[0].getObject()
        endDate = ends(obj)
        dayDelta, minuteDelta = float(request.get('dayDelta', 0)), float(
            request.get('minuteDelta', 0))
        endDate = endDate + dayDelta + minuteDelta / 1440.0

        if HAS_PAE and not hasattr(obj, 'setEndDate'):
            # duck-typed: dexterity-based plone.app.event type UTC datetime
            from plone.event.utils import pydt
            obj.end = pydt(endDate)  # endDate is already in UTC
        else:
            obj.setEndDate(endDate)
        obj.reindexObject()
        return True
Exemple #45
0
 def last_modified(self, value):
     tz = default_timezone(self.context, as_tzinfo=True)
     mod = DT(pydt(value, missing_zone=tz))
     setattr(self.context, 'modification_date', mod)
Exemple #46
0
 def test_pydt__wrong_type(self):
     from plone.event.utils import pydt
     self.assertEqual(pydt('wrongtype'), None)
Exemple #47
0
    def index_object(self, documentId, obj, threshold=None):
        """index an object, normalizing the indexed value to an integer

           o Normalized value has granularity of one minute.

           o Objects which have 'None' as indexed value are *omitted*,
             by design.

           o Repeat by recurdef - a RFC2445 reccurence definition string

        """
        returnStatus = 0

        try:
            date_attr = getattr(obj, self.id)
            if safe_callable(date_attr):
                date_attr = date_attr()
        except AttributeError:
            return returnStatus

        recurdef = getattr(obj, self.attr_recurdef, None)
        if safe_callable(recurdef):
            recurdef = recurdef()

        if not recurdef:
            dates = [pydt(date_attr)]
        else:
            until = getattr(obj, self.attr_until, None)
            if safe_callable(until):
                until = until()

            dates = recurrence_sequence_ical(date_attr,
                                             recrule=recurdef,
                                             until=until)

        newvalues = IISet(map(dt2int, dates))
        oldvalues = self._unindex.get(documentId, _marker)
        if oldvalues is not _marker:
            oldvalues = IISet(oldvalues)

        if oldvalues is not _marker and newvalues is not _marker\
            and not difference(newvalues, oldvalues)\
            and not difference(oldvalues, newvalues):
            # difference is calculated relative to first argument, so we have to
            # use it twice here
            return returnStatus

        if oldvalues is not _marker:
            for oldvalue in oldvalues:
                self.removeForwardIndexEntry(oldvalue, documentId)
            if newvalues is _marker:
                try:
                    del self._unindex[documentId]
                except ConflictError:
                    raise
                except:
                    LOG.error("Should not happen: oldvalues was there,"
                              " now it's not, for document with id %s" %
                              documentId)

        if newvalues is not _marker:
            inserted = False
            for value in newvalues:
                self.insertForwardIndexEntry(value, documentId)
                inserted = True
            if inserted:
                # store tuple values in reverse index entries for sorting
                self._unindex[documentId] = tuple(newvalues)
                returnStatus = 1

        return returnStatus
Exemple #48
0
    def test_import_from_ics(self):
        # Ical import unit test.
        self.portal.invokeFactory('Folder', 'impfolder1')
        impfolder = self.portal.impfolder1

        directory = os.path.dirname(__file__)
        icsfile = open(os.path.join(directory, 'icaltest.ics'), 'rb').read()
        res = ical_import(impfolder, icsfile, self.event_type)

        self.assertEqual(res['count'], 5)
        self.assertEqual(len(impfolder.contentIds()), 5)

        at = pytz.timezone('Europe/Vienna')
        utc = pytz.utc

        # Use pydt to normalize for DST times.

        # TODO: test for attendees. see note in
        # plone.app.event.ical.importer.ical_import
        e1 = IEventAccessor(impfolder.e1)
        self.assertEqual(e1.start, pydt(datetime(2013, 7, 19, 12, 0,
                                                 tzinfo=at)))
        self.assertEqual(e1.end, pydt(datetime(2013, 7, 20, 13, 0, tzinfo=at)))
        self.assertEqual(e1.description, 'A basic event with many properties.')
        self.assertEqual(e1.whole_day, False)
        self.assertEqual(e1.open_end, False)
        self.assertEqual(
            e1.sync_uid,
            u'48f1a7ad64e847568d860cd092344970',
        )

        e2 = IEventAccessor(impfolder.e2)
        self.assertEqual(e2.start, pydt(datetime(1996, 4, 1, 1, 0,
                                                 tzinfo=utc)))
        self.assertEqual(e2.end, pydt(datetime(1996, 4, 1, 2, 0, tzinfo=utc)))
        self.assertEqual(
            e2.recurrence,
            u'RRULE:FREQ=DAILY;COUNT=100\nEXDATE:19960402T010000Z,'
            u'19960403T010000Z,19960404T010000Z')

        e3 = IEventAccessor(impfolder.e3)
        self.assertEqual(e3.start, pydt(datetime(2012, 3, 27, 10, 0,
                                                 tzinfo=at)))
        self.assertEqual(e3.end, pydt(datetime(2012, 3, 27, 18, 0, tzinfo=at)))
        self.assertEqual(
            e3.recurrence,
            u'RRULE:FREQ=WEEKLY;UNTIL=20120703T080000Z;BYDAY=TU\n'
            u'EXDATE:20120529T100000,20120403T100000,20120410T100000,'
            u'20120501T100000,20120417T100000')

        e4 = IEventAccessor(impfolder.e4)
        self.assertEqual(e4.start, pydt(datetime(2013, 4, 4, 0, 0,
                                                 tzinfo=utc)))
        self.assertEqual(e4.end,
                         pydt(datetime(2013, 4, 4, 23, 59, 59, tzinfo=utc)))
        self.assertEqual(e4.whole_day, True)
        self.assertEqual(e4.open_end, False)

        e5 = IEventAccessor(impfolder.e5)
        self.assertEqual(e5.start, pydt(datetime(2013, 4, 2, 12, 0,
                                                 tzinfo=utc)))
        self.assertEqual(e5.end,
                         pydt(datetime(2013, 4, 2, 23, 59, 59, tzinfo=utc)))
        self.assertEqual(e5.whole_day, False)
        self.assertEqual(e5.open_end, True)
Exemple #49
0
    return find_context(context, iface=IPloneSiteRoot, as_url=as_url)


def find_navroot(context, as_url=False):
    return find_context(context, iface=INavigationRoot, as_url=as_url)


def find_event_listing(context, as_url=False):
    return find_context(context,
                        viewname='event_listing',
                        iface=ISite,
                        as_url=as_url,
                        append_view=True)


# Workaround for buggy strftime with timezone handling in DateTime.
# See: https://github.com/plone/plone.app.event/pull/47
# TODO: should land in CMFPlone or fixed in DateTime.
_strftime = lambda v, fmt: pydt(v).strftime(fmt)


class PatchedDateTime(DateTime):
    def strftime(self, fmt):
        return _strftime(self, fmt)


def ulocalized_time(time, *args, **kwargs):
    """Corrects for DateTime bugs doing wrong thing with timezones"""
    wrapped_time = PatchedDateTime(time)
    return orig_ulocalized_time(wrapped_time, *args, **kwargs)
 def end(self, value):
     value = pydt(value)
     self._behavior_map['end'](self.context).end = value
 def start(self, value):
     value = pydt(value)
     self._behavior_map['start'](self.context).start = value
Exemple #52
0
    def test_get_events(self):

        # whole range
        res = get_events(self.portal)
        self.assertEqual(len(res), 4)

        res = get_events(self.portal,
                         start=self.past,
                         end=self.future)
        self.assertEqual(len(res), 4)

        res = get_events(self.portal,
                         end=self.future)
        self.assertEqual(len(res), 4)

        res = get_events(self.portal,
                         start=self.past)
        self.assertEqual(len(res), 4)

        # Limit
        res = get_events(self.portal, limit=2)
        self.assertEqual(len(res), 2)

        # Return objects
        res = get_events(self.portal, ret_mode=RET_MODE_OBJECTS)
        self.assertTrue(IEvent.providedBy(res[0]))

        # Return IEventAccessor
        res = get_events(self.portal, ret_mode=RET_MODE_ACCESSORS)
        self.assertTrue(IEventAccessor.providedBy(res[0]))
        # Test sorting
        self.assertTrue(res[0].start < res[-1].start)

        # Test reversed sorting
        res = get_events(self.portal, ret_mode=RET_MODE_ACCESSORS,
                         sort_reverse=True)
        self.assertTrue(res[0].start > res[-1].start)

        # Test sort_on
        res = get_events(self.portal, ret_mode=RET_MODE_ACCESSORS,
                         sort="start")
        self.assertEqual(
            [it.title for it in res][2:],
            [u'Now Event', u'Future Event']
        )
        res = get_events(self.portal, ret_mode=RET_MODE_ACCESSORS, sort="end")
        self.assertEqual(
            [it.title for it in res],
            [u'Past Event', u'Now Event', u'Future Event', u'Long Event']
        )

        # Test expansion
        res = get_events(self.portal, ret_mode=RET_MODE_OBJECTS, expand=True)
        self.assertEqual(len(res), 8)

        res = get_events(self.portal, ret_mode=RET_MODE_ACCESSORS, expand=True)
        self.assertEqual(len(res), 8)
        # Test sorting
        self.assertTrue(res[0].start < res[-1].start)

        res = get_events(self.portal, ret_mode=RET_MODE_ACCESSORS,
                         expand=True, sort_reverse=True)
        # Test sorting
        self.assertTrue(res[0].start > res[-1].start)

        # only on now-date
        res = get_events(self.portal,
                         start=self.now,
                         end=self.now)
        self.assertEqual(len(res), 2)

        # only on now-date as date
        # NOTE: converting self.now to python datetime to allow testing also
        # with dates as Zope DateTime objects.
        res = get_events(self.portal,
                         start=pydt(self.now).date(),
                         end=pydt(self.now).date())
        self.assertEqual(len(res), 2)

        # only on past date
        res = get_events(self.portal,
                         start=self.past,
                         end=self.past)
        self.assertEqual(len(res), 2)

        # one recurrence occurrence in far future
        res = get_events(self.portal,
                         start=self.far,
                         end=self.far)
        self.assertEqual(len(res), 1)

        # from now on
        res = get_events(self.portal,
                         start=self.now)
        self.assertEqual(len(res), 3)

        # until now
        res = get_events(self.portal,
                         end=self.now)
        self.assertEqual(len(res), 3)

        # in subfolder
        path = '/'.join(self.portal.sub.getPhysicalPath())
        res = get_events(self.portal, path=path)
        self.assertEqual(len(res), 1)
Exemple #53
0
    def post_creation(self,
                      obj,
                      pdb_if_exception=False,
                      post_creation_data=None):
        if obj is None:
            return
        field_data = self.field_data
        bdata = ILayoutAware(obj, None)
        if bdata:
            try:
                bdata.contentLayout = self.layout
            except Exception:
                bdata.contentLayout = '++contentlayout++default/document.html'
        bdata = IRichText(obj, None)
        if bdata:
            try:
                bdata.text = RichTextValue(field_data['text'], 'text/html',
                                           'text/html')
            except Exception:
                try:
                    bdata.text = RichTextValue(
                        field_data[
                            'plone.app.contenttypes.behaviors.richtext.IRichText']
                        ['text'],  # noqa
                        'text/html',
                        'text/html').raw
                except Exception:
                    bdata.text = ''

        bdata = IBasic(obj, None)
        if bdata:
            try:
                bdata.title = field_data['title']
            except Exception:
                try:
                    bdata.title = field_data[
                        'plone.app.content.interfaces.INameFromTitle']['title']
                except Exception:
                    bdata.description = field_data[dublin]['title']
            try:
                bdata.description = field_data['description']
            except Exception:
                try:
                    bdata.description = field_data[dublin]['description']
                except Exception:
                    bdata.description = field_data[basic]['description']
        else:
            try:
                obj.title = field_data['title']
                obj.description = field_data['description']
            except Exception:
                obj.title = field_data[dublin]['title']
                obj.description = field_data[dublin]['description']

        bdata = ICategorization(obj, None)
        if bdata:
            try:
                bdata.subjects = field_data['subject']
            except Exception:
                try:
                    bdata.subjects = self.field_data[dublin]['subjects']
                except Exception:
                    try:
                        bdata.subjects = self.field_data[categorization][
                            'subjects']
                    except Exception:
                        pass  # no keywords found

            bdata = IPublication(obj)
            try:
                if field_data['effectiveDate']:
                    bdata.effective = pydt(field_data['effectiveDate'])
            except Exception:
                try:
                    if field_data[dublin]['effective']:
                        bdata.effective = pydt(field_data[dublin]['effective'])
                except Exception:
                    try:
                        if field_data[publication]['effective']:
                            bdata.effective = pydt(
                                field_data[publication]['effective'])
                    except Exception:
                        bdata.effective = None

        ldata = ILocation(obj, None)
        if ldata:
            if field_data.get('location'):
                ldata.locations = [field_data['location']]

            if field_data.get('newsLocation'):
                if ldata.locations:
                    ldata.locations.append(field_data['newsLocation'])
                else:
                    ldata.locations = [field_data['newsLocation']]

        try:
            obj.modification_date = field_data['modification_date']
        except Exception:
            try:
                obj.modification_date = obj.modified()
            except Exception:
                obj.modification_date = None
        try:
            obj.creation_date = field_data['creation_date']
        except Exception:
            try:
                obj.creation_date = obj.created()
            except Exception:
                obj.creation_date = None

        bdata = IDublinCore(obj, None)
        if bdata:
            if IDublinCore.__identifier__ in field_data:
                dublin_core = field_data[IDublinCore.__identifier__]
                bdata.expires = dublin_core['expires']
                bdata.rights = dublin_core['rights']
                bdata.creators = tuple(dublin_core['creators'])
                bdata.language = dublin_core['language']
                bdata.effective = pydt(dublin_core['effective'])
                bdata.subjects = dublin_core['subjects']
                bdata.contributors = tuple(dublin_core['contributors'])
            else:
                bdata.expires = pydt(field_data.get('expirationDate'))
                bdata.rights = field_data.get('rights')
                creators = field_data.get('creators')
                bdata.creators = tuple(creators) if creators else ()
                language = field_data.get('language')
                bdata.language = language if language is not None else ""
                bdata.effective = pydt(field_data.get('effectiveDate'))
                bdata.subjects = field_data.get('subject')
                contributors = field_data.get('contributors')
                bdata.contributors = tuple(contributors) if contributors else (
                )

        bdata = ILayoutAware(obj, None)
        if bdata:
            if self.data['portal_type'] == 'Folder' and (
                    self.field_data.get('text') or '').strip():
                bdata.content = FOLDER_DEFAULT_PAGE_LAYOUT % self.field_data[
                    'text']
                # need to explicitly reset contentLayout value because this data
                # could be overwritten
                bdata.contentLayout = None
            elif self.layout:
                if layoutaware in field_data and 'contentLayout' in field_data[
                        layoutaware]:
                    bdata.contentLayout = field_data[layoutaware][
                        'contentLayout']
                if layoutaware in field_data and 'content' in field_data[
                        layoutaware]:
                    bdata.content = field_data[
                        'plone.app.blocks.layoutbehavior.ILayoutAware'][
                            'content']
                if 'rendered_layout' in self.data['data']:
                    bdata.rendered_layout = self.data['data'][
                        'rendered_layout']

        inv_field_mapping = {v: k for k, v in self.fields_mapping.iteritems()}
        for IBehavior, field_name in self.behavior_data_mappers:

            original_field_name = inv_field_mapping.get(field_name, field_name)

            if original_field_name not in self.field_data:
                # data not here...
                continue

            behavior = IBehavior(obj, None)
            if behavior is None:
                # behavior not valid for obj type
                continue

            val = self.field_data[original_field_name]

            if field_name in self.data_converters:
                val = self.data_converters[field_name](val)

            setattr(behavior, field_name, val)

        # handle lead images
        for field_name in self.lead_image_field_names:
            if self.field_data.get(field_name):
                if field_name == 'plone.app.contenttypes.behaviors.leadimage.ILeadImage':
                    im_obj = self.field_data.get(field_name)['image']
                else:
                    im_obj = self.field_data.get(field_name)
                if hasattr(im_obj, 'read'):
                    im_data = im_obj.read()
                else:
                    im_data = im_obj

                if not im_data:
                    continue

                filename = self.field_data.get('image_filename')
                if not filename:
                    if hasattr(im_obj, 'filename'):
                        filename = im_obj.filename
                    else:
                        filename = self.field_data['id']
                obj.image = im_data

                if not isinstance(obj.image, NamedBlobImage):
                    is_stringio = isinstance(im_obj, StringIO)
                    if is_stringio:
                        namedblobimage_data = im_data
                    elif isinstance(im_obj, Image):
                        namedblobimage_data = im_data.data
                    else:
                        if pdb_if_exception:
                            pdb.set_trace()
                        logger.info("    lead image is type %s" % type(im_obj))
                    obj.image = NamedBlobImage(data=namedblobimage_data,
                                               contentType='',
                                               filename=filename)

                if hasattr(obj.image, 'contentType') and isinstance(
                        obj.image.contentType, unicode):
                    obj.image.contentType = obj.image.contentType.encode(
                        'ascii')
                else:
                    if isinstance(im_obj, Image):
                        data = im_obj.data
                    elif hasattr(im_obj, 'buf'):
                        data = im_obj.buf
                    elif hasattr(im_obj, '_blob'):
                        if hasattr(im_obj._blob, '_p_blob_uncommitted'):
                            f = open(im_obj._blob._p_blob_uncommitted, 'r')
                            data = f.read()
                            f.close()
                        else:
                            raise Exception(
                                "no _p_blob_uncommitted attr in im_obj._blob")
                    else:
                        raise Exception("no _blob attr in im_obj")

                    if data == '' or data is None:
                        data = base64.b64decode(
                            'R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=='
                        )

                    image_type = what('', h=data)
                    if image_type in [
                            'png', 'bmp', 'jpeg', 'xbm', 'tiff', 'gif'
                    ]:
                        obj.image.contentType = 'image/%s' % image_type
                    elif image_type == 'rast':
                        obj.image.contentType = 'image/cmu-raster'
                    elif image_type == 'ppm':
                        obj.image.contentType = 'image/x-portable-pixmap'
                    elif image_type == 'pgm':
                        obj.image.contentType = 'image/x-portable-greymap'
                    elif image_type == 'pbm':
                        obj.image.contentType = 'image/x-portable-bitmap'
                    elif image_type == 'rgb':
                        obj.image.contentType = 'image/x-rgb'
                    else:
                        # look at filename extension
                        contentType, encoding = guess_type(obj.image.filename,
                                                           strict=False)
                        if contentType:
                            obj.image.contentType = contentType
                        else:
                            logger.info(
                                "Unknown image type {};"
                                " defaulting to jpeg".format(image_type))
                            pdb.set_trace()
                            obj.image.contentType = 'image/jpeg'  # default
                for caption_field_name in self.lead_image_caption_field_names:
                    if caption_field_name in self.field_data:
                        obj.imageCaption = self.field_data.get(
                            caption_field_name)
Exemple #54
0
def DateTime_to_datetime(val):
    if hasattr(val, 'asdatetime'):
        return pydt(val)
    return val
Exemple #55
0
def recurrence_sequence_ical(
        start,
        recrule=None,
        from_=None,
        until=None,
        count=None,
        duration=None,
):
    """Calculates a sequence of datetime objects from a recurrence rule
    following the RFC2445 specification, using python-dateutil recurrence
    rules.  The resolution of the resulting datetime objects is one second,
    since python-dateutil rrulestr doesn't support microseconds.

    :param start:   datetime or DateTime instance of the date from which the
                    recurrence sequence is calculated.
    :type start: datetime.datetime

    :param recrule: Optional string with RFC2445 compatible recurrence
                    definition, dateutil.rrule or dateutil.rruleset instances.
    :type recrule: string

    :param from_:   Optional datetime or DateTime instance of the date, to
                    limit the result within a timespan.
    :type from_: datetime.datetime

    :param until:   Optional datetime or DateTime instance of the date, until
                    the recurrence is calculated. If not given, count or
                    MAXDATE limit the recurrence calculation.
    :type until: datetime.datetime

    :param count:   Optional integer which defines the number of occurences.
                    If not given, until or MAXDATE limits the recurrence
                    calculation.
    :type count: integer

    :param duration: Optional timedelta instance, which is used to calculate
                     if a occurence datetime plus duration is within the
                     queried timerange.
    :type duration:  datetime.timedelta

    :returns: A generator which generates a sequence of datetime instances.
    :rtype: generator

    """
    # Always use python datetime objects and remove the microseconds
    start = pydt(start, exact=False)
    from_ = pydt(from_, exact=False)
    until = pydt(until, exact=False)
    tz = start.tzinfo
    start = tzdel(start)  # tznaive | start defines tz
    _from = tzdel(from_)
    _until = tzdel(until)
    if duration:
        assert (isinstance(duration, datetime.timedelta))
    else:
        duration = datetime.timedelta(0)

    if recrule:
        # TODO BUGFIX WRONG TIME DEFINITIONS
        # THIS HACK ensures, that UNTIL, RDATE and EXDATE definitions with
        # incorrect time (currently always set to 0:00 by the recurrence
        # widget) are handled correctly.
        #
        # Following fixes are made:
        # - The UNTIL date should be included in the recurrence set, as defined
        #   by RFC5545 (fix sets it to the end of the day)
        # - RDATE definitions should have the same time as the start date.
        # - EXDATE definitions should exclude occurrences on the specific date
        #   only the same time as the start date.
        # In the long term ,the recurrence widget should be able to set the
        # time for UNTIL, RDATE and EXDATE.
        t0 = start.time()  # set initial time information.
        # First, replace all times in the recurring rule with starttime
        t0str = 'T{0:02d}{1:02d}{2:02d}'.format(t0.hour, t0.minute, t0.second)
        # Replace any times set to 000000 with start time, not all
        # rrules are set by a specific broken widget.  Don't waste time
        # subbing if the start time is already 000000.
        if t0str != 'T000000':
            recrule = re.sub(r'T000000', t0str, recrule)
        # Then, replace incorrect until times with the end of the day
        recrule = re.sub(
            r'(UNTIL[^T]*[0-9]{8})T(000000)',
            r'\1T235959',
            recrule,
        )

        # RFC2445 string
        # forceset: always return a rruleset
        # dtstart: optional used when no dtstart is in RFC2445 string
        #          dtstart is given as timezone naive time. timezones are
        #          applied afterwards, since rrulestr doesn't normalize
        #          timezones over DST boundaries
        rset = rrule.rrulestr(
            recrule,
            dtstart=start,
            forceset=True,
            ignoretz=True,
            # compatible=True # RFC2445 compatibility
        )
    else:
        rset = rrule.rruleset()
    rset.rdate(start)  # RCF2445: always include start date

    # limit
    if _from and _until:
        # between doesn't add a ruleset but returns a list
        rset = rset.between(_from - duration, _until, inc=True)
    for cnt, date in enumerate(rset):
        # Localize tznaive dates from rrulestr sequence
        date = tz.localize(date)

        # Limit number of recurrences otherwise calculations take too long
        if MAXCOUNT and cnt + 1 > MAXCOUNT:
            break
        if count and cnt + 1 > count:
            break
        if from_ and utc(date) + duration < utc(from_):
            continue
        if until and utc(date) > utc(until):
            break

        yield date
    return
Exemple #56
0
    def to_ical(self):

        ical = icalendar.Event()

        event = self.event

        # TODO: event.text

        # must be in utc
        ical.add('dtstamp', utc(pydt(datetime.now())))
        ical.add('created', utc(pydt(event.created)))
        ical.add('last-modified', utc(pydt(event.last_modified)))

        ical.add('uid', event.uid)
        ical.add('url', event.url)

        ical.add('summary', event.title)

        if event.description: ical.add('description', event.description)

        if event.whole_day:
            ical.add('dtstart', event.start.date())
            # RFC5545, 3.6.1
            # For cases where a "VEVENT" calendar component
            # specifies a "DTSTART" property with a DATE value type but no
            # "DTEND" nor "DURATION" property, the event's duration is taken to
            # be one day.
            #
            # RFC5545 doesn't define clearly, if all-day events should have
            # a end date on the same date or one day after the start day at
            # 0:00. Most icalendar libraries use the latter method.
            # Internally, whole_day events end on the same day one second
            # before midnight. Using the RFC5545 preferred method for
            # plone.app.event seems not appropriate, since we would have to fix
            # the date to end a day before for displaying.
            # For exporting, we let whole_day events end on the next day at
            # midnight.
            # See:
            # http://stackoverflow.com/questions/1716237/single-day-all-day-appointments-in-ics-files
            # http://icalevents.com/1778-all-day-events-adding-a-day-or-not/
            # http://www.innerjoin.org/iCalendar/all-day-events.html
            ical.add('dtend', event.end.date() + timedelta(days=1))
        elif event.open_end:
            # RFC5545, 3.6.1
            # For cases where a "VEVENT" calendar component
            # specifies a "DTSTART" property with a DATE-TIME value type but no
            # "DTEND" property, the event ends on the same calendar date and
            # time of day specified by the "DTSTART" property.
            ical.add('dtstart', event.start)
        else:
            ical.add('dtstart', event.start)
            ical.add('dtend', event.end)

        if event.recurrence:
            for recdef in event.recurrence.split():
                prop, val = recdef.split(':')
                if prop == 'RRULE':
                    ical.add(prop, icalendar.prop.vRecur.from_ical(val))
                elif prop in ('EXDATE', 'RDATE'):
                    factory = icalendar.prop.vDDDLists

                    # localize ex/rdate
                    # TODO: should better already be localized by event object
                    tzid = event.timezone
                    # get list of datetime values from ical string
                    try:
                        dtlist = factory.from_ical(val, timezone=tzid)
                    except ValueError:
                        # TODO: caused by a bug in plone.formwidget.recurrence,
                        # where the recurrencewidget or plone.event fails with
                        # COUNT=1 and a extra RDATE.
                        # TODO: REMOVE this workaround, once this failure is
                        # fixed in recurrence widget.
                        continue
                    ical.add(prop, dtlist)

        if event.location: ical.add('location', event.location)

        # TODO: revisit and implement attendee export according to RFC
        if event.attendees:
            for attendee in event.attendees:
                att = icalendar.prop.vCalAddress(attendee)
                att.params['cn'] = icalendar.prop.vText(attendee)
                att.params['ROLE'] = icalendar.prop.vText('REQ-PARTICIPANT')
                ical.add('attendee', att)

        cn = []
        if event.contact_name:
            cn.append(event.contact_name)
        if event.contact_phone:
            cn.append(event.contact_phone)
        if event.contact_email:
            cn.append(event.contact_email)
        if event.event_url:
            cn.append(event.event_url)
        if cn:
            ical.add('contact', u', '.join(cn))

        if event.subjects:
            for subject in event.subjects:
                ical.add('categories', subject)

        return ical