1
0
mirror of https://github.com/dkmstr/openuds.git synced 2025-01-26 10:03:50 +03:00

Added get next event from a given date to calendar

This commit is contained in:
Adolfo Gómez García 2016-03-10 11:46:22 +01:00
parent ff622bb9cd
commit 135392d245

View File

@ -30,7 +30,7 @@
'''
.. moduleauthor:: Adolfo Gómez, dkmaster at dkmon dot com
'''
# pylint: disable=maybe-no-member
from __future__ import unicode_literals
from uds.models.Util import NEVER
@ -45,17 +45,14 @@ import six
import bitarray
import logging
__updated__ = '2016-02-17'
__updated__ = '2016-03-10'
logger = logging.getLogger(__name__)
class CalendarChecker(object):
data = None
data_time = None
calendar = None
inverse = False
# For performance checking
updates = 0
@ -64,33 +61,20 @@ class CalendarChecker(object):
cache = Cache('calChecker')
def __init__(self, calendar, inverse=False):
def __init__(self, calendar):
self.calendar = calendar
self.calendar_modified = None
self.inverse = inverse
self.data = None
self.data_time = None
def _updateData(self, dtime):
# Else, update the array
CalendarChecker.updates += 1
self.calendar_modified = self.calendar.modified
self.data_time = dtime.date()
# First, try to get data from cache if it is valid
cacheKey = six.text_type(self.calendar.modified.toordinal()) + six.text_type(self.data_time.toordinal()) + self.calendar.uuid
cached = CalendarChecker.cache.get(cacheKey, None)
if cached is not None:
self.data = bitarray.bitarray() # Empty bitarray
self.data.frombytes(cached)
CalendarChecker.cache_hit += 1
return
data = bitarray.bitarray(60 * 24) # Granurality is minute
data.setall(False)
self.data = bitarray.bitarray(60 * 24) # Granurality is minute
self.data.setall(False)
data_date = dtime.date()
start = datetime.datetime.combine(self.data_time, datetime.datetime.min.time())
end = datetime.datetime.combine(self.data_time, datetime.datetime.max.time())
start = datetime.datetime.combine(data_date, datetime.datetime.min.time())
end = datetime.datetime.combine(data_date, datetime.datetime.max.time())
for rule in self.calendar.rules.all():
rr = rule.as_rrule()
@ -109,7 +93,7 @@ class CalendarChecker(object):
_end = end if r_end is None or end < r_end else r_end
for val in rr.between(_start, _end, inc=True):
if val.date() != self.data_time:
if val.date() != data_date:
diff = int((start - val).total_seconds() / 60)
pos = 0
posdur = ruleDurationMinutes - diff
@ -120,11 +104,22 @@ class CalendarChecker(object):
posdur = pos + ruleDurationMinutes
if posdur > 60 * 24:
posdur = 60 * 24
self.data[pos:posdur] = True
data[pos:posdur] = True
# Now self.data can be accessed as an array of booleans.
# Store data on persistent cache
CalendarChecker.cache.put(cacheKey, self.data.tobytes(), 3600 * 24)
return data
def _updateEvents(self, checkFrom):
next_event = None
for rule in self.calendar.rules.all():
event = rule.as_rrule().after(checkFrom)
duration = rule.duration_as_minutes
if next_event is None or self.next_event[0] > event:
next_event = (event, datetime.timedelta(minutes=duration))
return next_event
def check(self, dtime=None):
'''
@ -133,18 +128,45 @@ class CalendarChecker(object):
TODO: We can improve performance of this by getting from a cache first if we can
'''
if dtime is None:
dtime = datetime.datetime.now()
if self.calendar_modified != self.calendar.modified or self.data is None or self.data_time != dtime.date():
self._updateData(dtime)
dtime = getSqlDatetime()
# First, try to get data from cache if it is valid
cacheKey = six.text_type(self.calendar.modified.toordinal()) + six.text_type(dtime.date().toordinal()) + self.calendar.uuid + 'checker'
cached = CalendarChecker.cache.get(cacheKey, None)
if cached is not None:
data = bitarray.bitarray() # Empty bitarray
data.frombytes(cached)
CalendarChecker.cache_hit += 1
else:
data = self._updateData(dtime)
# Now data can be accessed as an array of booleans.
# Store data on persistent cache
CalendarChecker.cache.put(cacheKey, data.tobytes(), 3600 * 24)
return data[dtime.hour * 60 + dtime.minute]
def nextEvent(self, checkFrom=None):
'''
Returns next event for this interval
Returns a list of two elements. First is datetime of event begining, second is timedelta of duration
'''
if checkFrom is None:
checkFrom = getSqlDatetime()
cacheKey = six.text_type(self.calendar.modified.toordinal()) + self.calendar.uuid + six.text_type(checkFrom.toordinal()) + 'event'
next_event = CalendarChecker.cache.get(cacheKey, None)
if next_event is None:
next_event = self._updateEvents(checkFrom)
CalendarChecker.cache.put(cacheKey, next_event, 3600)
else:
CalendarChecker.hits += 1
return self.data[dtime.hour * 60 + dtime.minute]
return next_event
def debug(self):
if self.data is None:
self.check()
return '\n'.join([
'{1}:{2} is {0}'.format(self.data[i], i / 60, i % 60) for i in range(60 * 24)
])
return "Calendar checker for {}".format(self.calendar)