# HG changeset patch # User Paul Boddie # Date 1428331192 -7200 # Node ID edc4e54a5dbf0e787198fe6b41fe8f170f3d8986 # Parent b59babfd290d767f1fb5ca04eb23782621cde2e0 Moved various date control value-handling methods into a separate module. diff -r b59babfd290d -r edc4e54a5dbf imipweb/data.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/imipweb/data.py Mon Apr 06 16:39:52 2015 +0200 @@ -0,0 +1,112 @@ +#!/usr/bin/env python + +""" +Web interface data abstractions. + +Copyright (C) 2014, 2015 Paul Boddie + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free Software +Foundation; either version 3 of the License, or (at your option) any later +version. + +This program is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see . +""" + +from datetime import datetime, timedelta +from imiptools.dates import get_datetime, get_start_of_day +from imiptools.period import Period + +class EventPeriod(Period): + + "A simple period plus attribute details, compatible with RecurringPeriod." + + def __init__(self, start, end, start_attr=None, end_attr=None): + Period.__init__(self, start, end) + self.start_attr = start_attr + self.end_attr = end_attr + + def as_tuple(self): + return self.start, self.end, self.start_attr, self.end_attr + + def __repr__(self): + return "EventPeriod(%r, %r, %r, %r)" % self.as_tuple() + +def handle_date_control_values(values, with_time=True): + + """ + Handle date control information for the given 'values', returning a + (datetime, attr) tuple, or None if the fields cannot be used to + construct a datetime object. + """ + + if not values or not values["date"]: + return None + elif with_time: + value = "%s%s" % (values["date"], values["time"]) + attr = {"TZID" : values["tzid"], "VALUE" : "DATE-TIME"} + dt = get_datetime(value, attr) + else: + attr = {"VALUE" : "DATE"} + dt = get_datetime(values["date"]) + + if dt: + return dt, attr + + return None + +def handle_period_controls(start_values, end_values, dtend_enabled, dttimes_enabled, index=None): + + """ + Handle datetime controls for a particular period, described by the given + 'start_values' and 'end_values', with 'dtend_enabled' and + 'dttimes_enabled' affecting the usage of the provided values. + + If 'index' is specified, incorporate it into any error indicator. + """ + + t = handle_date_control_values(start_values, dttimes_enabled) + if t: + dtstart, dtstart_attr = t + else: + return None, [index is not None and ("dtstart", index) or "dtstart"] + + # Handle specified end datetimes. + + if dtend_enabled: + t = handle_date_control_values(end_values, dttimes_enabled) + if t: + dtend, dtend_attr = t + + # Convert end dates to iCalendar "next day" dates. + + if not isinstance(dtend, datetime): + dtend += timedelta(1) + else: + return None, [index is not None and ("dtend", index) or "dtend"] + + # Otherwise, treat the end date as the start date. Datetimes are + # handled by making the event occupy the rest of the day. + + else: + dtend = dtstart + timedelta(1) + dtend_attr = dtstart_attr + + if isinstance(dtstart, datetime): + dtend = get_start_of_day(dtend, attr["TZID"]) + + if dtstart > dtend: + return None, [ + index is not None and ("dtstart", index) or "dtstart", + index is not None and ("dtend", index) or "dtend" + ] + + return EventPeriod(dtstart, dtend, dtstart_attr, dtend_attr), None + +# vim: tabstop=4 expandtab shiftwidth=4 diff -r b59babfd290d -r edc4e54a5dbf imipweb/event.py --- a/imipweb/event.py Mon Apr 06 16:10:01 2015 +0200 +++ b/imipweb/event.py Mon Apr 06 16:39:52 2015 +0200 @@ -24,28 +24,15 @@ from imiptools.data import get_uri, uri_dict, uri_values from imiptools.dates import format_datetime, to_date, get_datetime, \ get_datetime_item, get_period_item, \ - get_start_of_day, to_timezone + to_timezone from imiptools.mail import Messenger -from imiptools.period import have_conflict, Period +from imiptools.period import have_conflict +from imipweb.data import EventPeriod, handle_date_control_values, \ + handle_period_controls from imipweb.handler import ManagerHandler from imipweb.resource import Resource import pytz -class EventPeriod(Period): - - "A simple period plus attribute details, compatible with RecurringPeriod." - - def __init__(self, start, end, start_attr=None, end_attr=None): - Period.__init__(self, start, end) - self.start_attr = start_attr - self.end_attr = end_attr - - def as_tuple(self): - return self.start, self.end, self.start_attr, self.end_attr - - def __repr__(self): - return "EventPeriod(%r, %r, %r, %r)" % self.as_tuple() - class EventPage(Resource): "A request handler for the event page." @@ -204,7 +191,7 @@ start_values = self.get_date_control_values("dtstart") end_values = self.get_date_control_values("dtend") - period, errors = self.handle_period_controls(start_values, end_values, dtend_enabled, dttimes_enabled) + period, errors = handle_period_controls(start_values, end_values, dtend_enabled, dttimes_enabled) if errors: return None, errors @@ -230,84 +217,13 @@ dtend_enabled = str(index) in all_dtend_enabled dttimes_enabled = str(index) in all_dttimes_enabled - period, _errors = self.handle_period_controls(start_values, end_values, dtend_enabled, dttimes_enabled, index) + period, _errors = handle_period_controls(start_values, end_values, dtend_enabled, dttimes_enabled, index) periods.append(period) errors += _errors return periods, errors - def handle_period_controls(self, start_values, end_values, dtend_enabled, dttimes_enabled, index=None): - - """ - Handle datetime controls for a particular period, described by the given - 'start_values' and 'end_values', with 'dtend_enabled' and - 'dttimes_enabled' affecting the usage of the provided values. - - If 'index' is specified, incorporate it into any error indicator. - """ - - t = self.handle_date_control_values(start_values, dttimes_enabled) - if t: - dtstart, dtstart_attr = t - else: - return None, [index is not None and ("dtstart", index) or "dtstart"] - - # Handle specified end datetimes. - - if dtend_enabled: - t = self.handle_date_control_values(end_values, dttimes_enabled) - if t: - dtend, dtend_attr = t - - # Convert end dates to iCalendar "next day" dates. - - if not isinstance(dtend, datetime): - dtend += timedelta(1) - else: - return None, [index is not None and ("dtend", index) or "dtend"] - - # Otherwise, treat the end date as the start date. Datetimes are - # handled by making the event occupy the rest of the day. - - else: - dtend = dtstart + timedelta(1) - dtend_attr = dtstart_attr - - if isinstance(dtstart, datetime): - dtend = get_start_of_day(dtend, attr["TZID"]) - - if dtstart > dtend: - return None, [ - index is not None and ("dtstart", index) or "dtstart", - index is not None and ("dtend", index) or "dtend" - ] - - return EventPeriod(dtstart, dtend, dtstart_attr, dtend_attr), None - - def handle_date_control_values(self, values, with_time=True): - - """ - Handle date control information for the given 'values', returning a - (datetime, attr) tuple, or None if the fields cannot be used to - construct a datetime object. - """ - - if not values or not values["date"]: - return None - elif with_time: - value = "%s%s" % (values["date"], values["time"]) - attr = {"TZID" : values["tzid"], "VALUE" : "DATE-TIME"} - dt = get_datetime(value, attr) - else: - attr = {"VALUE" : "DATE"} - dt = get_datetime(values["date"]) - - if dt: - return dt, attr - - return None - def get_date_control_values(self, name, multiple=False, tzid_name=None): """ @@ -338,17 +254,18 @@ # Construct a usable dictionary of values. - time = (hour or minute or second) and \ - "T%s%s%s" % ( - (hour or "").rjust(2, "0")[:2], - (minute or "").rjust(2, "0")[:2], - (second or "").rjust(2, "0")[:2] - ) or "" + if hour or minute or second: + hour = (hour or "").rjust(2, "0")[:2] + minute = (minute or "").rjust(2, "0")[:2] + second = (second or "").rjust(2, "0")[:2] + time = "T%s%s%s" % (hour, minute, second) + else: + hour = minute = second = time = "" value = { - "date" : date, - "time" : time, - "tzid" : tzid or self.get_tzid() + "date" : date, "time" : time, + "tzid" : tzid or self.get_tzid(), + "hour" : hour, "minute" : minute, "second" : second } # Return a single value or append to a collection of all values.