1 #!/usr/bin/env python 2 3 """ 4 Web interface data abstractions. 5 6 Copyright (C) 2014, 2015 Paul Boddie <paul@boddie.org.uk> 7 8 This program is free software; you can redistribute it and/or modify it under 9 the terms of the GNU General Public License as published by the Free Software 10 Foundation; either version 3 of the License, or (at your option) any later 11 version. 12 13 This program is distributed in the hope that it will be useful, but WITHOUT 14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 15 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 16 details. 17 18 You should have received a copy of the GNU General Public License along with 19 this program. If not, see <http://www.gnu.org/licenses/>. 20 """ 21 22 from datetime import datetime, timedelta 23 from imiptools.dates import get_datetime, get_start_of_day 24 from imiptools.period import Period 25 26 class EventPeriod(Period): 27 28 "A simple period plus attribute details, compatible with RecurringPeriod." 29 30 def __init__(self, start, end, start_attr=None, end_attr=None): 31 Period.__init__(self, start, end) 32 self.start_attr = start_attr 33 self.end_attr = end_attr 34 35 def as_tuple(self): 36 return self.start, self.end, self.start_attr, self.end_attr 37 38 def __repr__(self): 39 return "EventPeriod(%r, %r, %r, %r)" % self.as_tuple() 40 41 def handle_date_control_values(values, with_time=True): 42 43 """ 44 Handle date control information for the given 'values', returning a 45 (datetime, attr) tuple, or None if the fields cannot be used to 46 construct a datetime object. 47 """ 48 49 if not values or not values["date"]: 50 return None 51 elif with_time: 52 value = "%s%s" % (values["date"], values["time"]) 53 attr = {"TZID" : values["tzid"], "VALUE" : "DATE-TIME"} 54 dt = get_datetime(value, attr) 55 else: 56 attr = {"VALUE" : "DATE"} 57 dt = get_datetime(values["date"]) 58 59 if dt: 60 return dt, attr 61 62 return None 63 64 def handle_period_controls(start_values, end_values, dtend_enabled, dttimes_enabled, index=None): 65 66 """ 67 Handle datetime controls for a particular period, described by the given 68 'start_values' and 'end_values', with 'dtend_enabled' and 69 'dttimes_enabled' affecting the usage of the provided values. 70 71 If 'index' is specified, incorporate it into any error indicator. 72 """ 73 74 t = handle_date_control_values(start_values, dttimes_enabled) 75 if t: 76 dtstart, dtstart_attr = t 77 else: 78 return None, [index is not None and ("dtstart", index) or "dtstart"] 79 80 # Handle specified end datetimes. 81 82 if dtend_enabled: 83 t = handle_date_control_values(end_values, dttimes_enabled) 84 if t: 85 dtend, dtend_attr = t 86 87 # Convert end dates to iCalendar "next day" dates. 88 89 if not isinstance(dtend, datetime): 90 dtend += timedelta(1) 91 else: 92 return None, [index is not None and ("dtend", index) or "dtend"] 93 94 # Otherwise, treat the end date as the start date. Datetimes are 95 # handled by making the event occupy the rest of the day. 96 97 else: 98 dtend = dtstart + timedelta(1) 99 dtend_attr = dtstart_attr 100 101 if isinstance(dtstart, datetime): 102 dtend = get_start_of_day(dtend, attr["TZID"]) 103 104 if dtstart > dtend: 105 return None, [ 106 index is not None and ("dtstart", index) or "dtstart", 107 index is not None and ("dtend", index) or "dtend" 108 ] 109 110 return EventPeriod(dtstart, dtend, dtstart_attr, dtend_attr), None 111 112 # vim: tabstop=4 expandtab shiftwidth=4