Package flumotion :: Package component :: Package bouncers :: Package algorithms :: Module icalbouncer
[hide private]

Source Code for Module flumotion.component.bouncers.algorithms.icalbouncer

  1  # -*- Mode: Python;  test-case-name: flumotion.test.test_icalbouncer -*- 
  2  # vi:si:et:sw=4:sts=4:ts=4 
  3   
  4  # Flumotion - a streaming media server 
  5  # Copyright (C) 2004,2005,2006,2007,2008,2009 Fluendo, S.L. 
  6  # Copyright (C) 2010,2011 Flumotion Services, S.A. 
  7  # All rights reserved. 
  8  # 
  9  # This file may be distributed and/or modified under the terms of 
 10  # the GNU Lesser General Public License version 2.1 as published by 
 11  # the Free Software Foundation. 
 12  # This file is distributed without any warranty; without even the implied 
 13  # warranty of merchantability or fitness for a particular purpose. 
 14  # See "LICENSE.LGPL" in the source distribution for more information. 
 15  # 
 16  # Headers in this file shall remain intact. 
 17   
 18  """ 
 19  A bouncer that only lets in during an event scheduled with an ical file. 
 20  """ 
 21   
 22  from datetime import datetime, timedelta 
 23   
 24  from twisted.internet import defer 
 25   
 26  from flumotion.common import keycards, messages, errors 
 27  from flumotion.common import log, documentation 
 28  from flumotion.common import eventcalendar, tz 
 29  from flumotion.common.i18n import N_, gettexter 
 30  from flumotion.component.base import scheduler 
 31  from flumotion.component.bouncers.algorithms import base 
 32   
 33  __all__ = ['IcalBouncerAlgorithm'] 
 34  __version__ = "$Rev$" 
 35  T_ = gettexter() 
 36   
 37   
38 -class IcalBouncerAlgorithm(base.BouncerAlgorithm):
39 40 logCategory = 'icalbouncer' 41 events = [] 42 maxKeyCardDuration = timedelta(days=1) 43
44 - def get_namespace(self):
45 return 'icalbouncer'
46
47 - def start(self, component):
48 self.props = self.args['properties'] 49 self.iCalScheduler = None 50 self.subscriptionToken = None 51 self.check_properties(component) 52 self.setup(component)
53
54 - def check_properties(self, component):
55 56 def missingModule(moduleName): 57 m = messages.Error(T_(N_( 58 "To use the iCalendar bouncer you need to have " 59 "the '%s' module installed.\n"), moduleName), 60 mid='error-python-%s' % moduleName) 61 documentation.messageAddPythonInstall(m, moduleName) 62 component.addMessage(m)
63 64 if not eventcalendar.HAS_ICALENDAR: 65 missingModule('icalendar') 66 if not eventcalendar.HAS_DATEUTIL: 67 missingModule('dateutil')
68
69 - def setup(self, component):
70 self._icsfile = self.props['file'] 71 72 try: 73 handle = open(self._icsfile, 'r') 74 except IOError, e: 75 m = messages.Error(T_(N_( 76 "Failed to open iCalendar file '%s'. " 77 "Check permissions on that file."), self._icsfile), 78 mid='error-icalbouncer-file') 79 component.addMessage(m) 80 raise errors.ComponentSetupHandledError() 81 82 try: 83 self.iCalScheduler = scheduler.ICalScheduler(handle) 84 except (ValueError, IndexError, KeyError), e: 85 m = messages.Error(T_(N_( 86 "Error parsing ical file '%s'."), self._icsfile), 87 debug=log.getExceptionMessage(e), 88 mid="error-icalbouncer-file") 89 component.addMessage(m) 90 raise errors.ComponentSetupHandledError() 91 self.subscriptionToken = \ 92 self.iCalScheduler.subscribe(self._do_nothing, self._eventEnded)
93
94 - def authenticate(self, keycard):
95 self.debug('authenticating keycard') 96 97 # need to check if inside an event time 98 cal = self.iCalScheduler.getCalendar() 99 now = datetime.now(tz.UTC) 100 eventInstances = cal.getActiveEventInstances() 101 if not eventInstances: 102 keycard.state = keycards.REFUSED 103 self.info("failed in authentication, outside hours") 104 return None 105 last_end = now 106 while eventInstances: 107 # decorate-sort-undecorate to get the event ending last 108 instance = max([(ev.end, ev) for ev in eventInstances])[1] 109 duration = instance.end - now 110 111 if duration > self.maxKeyCardDuration: 112 duration = self.maxKeyCardDuration 113 break 114 if last_end == instance.end: 115 break 116 eventInstances = cal.getActiveEventInstances(instance.end) 117 last_end = instance.end 118 119 durationSecs = duration.days * 86400 + duration.seconds 120 keycard.duration = durationSecs 121 keycard.state = keycards.AUTHENTICATED 122 self.info("authenticated login, duration %d seconds", 123 durationSecs) 124 return keycard
125
126 - def stop(self, component):
127 # we might not have an iCalScheduler, if something went wrong 128 # during do_setup or do_check 129 if self.iCalScheduler: 130 self.iCalScheduler.cleanup() 131 if self.subscriptionToken: 132 self.iCalScheduler.unsubscribe(self.subscriptionToken) 133 self.subscriptionToken = None
134
135 - def _eventEnded(self, event):
136 self.debug("_eventEnded") 137 if not event.start < datetime.now(tz.UTC) < event.end: 138 return 139 cal = self.iCalScheduler.getCalendar() 140 eventInstances = cal.getActiveEventInstances() 141 if not eventInstances: 142 self.debug("We're now outside hours, revoking all keycards") 143 self._expire_all_keycards()
144
145 - def _expire_all_keycards(self):
146 self.expire(self.keycards.keys())
147
148 - def _do_nothing(self, _):
149 pass
150