2012-03-31 15:45:24 +00:00
# -*- coding: utf-8 -*-
from datetime import datetime , timedelta
from collections import defaultdict
from trac . core import *
from trac . env import IEnvironmentSetupParticipant
from trac . perm import PermissionSystem
from trac . db import Table , Column , Index
from trac . db . util import sql_escape_percent
from trac . util . datefmt import utc , to_timestamp
from trac . util . text import to_unicode
from trac . util . datefmt import get_timezone , utc , format_time , localtz
from trac . util . translation import _
from dateutil . rrule import *
from babel . core import Locale
from ctdotools . utils import validate_id , gen_wiki_page
from tracrendezvous . location . model import ItemLocation
__all__ = [ ' Event ' , ' EventRRule ' , ' EventRDate ' , ' EventModelProvider ' ]
def rrule_to_ical ( rrule ) :
ttypes = ( " YEARLY " , " MONTHLY " , " WEEKLY " , " DAILY " )
s = " RRULE:FREQ= %s ;INTERVAL= %s %s " % ( ttypes [ rrule . _freq ] , rrule . _interval )
if rrule . _until :
s + = " ;UNTIL= %s " % rrule . _until . strftime ( " % Y % m %d T % H % M % SZ " )
elif rrule . _count :
s + = " ;COUNT= %s " % rrule . _count
return s
def unfold ( d ) :
return map ( int , d . split ( ) )
def unfold_weekdays ( d ) :
return map ( lambda s : map ( int , s . split ( " , " ) ) , d . split ( ) )
class EventRDate ( object ) :
def __init__ ( self , env , erd_id = 0 , e_id = 0 , erd_exclude = False ,
erd_datetime = None ) :
self . env = env
self . erd_id = erd_id
self . e_id = e_id
self . erd_exclude = erd_exclude
self . erd_datetime = erd_datetime
@staticmethod
def fetch_one ( env , erd_id ) :
db = env . get_db_cnx ( )
cursor = db . cursor ( )
cursor . execute ( " SELECT * "
" FROM event_rdates "
" WHERE erd_id= %s " , ( erd_id , ) )
row = cursor . fetchone ( )
if not row :
return None
return EventRDate ( env , row [ 0 ] , row [ 1 ] , bool ( row [ 2 ] ) ,
2012-04-25 05:30:22 +00:00
datetime . utcfromtimestamp ( row [ 3 ] ) )
2012-03-31 15:45:24 +00:00
@staticmethod
def fetch_by_event ( env , e_id ) :
db = env . get_db_cnx ( )
cursor = db . cursor ( )
cursor . execute ( " SELECT * "
" FROM event_rdates "
" WHERE e_id= %s " , ( e_id , ) )
rows = cursor . fetchall ( )
res = list ( )
for row in rows :
res . append ( EventRDate ( env , row [ 0 ] , row [ 1 ] , bool ( row [ 2 ] ) ,
2012-04-25 05:30:22 +00:00
datetime . utcfromtimestamp ( row [ 3 ] ) ) )
2012-03-31 15:45:24 +00:00
return res
def commit ( self ) :
db = self . env . get_db_cnx ( )
cursor = db . cursor ( )
cursor . execute ( " INSERT INTO event_rdates "
" (e_id, erd_exclude, erd_datetime) VALUES ( %s , %s , %s ); " ,
( int ( self . e_id ) , int ( self . erd_exclude ) ,
to_timestamp ( self . erd_datetime ) ) )
db . commit ( )
self . erd_id = db . get_last_id ( cursor , ' event_rdates ' )
def update ( self ) :
db = self . env . get_db_cnx ( )
cursor = db . cursor ( )
cursor . execute ( " UPDATE event_rdates SET "
" erd_datetime= %s "
" WHERE erd_id= %s ; " ,
( to_timestamp ( self . erd_datetime ) , int ( self . erd_id ) ) )
db . commit ( )
@staticmethod
def delete ( env , erd_id ) :
db = env . get_db_cnx ( )
cursor = db . cursor ( )
try :
cursor . execute ( " DELETE FROM event_rdates " \
" WHERE erd_id= %s " , ( erd_id , ) )
db . commit ( )
except Exception :
db . rollback ( )
pass
class EventWikiPage ( object ) :
def __init__ ( self , env , ewp_id = 0 , e_id = 0 , time_begin = None , wikipage = None ) :
self . env = env
self . ewp_id = ewp_id
self . e_id = e_id
self . time_begin = time_begin
self . wikipage = wikipage
@staticmethod
def fetch_by_event_occurrence ( env , e_id , time_begin = None ) :
db = env . get_db_cnx ( )
cursor = db . cursor ( )
if not time_begin :
cursor . execute ( " SELECT * "
" FROM event_wikipages "
" WHERE e_id= %s " , ( e_id , ) )
else :
cursor . execute ( " SELECT * "
" FROM event_wikipages "
" WHERE e_id= %s and time_begin= %s " , ( e_id , time_begin ) )
rows = cursor . fetchall ( )
res = list ( )
for row in rows :
res . append ( EventWikiPage ( env , * row ) )
return res
def commit ( self ) :
db = self . env . get_db_cnx ( )
cursor = db . cursor ( )
cursor . execute ( " INSERT INTO event_wikipages " \
" (e_id, time_begin, wikipage) VALUES ( %s , %s , %s ); " ,
( int ( self . e_id ) , to_timestamp ( self . time_begin ) , self . wikipage ) )
db . commit ( )
self . ewp_id = db . get_last_id ( cursor , ' event_wikipages ' )
def update ( self , env ) :
db = self . env . get_db_cnx ( )
cursor = db . cursor ( )
cursor . execute ( " UPDATE event_wikipages " \
" (e_id,timestamp,wikipage) VALUES ( %s , %s , %s ) where ewp_id= %s ; " ,
( int ( self . e_id ) , to_timestamp ( self . time_begin ) , self . wikipage , int ( self . ewp_id ) ) )
db . commit ( )
@staticmethod
def delete ( env , erd_id ) :
db = env . get_db_cnx ( )
cursor = db . cursor ( )
try :
cursor . execute ( " DELETE FROM event_wikipages " \
" WHERE ewp_id= %s " , ( ewp_id , ) )
db . commit ( )
except Exception :
db . rollback ( )
pass
class EventRRule ( object ) :
freq_enum = ( YEARLY , MONTHLY , WEEKLY , DAILY )
day_enum = ( MO , TU , WE , TH , FR , SA , SU )
# TODO: porting to babel
day_abr_names = ( _ ( " MO " ) , _ ( " TU " ) , _ ( " WE " ) , _ ( " TH " ) , _ ( " FR " ) , _ ( " SA " ) , _ ( " SU " ) )
day_names = ( _ ( " Monday " ) , _ ( " Tuesday " ) , _ ( " Wednesday " ) , _ ( " Thursday " ) , _ ( " Friday " ) , _ ( " Saturday " ) , _ ( " Sunday " ) )
monthday_names = [ " %d . " % i for i in xrange ( 1 , 32 ) ] + [ ' last ' , ] + [ " %d -last " % i for i in xrange ( 1 , 32 ) ]
month_names = ( _ ( " January " ) , _ ( " February " ) , _ ( " March " ) , _ ( " April " ) , _ ( " May " ) , _ ( " June " ) , _ ( " July " ) , _ ( " August " ) , _ ( " September " ) , _ ( " October " ) , _ ( " November " ) , _ ( " December " ) )
monthday_enum = range ( 1 , 32 ) + range ( - 1 , - 33 , - 1 )
weekday_names = ( _ ( " 1st " ) , _ ( " 2nd " ) , _ ( " 3rd " ) , _ ( " 4th " ) , _ ( " 5th " ) , _ ( " last " ) , _ ( " 2-last " ) , _ ( " 3-last " ) , _ ( " 4-last " ) , _ ( " 5-last " ) )
selectkeys = [ 1 , 2 , 3 , 4 , 5 , - 1 , - 2 , - 3 , - 4 , - 5 , - 6 ]
def __init__ ( self , env , err_id = 0 , e_id = None , exclude = None , freq = None , interval = None ,
count = None , until = None , bysetpos = None ,
bymonth = None , bymonthday = None , byyearday = None ,
byweeknumber = None , byweekday = set ( ) , byweekdayocc = None ) :
self . env = env
self . err_id = err_id
self . e_id = e_id
self . exclude = exclude
self . freq = freq
self . interval = interval
self . count = count
self . until = until
self . bysetpos = bysetpos
self . bymonth = bymonth
self . bymonthday = bymonthday
self . byyearday = byyearday
self . byweeknumber = byweeknumber
self . byweekday = byweekday
self . byweekdayocc = byweekdayocc
@staticmethod
def _fetch_data ( env , e_id ) :
db = env . get_db_cnx ( )
cursor = db . cursor ( )
cursor . execute ( """ SELECT *
FROM event_rrules
WHERE e_id = % s """ , (e_id,))
return cursor . fetchall ( )
@staticmethod
def fetch_by_event ( env , e_id ) :
''' Returns a list of EventRRule that can be used to display and edit the raw data '''
rows = EventRRule . _fetch_data ( env , e_id )
if not rows :
return list ( )
res = list ( )
for row in rows :
err_id , e_id , exclude , freq , interval , count , until , bysetpos , bymonth , bymonthday , byyearday , byweeknumber , byweekday , byweekdayocc = row
if byweekday :
try :
byweekday = set ( map ( int , byweekday . split ( " " ) ) )
except AttributeError :
byweekday = set ( ( byweekday , ) )
else :
byweekday = set ( )
res . append ( EventRRule ( env ,
err_id ,
e_id ,
exclude ,
freq ,
interval ,
count ,
2012-04-25 05:30:22 +00:00
until and datetime . utcfromtimestamp ( until ) or None ,
2012-03-31 15:45:24 +00:00
bysetpos ,
bymonth ,
bymonthday ,
byyearday ,
byweeknumber ,
byweekday ,
byweekdayocc ) )
return res
@staticmethod
def fetch_by_event_rrules ( env , e_id , time_begin = None ) :
''' returns a rruleset that can be used to actually display dates '''
rows = EventRRule . _fetch_data ( env , e_id )
if not rows :
return rruleset ( )
res = rruleset ( )
for row in rows :
res . rrule ( EventRRule . to_rrule ( row , time_begin ) )
return res
@staticmethod
def fetch_by_event_full ( env , e_id , time_begin = None ) :
rows = EventRRule . _fetch_data ( env , e_id )
if not rows :
return list ( ) , rruleset ( )
lst = list ( )
rs = rruleset ( )
for row in rows :
rs . rrule ( EventRRule . to_rrule ( row , time_begin ) )
err_id , e_id , exclude , freq , interval , count , until , bysetpos , bymonth , bymonthday , byyearday , byweeknumber , byweekday , byweekdayocc = row
if byweekday :
try :
byweekday = set ( map ( int , byweekday . split ( " " ) ) )
except AttributeError :
byweekday = set ( ( byweekday , ) )
else :
byweekday = set ( )
2012-04-25 05:30:22 +00:00
lst . append ( EventRRule ( env , err_id , e_id , exclude , freq , interval , count , until and datetime . utcfromtimestamp ( until ) or None , bysetpos , bymonth , bymonthday , byyearday , byweeknumber , byweekday , byweekdayocc ) )
2012-03-31 15:45:24 +00:00
return lst , rs
@staticmethod
def fetch_by_event_ical ( env , e_id , time_begin = None ) :
''' returns a list of ical formatted strings '''
rows = EventRRule . _fetch_data ( env , e_id )
lst = list ( )
for row in rows :
lst . append ( EventRRule . to_ical ( row ) )
return lst
def commit ( self , conn = None ) :
db = conn and conn or self . env . get_db_cnx ( )
cursor = db . cursor ( )
try :
cursor . execute ( " INSERT INTO event_rrules (e_id, exclude, freq, interval, count, until, bysetpos, bymonth, bymonthday, byyearday, byweeknumber, byweekday, byweekdayocc) VALUES ( %s , %s , %s , %s , %s , %s , %s , %s , %s , %s , %s , %s , %s ); " ,
( self . e_id ,
self . exclude ,
self . freq ,
self . interval ,
self . count ,
to_timestamp ( self . until ) ,
self . bysetpos ,
self . bymonth ,
self . bymonthday ,
self . byyearday ,
self . byweeknumber ,
self . byweekday and " " . join ( map ( str , self . byweekday ) ) or None ,
self . byweekdayocc ) )
db . commit ( )
self . err_id = db . get_last_id ( cursor , ' event_rrules ' )
except Exception , e :
db . rollback ( )
raise
@staticmethod
def delete ( env , e_id ) :
db = env . get_db_cnx ( )
cursor = db . cursor ( )
try :
cursor . execute ( " DELETE FROM event_rrules where e_id= %s " , ( e_id , ) )
db . commit ( )
except Exception , e :
db . rollback ( )
raise
def update ( self , conn = None ) :
db = conn and conn or self . env . get_db_cnx ( )
cursor = db . cursor ( )
weekdays = self . byweekday and " " . join ( map ( str , self . byweekday ) ) or None
cursor . execute ( " UPDATE event_rrules " \
" SET exclude= %s , " \
" freq= %s , " \
" interval= %s , " \
" count= %s , " \
" until= %s , " \
" bysetpos= %s , " \
" bymonth= %s , " \
" bymonthday= %s , " \
" byyearday= %s , " \
" byweeknumber= %s , " \
" byweekday= %s , " \
" byweekdayocc= %s " \
" WHERE e_id= %s " , ( self . exclude ,
self . freq ,
self . interval ,
self . count ,
self . until and to_timestamp ( self . until ) or None ,
self . bysetpos ,
self . bymonth ,
self . bymonthday ,
self . byyearday ,
self . byweeknumber ,
weekdays ,
self . byweekdayocc ,
self . e_id ) )
if not conn :
db . commit ( )
@staticmethod
def to_rrule ( row , time_begin ) :
err_id , e_id , exclude , freq , interval , count , until , bysetpos , bymonth , bymonthday , byyearday , byweeknumber , byweekday , byweekdayocc = row
args = { " dtstart " : time_begin , " interval " : interval }
if count != None :
args [ " count " ] = count
if until :
2012-04-25 05:30:22 +00:00
args [ " until " ] = datetime . utcfromtimestamp ( until )
2012-03-31 15:45:24 +00:00
if bysetpos != None :
args [ " bysetpos " ] = bysetpos
if bymonth != None :
args [ " bymonth " ] = bymonth
if bymonthday != None :
args [ " bymonthday " ] = bymonthday
if byyearday != None :
args [ " byyearday " ] = byyearday
if byweeknumber != None :
args [ " byweekno " ] = byweeknumber
if byweekday != None :
if byweekdayocc != None :
try :
byweekdayocc = byweekdayocc . split ( )
except Exception :
byweekdayocc = [ byweekdayocc , ]
else :
byweekdayocc = [ ]
if byweekday != None :
try :
byweekday = byweekday . split ( )
except Exception :
byweekday = [ byweekday , ]
else :
byweekday = [ ]
args [ " byweekday " ] = map (
lambda x : EventRRule . day_enum [ x [ 0 ] ] ( x [ 1 ] != None and
EventRRule . selectkeys [ x [ 1 ] ] or None ) ,
map ( None , * [ map ( int , byweekday ) , map ( int , byweekdayocc ) ] ) )
return rrule ( freq , * * args )
@staticmethod
def to_ical ( row ) :
ttypes = ( " YEARLY " , " MONTHLY " , " WEEKLY " , " DAILY " )
err_id , e_id , exclude , freq , interval , count , until , bysetpos , bymonth , bymonthday , byyearday , byweeknumber , byweekday , byweekdayocc = row
s = [ " RRULE:FREQ= %s ;INTERVAL= %s " % ( ttypes [ freq ] , interval ) , ]
if until :
2012-04-25 05:30:22 +00:00
s . append ( " UNTIL= %s " % datetime . utcfromtimestamp ( until ) . strftime ( " % Y % m %d T % H % M % SZ " ) )
2012-03-31 15:45:24 +00:00
if count != None :
s . append ( " COUNT= %s " % count )
if bysetpos != None :
s . append ( " BYSETPOS= %s " % bysetpos )
if bymonth != None :
s . append ( " BYMONTH= %s " % bymonth )
if bymonthday != None :
s . append ( " MONTHDAY= %s " % bymonthday )
if byyearday != None :
s . append ( " COUNT= %s " % byyearday )
if byweeknumber != None :
s . append ( " COUNT= %s " % byweeknumber )
if byweekday != None :
if byweekdayocc != None :
try :
byweekdayocc = byweekdayocc . split ( )
except Exception :
byweekdayocc = [ str ( byweekdayocc ) , ]
else :
byweekdayocc = [ ]
if byweekday != None :
try :
byweekday = byweekday . split ( )
except Exception :
byweekday = [ str ( byweekday ) , ]
else :
byweekday = [ ]
#data = list()
#count = 0
#print "byweekday", byweekday
#print "byweekdayocc", byweekdayocc
#wi = iter(byweekday)
#oi = iter(byweekdayocc)
#while 1:
#d = wi.next()
#print "d", d
#try:
#d = wi.next()
#except StopIteration:
#break
#try:
#o = oi.next()
#except StopIteration:
#o = None
#print "o", o
#data.append((d, o))
data = map ( None , map ( int , byweekday ) , map ( int , byweekdayocc ) )
s . append ( " BYDAY= %s " % " , " . join (
map ( lambda x : " %s %s " % ( x [ 1 ] != None and EventRRule . selectkeys [ x [ 1 ] ] or ' ' , EventRRule . day_enum [ x [ 0 ] ] ) ,
data ) ) )
return " ; " . join ( s )
def explain ( self ) :
start = ( _ ( " %d year(s) " ) , _ ( " monthly " ) , _ ( " weekly " ) , _ ( " daily " ) )
freq = ( _ ( " year(s) " ) , _ ( " month(s) " ) , _ ( " week(s) " ) , _ ( " day(s) " ) )
expl = [ ]
expl . append ( " Repeat every %d %s " % ( self . interval , freq [ self . freq ] ) )
if self . byweekday :
if self . byweekdayocc != None :
try :
byweekdayocc = map ( int , self . byweekdayocc . split ( ) )
except Exception :
byweekdayocc = [ int ( self . byweekdayocc ) , ]
else :
byweekdayocc = [ ]
byweekday = self . byweekday
if not byweekday :
byweekday = [ ]
tmp = map ( None , byweekday , byweekdayocc )
tpl = _ ( " on %s " )
res = list ( )
for x0 , x1 in tmp :
if x1 :
res . append ( " %s %s " % ( unicode ( self . weekday_names [ x1 ] ) , unicode ( self . day_names [ x0 ] ) ) )
else :
res . append ( unicode ( self . day_names [ x0 ] ) )
#tmp = ", ".join(res)
tmp = tpl % " , " . join (
map ( lambda x : x [ 1 ] and _ ( " %s %s " ) %
( unicode ( self . weekday_names [ x [ 1 ] ] ) , unicode ( self . day_names [ x [ 0 ] ] ) ) or
unicode ( self . day_names [ x [ 0 ] ] ) , tmp ) )
expl . append ( tmp )
elif self . bymonthday :
expl . append ( _ ( " on day %s " ) % self . bymonthday )
elif self . bymonth :
expl . append ( _ ( " in %s " ) % self . month_names [ self . bymonth ] )
elif self . byyearday :
expl . append ( _ ( " on day %s " ) % self . byyearday )
if self . count and self . count > 0 :
expl . append ( _ ( " for %d times " % self . count ) )
if self . until :
expl . append ( _ ( " until %s " % self . until . strftime ( ' % Y- % m- %d ' ) ) )
#else:
#raise NotImplementedError("could not provide a sane explanation of event:\n%s" % self.__str__())
return " " . join ( expl )
def __str__ ( self ) :
return " \n " . join ( ( " self.e_id %s " % self . e_id ,
" self.exclude %s " % self . exclude ,
" self.freq %s " % self . freq ,
" self.interval %s " % self . interval ,
" self.count %s " % self . count ,
" self.until %s " % to_timestamp ( self . until ) ,
" self.bysetpos %s " % self . bysetpos ,
" self.bymonth %s " % self . bymonth ,
" self.bymonthday %s " % self . bymonthday ,
" self.byyearday %s " % self . byyearday ,
" self.byweeknumber %s " % self . byweeknumber ,
" self.byweekday %s " % self . byweekday ,
" self.byweekdayocc %s " % self . byweekdayocc ) )
class Event ( object ) :
def __init__ ( self , env , e_id , name , author , time_created , time_modified , time_begin , time_end , location_id , initial_e_id = None , tags = None , attendees = None , is_periodic = False , wikipage = None ) :
""" maps an relation of the ' events ' table to a python object
@type e_id : int
@param e_id : primary key
@type name : string
@param name : name of that event
@type author : string
@param author : name of events ' creator
@type time_begin : datetime
@param time_begin : begin of the event
@type time_end : datetime
@param time_end : end of the event
@type time_created : datetime
@param time_created : creation timestamp of the event
@type time_modified : datetime
@param time_modified : timestamp of last modification
@type location_id : int
@param location_id : primary key of the location the event is taking place
@type initial_e_id : int
@param initial_e_id : gets the same value as e_id , but only if it ' s
not the first occurence of an recurring event
@type tags : unicode
@param tags : space seperated list of tags
@type attendees : unicode
@param attendees : space seperated list of tags
@type is_periodic : bool
@param is_periodic : shows if that event is recurring
@type wikipage : unicode
@param wikipage : the link as plaintext without ' wiki ' prefix , e . g : " events/wikipage-of-that-event " , or " foo "
"""
self . env = env
self . e_id = e_id
self . name = unicode ( name )
self . author = unicode ( author )
self . time_created = time_created
self . time_modified = time_modified
self . time_begin = time_begin
self . time_end = time_end
self . location_id = location_id
self . initial_e_id = initial_e_id # reference to another object of the same type. if this is not None, its a follow-up event with a wiki page created
self . tags = tags # space separated list of strings
self . attendees = attendees # space separated list of strings
self . is_periodic = is_periodic
self . location = ItemLocation . fetch_one ( env , location_id )
#self.location = 0
self . wikipage = wikipage
def periodic ( self ) :
return self . is_periodic or self . initial_e_id
@staticmethod
def fetch_one ( env , event_id , show_next = False , show_all = False , days = 365 ) :
""" returns Event with primary key event_id
@type event_id : int
@param event_id : primary key of Event
@type show_next : bool
@param show_next : if True and if Event . is periodic == True then
@type show_all : bool
@param show_all : if True and if Event . is periodic == True then
event gets a new member list ' Event.followups ' of followup events between now and now + 1 year .
"""
db = env . get_db_cnx ( )
cursor = db . cursor ( )
cursor . execute ( " SELECT * " \
" FROM events " \
" WHERE e_id= %s " , ( event_id , ) )
row = cursor . fetchone ( )
if not row :
return None
e_id , name , author , time_created , time_modified , time_begin , time_end , location_id , initial_e_id , tags , attendees , is_periodic , wikipage = row
2012-04-25 05:30:22 +00:00
event = Event ( env , e_id , name , author ,
utc . localize ( datetime . utcfromtimestamp ( time_created ) ) ,
utc . localize ( datetime . utcfromtimestamp ( time_modified ) ) ,
utc . localize ( datetime . utcfromtimestamp ( time_begin ) ) ,
utc . localize ( datetime . utcfromtimestamp ( time_end ) ) ,
location_id , initial_e_id , tags , attendees , bool ( is_periodic ) , wikipage )
2012-03-31 15:45:24 +00:00
if show_next and is_periodic :
rrules = EventRRule . fetch_by_event_rrules ( env , e_id , event . time_begin )
if rrules :
dt = rrules . after ( datetime . now ( utc ) , True )
if not dt :
return event
delta = event . time_end - event . time_begin
s = Event ( env ,
e_id ,
name ,
author ,
event . time_created ,
event . time_modified ,
dt ,
dt + delta ,
location_id ,
e_id ,
tags ,
attendees ,
False ,
wikipage )
return s
if show_all and is_periodic :
event . followups = [ ]
event . rrules_explained = None
ls , rrules = EventRRule . fetch_by_event_full ( env , e_id , event . time_begin )
if rrules :
text = ls [ 0 ] . explain ( )
event . rrules_explained = text
n = datetime . now ( utc )
e = n + timedelta ( days )
followups = rrules . between ( n , e , True )
delta = event . time_end - event . time_begin
for i in followups :
dt = datetime ( i . year , i . month , i . day , event . time_begin . hour , event . time_begin . minute , tzinfo = utc )
s = Event ( env ,
e_id ,
name ,
author ,
2012-04-25 05:30:22 +00:00
datetime . utcfromtimestamp ( time_created ) ,
datetime . utcfromtimestamp ( time_modified ) ,
2012-03-31 15:45:24 +00:00
dt ,
dt + delta ,
location_id ,
e_id ,
tags ,
attendees ,
False ,
wikipage )
s . rrules_explained = text
event . followups . append ( s )
return event
@staticmethod
def fetch_all ( env ) :
db = env . get_db_cnx ( )
cursor = db . cursor ( )
cursor . execute ( " SELECT * from events; " )
rows = cursor . fetchall ( )
if not rows :
return [ ]
res = [ ]
for row in rows :
e_id , name , author , time_created , time_modified , time_begin , time_end , location_id , initial_e_id , tags , attendees , is_periodic , wikipage = row
2012-04-25 05:30:22 +00:00
time_begin = utc . localize ( datetime . utcfromtimestamp ( time_begin ) )
2012-03-31 15:45:24 +00:00
event = Event ( env , e_id , name , author ,
2012-04-25 05:30:22 +00:00
utc . localize ( datetime . utcfromtimestamp ( time_created ) ) ,
utc . localize ( datetime . utcfromtimestamp ( time_modified ) ) ,
time_begin ,
utc . localize ( datetime . utcfromtimestamp ( time_end ) ) , location_id , initial_e_id ,
2012-03-31 15:45:24 +00:00
tags , attendees , is_periodic , wikipage )
if is_periodic :
rrules = EventRRule . fetch_by_event_rrules ( env , e_id , event . time_begin )
if rrules :
2012-04-25 05:30:22 +00:00
dt = rrules . after ( datetime . utcnow ( ) , inc = True )
2012-03-31 15:45:24 +00:00
if not dt :
res . append ( event )
continue
delta = event . time_end - event . time_begin
s = Event ( env ,
e_id ,
name ,
author ,
event . time_created ,
event . time_modified ,
dt ,
dt + delta ,
location_id ,
e_id ,
tags ,
attendees ,
False ,
wikipage )
res . append ( s )
else :
res . append ( event )
return res
@staticmethod
def fetch_all_with_rrule ( env ) :
db = env . get_db_cnx ( )
cursor = db . cursor ( )
cursor . execute ( " SELECT * from events; " )
rows = cursor . fetchall ( )
if not rows :
return [ ]
res = [ ]
for row in rows :
e_id , name , author , time_created , time_modified , time_begin , time_end , location_id , initial_e_id , tags , attendees , is_periodic , wikipage = row
2012-04-25 05:30:22 +00:00
time_begin = utc . localize ( datetime . utcfromtimestamp ( time_begin ) )
2012-03-31 15:45:24 +00:00
event = Event ( env , e_id , name , author ,
2012-04-25 05:30:22 +00:00
utc . localize ( datetime . utcfromtimestamp ( time_created ) ) ,
utc . localize ( datetime . utcfromtimestamp ( time_modified ) ) ,
time_begin ,
utc . localize ( datetime . utcfromtimestamp ( time_end ) ) , location_id , initial_e_id ,
2012-03-31 15:45:24 +00:00
tags , attendees , is_periodic , wikipage )
res . append ( event )
if is_periodic :
try :
event . rrule = EventRRule . fetch_by_event ( env , e_id ) [ 0 ]
except Exception :
pass
return res
@staticmethod
def fetch_as_ical ( env ) :
db = env . get_db_cnx ( )
cursor = db . cursor ( )
cursor . execute ( " SELECT * from events; " )
rows = cursor . fetchall ( )
if not rows :
return [ ]
res = [ ]
for row in rows :
e_id , name , author , time_created , time_modified , time_begin , time_end , location_id , initial_e_id , tags , attendees , is_periodic , wikipage = row
2012-04-25 05:30:22 +00:00
time_begin = utc . localize ( datetime . utcfromtimestamp ( time_begin ) )
2012-03-31 15:45:24 +00:00
event = Event ( env , e_id , name , author ,
2012-04-25 05:30:22 +00:00
utc . localize ( datetime . utcfromtimestamp ( time_created ) ) ,
utc . localize ( datetime . utcfromtimestamp ( time_modified ) ) ,
time_begin ,
utc . localize ( datetime . utcfromtimestamp ( time_end ) ) , location_id , initial_e_id ,
2012-03-31 15:45:24 +00:00
tags , attendees , is_periodic , wikipage )
event . rrules = EventRRule . fetch_by_event_ical ( env , int ( e_id ) )
event . alarms = [
u """
BEGIN : VALARM
DESCRIPTION : Gleich beginnt das Event ' %s '
ACTION : DISPLAY
TRIGGER ; VALUE = DURATION : - PT10M
END : VALARM
BEGIN : VALARM
DESCRIPTION : In 2 Tagen beginnt das Event ' %s '
ACTION : DISPLAY
TRIGGER ; VALUE = DURATION : - P2D
END : VALARM """ % (event.name, event.name)]
res . append ( event )
return res
@staticmethod
def get_recurrency_data ( env , e_id ) :
return EventRRule . fetch_by_event_data ( env , e_id ) . extend ( EventRDate . fetch_by_event ( env , e_id ) )
@staticmethod
def _data_fetch_by_period ( env , start_dt , end_dt , is_periodic = False , locations = [ ] ) :
db = env . get_db_cnx ( )
cursor = db . cursor ( )
if is_periodic :
cursor . execute ( " SELECT * from events where is_periodic=1; " )
return cursor . fetchall ( )
else :
query = " SELECT * from events where is_periodic= ' 0 ' and (time_begin between %s and %s or time_end between %s and %s ) "
if locations :
query + = " and location_id in ( %s ) " % " , " . join ( map ( sql_escape_percent , locations ) )
query + = " ; "
s = to_timestamp ( start_dt )
e = to_timestamp ( end_dt )
cursor . execute ( query , ( s , e , s , e ) )
return cursor . fetchall ( )
@staticmethod
def fetch_by_period_dict ( env , start_dt , end_dt , locations = [ ] ) :
""" returns a dictionary with date as keys and lists of events as values
Some events might be periodic and the actual recurrency ruleset created and processed ,
so this method is somewhat cpu intensive . To keep apart singular from recurring events check
Event . is_periodic
"""
rows = Event . _data_fetch_by_period ( env , start_dt , end_dt , locations = locations )
res = defaultdict ( list )
if rows :
for row in rows :
e_id , name , author , time_created , time_modified , time_begin , time_end , location_id , initial_e_id , tags , attendees , is_periodic , wikipage = row
2012-04-25 05:30:22 +00:00
time_begin = utc . localize ( datetime . utcfromtimestamp ( time_begin ) )
2012-03-31 15:45:24 +00:00
res [ time_begin . date ( ) ] . append (
2012-04-25 05:30:22 +00:00
Event ( env , e_id , name , author ,
utc . localize ( datetime . utcfromtimestamp ( time_created ) ) ,
utc . localize ( datetime . utcfromtimestamp ( time_modified ) ) ,
time_begin ,
utc . localize ( datetime . utcfromtimestamp ( time_end ) ) ,
location_id , initial_e_id ,
2012-03-31 15:45:24 +00:00
tags , attendees , False , wikipage ) )
rows = Event . _data_fetch_by_period ( env , start_dt , end_dt , is_periodic = True , locations = locations )
if not rows :
return res
for row in rows :
e_id , name , author , time_created , time_modified , time_begin , time_end , location_id , initial_e_id , tags , attendees , is_periodic , wikipage = row
2012-04-25 05:54:48 +00:00
time_begin = utc . localize ( datetime . utcfromtimestamp ( time_begin ) )
time_end = utc . localize ( datetime . utcfromtimestamp ( time_end ) )
2012-03-31 15:45:24 +00:00
delta = time_end - time_begin
rrules = EventRRule . fetch_by_event_rrules ( env , e_id , time_begin )
if not rrules :
raise ValueError ( " missing rruleset " )
try :
myrrule = EventRRule . fetch_by_event ( env , e_id ) [ 0 ]
except Exception , e :
myrrule = None
try :
excluding = EventRDate . fetch_by_event ( env , e_id )
except Exception , e :
excluding = [ ]
for i in excluding :
rrules . exdate ( i . erd_datetime . replace ( hour = time_begin . hour , minute = time_begin . minute ) )
followups = rrules . between ( start_dt , end_dt , True )
for i in followups :
dt = datetime ( i . year , i . month , i . day , time_begin . hour , time_begin . minute , tzinfo = utc )
s = Event ( env ,
e_id ,
name ,
author ,
2012-04-25 05:30:22 +00:00
datetime . utcfromtimestamp ( time_created ) ,
datetime . utcfromtimestamp ( time_modified ) ,
2012-03-31 15:45:24 +00:00
dt ,
dt + delta ,
location_id ,
e_id ,
tags ,
attendees ,
False ,
wikipage )
if rrule :
s . rrule = myrrule
res [ i . date ( ) ] . append ( s )
return res
@staticmethod
def fetch_by_period_list ( env , start_dt , end_dt , locations = [ ] ) :
""" If you need a list of events between datetime a and datetime b, use this method, which is less expensive than Event.fetch_by_period_dict.
"""
rows = Event . _data_fetch_by_period ( env , start_dt , end_dt , locations = locations )
res = list ( )
if rows :
for row in rows :
e_id , name , author , time_created , time_modified , time_begin , time_end , location_id , initial_e_id , tags , attendees , is_periodic , wikipage = row
2012-04-25 05:30:22 +00:00
time_begin = utc . localize ( datetime . utcfromtimestamp ( time_begin ) )
2012-03-31 15:45:24 +00:00
res . append ( Event ( env , e_id , name , author ,
2012-04-25 05:30:22 +00:00
utc . localize ( datetime . utcfromtimestamp ( time_created ) ) ,
utc . localize ( datetime . utcfromtimestamp ( time_modified ) ) ,
time_begin ,
utc . localize ( datetime . utcfromtimestamp ( time_end ) ) ,
2012-03-31 15:45:24 +00:00
location_id , initial_e_id , tags , attendees , False , wikipage ) )
rows = Event . _data_fetch_by_period ( env , start_dt , end_dt , True , locations = locations )
if not rows :
return res
for row in rows :
e_id , name , author , time_created , time_modified , time_begin , time_end , location_id , initial_e_id , tags , attendees , is_periodic , wikipage = row
2012-04-25 05:30:22 +00:00
time_begin = utc . localize ( datetime . utcfromtimestamp ( time_begin ) )
time_end = utc . localize ( datetime . utcfromtimestamp ( time_end ) )
time_created = utc . localize ( datetime . utcfromtimestamp ( time_created ) )
time_modified = utc . localize ( datetime . utcfromtimestamp ( time_modified ) )
2012-03-31 15:45:24 +00:00
delta = time_end - time_begin
rrules = EventRRule . fetch_by_event_rrules ( env , e_id , time_begin )
followups = rrules . between ( start_dt , end_dt , inc = True )
try :
rrule = EventRRule . fetch_by_event ( env , e_id ) [ 0 ]
except Exception , e :
pass
for i in followups :
2012-04-25 05:30:22 +00:00
dt = utc . localize ( datetime ( i . year , i . month , i . day , time_begin . hour , time_begin . minute ) )
2012-03-31 15:45:24 +00:00
s = Event ( env ,
e_id ,
name ,
author ,
time_created ,
time_modified ,
dt ,
dt + delta ,
location_id ,
e_id ,
tags ,
attendees ,
False ,
wikipage )
if rrule :
s . rrule = rrule
res . append ( s )
return res
def commit ( self , conn = None ) :
db = conn and conn or self . env . get_db_cnx ( )
2012-04-25 05:30:22 +00:00
t = utc . localize ( datetime . utcnow ( ) )
2012-03-31 15:45:24 +00:00
cursor = db . cursor ( )
try :
cursor . execute ( " INSERT INTO events " \
" (name,author,time_created,time_modified,time_begin,time_end,location_id,initial_e_id,tags,attendees,is_periodic, wikipage) " \
" VALUES( %s , %s , %s , %s , %s , %s , %s , %s , %s , %s , %s , %s ); " ,
( self . name ,
self . author ,
to_timestamp ( self . time_created ) ,
to_timestamp ( self . time_modified ) ,
to_timestamp ( self . time_begin ) ,
to_timestamp ( self . time_end ) ,
self . location_id ,
self . initial_e_id ,
self . tags ,
self . attendees ,
int ( self . is_periodic ) ,
self . wikipage ) )
db . commit ( )
self . e_id = db . get_last_id ( cursor , ' events ' )
except Exception , e :
db . rollback ( )
raise
@staticmethod
def delete ( env , e_id ) :
db = env . get_db_cnx ( )
cursor = db . cursor ( )
try :
cursor . execute ( " DELETE FROM events WHERE e_id = %s " , ( e_id , ) )
db . commit ( )
except Exception , e :
db . rollback ( )
raise
def update ( self , conn = None ) :
db = conn and conn or self . env . get_db_cnx ( )
cursor = db . cursor ( )
try :
cursor . execute ( " UPDATE events " \
" SET name = %s , " \
" author= %s , " \
" time_created= %s , " \
" time_modified= %s , " \
" time_begin= %s , " \
" time_end= %s , " \
" initial_e_id= %s , " \
" location_id= %s , " \
" tags= %s , " \
" attendees= %s , " \
" is_periodic= %s , " \
" wikipage= %s " \
" WHERE e_id= %s " , ( self . name , self . author , to_timestamp ( self . time_created ) , to_timestamp ( self . time_modified ) ,
to_timestamp ( self . time_begin ) , to_timestamp ( self . time_end ) ,
self . initial_e_id , self . location_id , self . tags , self . attendees , int ( self . is_periodic ) , self . wikipage , self . e_id ) )
db . commit ( )
except Exception , e :
db . rollback ( )
raise
def __str__ ( self ) :
return " <Event: %d , %s , %s , %s > " % ( self . e_id , self . name , self . time_begin , self . time_end )
class EventModelProvider ( Component ) :
implements ( IEnvironmentSetupParticipant )
SCHEMA = [
Table ( ' events ' , key = ' e_id ' ) [
Column ( ' e_id ' , auto_increment = True ) ,
Column ( ' name ' ) ,
Column ( ' author ' ) ,
Column ( ' time_created ' , type = ' int ' ) ,
Column ( ' time_modified ' , type = ' int ' ) ,
Column ( ' time_begin ' , type = ' int ' ) ,
Column ( ' time_end ' , type = ' int ' ) ,
Column ( ' location_id ' , type = ' int ' ) ,
Column ( ' initial_e_id ' , type = ' int ' ) ,
Column ( ' tags ' ) ,
Column ( ' attendees ' ) ,
Column ( ' is_periodic ' , type = " int " ) ,
Column ( ' wikipage ' ) ,
Index ( [ ' name ' ] ) ] ,
Table ( ' event_wikipages ' , key = ' ewp_id ' ) [
Column ( ' ewp_id ' , auto_increment = True ) ,
Column ( ' e_id ' ) ,
Column ( ' wikipage ' ) ] ,
Table ( ' event_rrules ' , key = ' err_id ' ) [
Column ( ' err_id ' , auto_increment = True ) ,
Column ( ' e_id ' , type = " int " ) ,
Column ( ' exclude ' , type = " int " ) ,
Column ( ' freq ' , type = " int " ) ,
Column ( ' interval ' , type = " int " ) ,
Column ( ' count ' , type = " int " ) ,
Column ( ' until ' , type = " int " ) ,
Column ( ' bysetpos ' , type = " int " ) ,
Column ( ' bymonth ' , type = " int " ) ,
Column ( ' bymonthday ' , type = " int " ) ,
Column ( ' byyearday ' , type = " int " ) ,
Column ( ' byweeknumber ' ) ,
Column ( ' byweekday ' ) ,
Column ( ' byweekdayocc ' ) ] ,
Table ( ' event_rdates ' ) [
Column ( ' erd_id ' , auto_increment = True ) ,
Column ( ' e_id ' , type = " int " ) ,
Column ( ' erd_exclude ' , type = " int " ) ,
Column ( ' erd_datetime ' , type = " int " ) ] ]
#TERMINE_DATA = (
#(u"Offizielles Treffen",
#to_timestamp(datetime.now(utc)),
#to_timestamp(datetime.now(utc)),
#to_timestamp(datetime(2009,5,7,17,0, tzinfo=utc)),
#to_timestamp(datetime(2009,5,7,20,0, tzinfo=utc)),
#1,
#None,
#"foo bar",
#"heinz horst elke peter",
#True),
#(u"Topic Treffen",
#to_timestamp(datetime.now(utc)),
#to_timestamp(datetime.now(utc)),
#to_timestamp(datetime(2009,5,8,17,0, tzinfo=utc)),
#to_timestamp(datetime(2009,5,8,20,0, tzinfo=utc)),
#1,
#None,
#"foo bar",
#"heinz horst elke peter",
#True),
#(u"Zombies Beamer Action",
#to_timestamp(datetime.now(utc)),
#to_timestamp(datetime.now(utc)),
#to_timestamp(datetime(2009,7,2,17,0, tzinfo=utc)),
#to_timestamp(datetime(2009,7,2,23,0, tzinfo=utc)),
#1,
#None,
#"gamez beamer",
#"syn knuddel kalle lucifer schnarchnase",
#False))
TERMINE_PERIOD_DATA = (
( 1 , 0 , 3 , 15 , 30 , None ) ,
( 2 , 0 , 3 , 30 , 15 , None ) )
def environment_created ( self ) :
self . _create_models ( self . env . get_db_cnx ( ) )
def environment_needs_upgrade ( self , db ) :
""" First version - nothing to migrate, but possibly to create.
"""
cursor = db . cursor ( )
try :
cursor . execute ( " select count(*) from events " )
cursor . fetchone ( )
cursor . execute ( " select count(*) from event_rrules " )
cursor . fetchone ( )
cursor . execute ( " select count(*) from event_rdates " )
cursor . fetchone ( )
cursor . execute ( " select count(*) from event_wikipages " )
cursor . fetchone ( )
return False
except :
db . rollback ( )
return True
def upgrade_environment ( self , db ) :
""" nothing to do here for now
"""
self . _create_models ( db )
def _create_models ( self , db ) :
""" Called when a new Trac environment is created. """
db_backend = None
try :
from trac . db import DatabaseManager
db_backend , _ = DatabaseManager ( self . env ) . _get_connector ( )
except ImportError :
db_backend = self . env . get_db_cnx ( )
try :
cursor = db . cursor ( )
for table in self . SCHEMA :
try :
for stmt in db_backend . to_sql ( table ) :
self . env . log . debug ( stmt )
cursor . execute ( stmt )
except Exception , e :
self . env . log . exception ( e )
db . commit ( )
#cursor.executemany("""INSERT INTO 'events'
# (name, time_created, time_modified, time_begin, time_end, location_id, initial_e_id, tags, attendees, is_periodic)
# VALUES(%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)""", self.TERMINE_DATA)
#cursor.executemany("""INSERT INTO 'event_rrules'
# (e_id,exclude,freq,interval,count,until)
# VALUES(%s,%s,%s,%s,%s,%s)""", self.TERMINE_PERIOD_DATA)
#db.commit()
#gen_wiki_page(self.env, "hotshelf", "events/1", u"= Offizielles Treffen = \nDiese Page kann mit Ideen und Inhalten des Events/Treffs gefüllt werden", "localhost")
#gen_wiki_page(self.env, "hotshelf", "events/2", u"= Topic Treffen = \nDiese Page kann mit Ideen und Inhalten des Events/Treffs gefüllt werden", "localhost")
except Exception , e :
db . rollback ( )
raise